【问题标题】:Linq Full Outer Join on Two Objects两个对象的Linq完全外连接
【发布时间】:2015-06-23 18:23:56
【问题描述】:

我有两个名为 CountryMobility 的对象,我认为我需要将它们与完整的外部联接结合起来。如何使用 linq 做到这一点?

public class CountryMobility
{
    public string countryCode { get; set; }
    public int inbound { get; set; }
    public int outbound { get; set; }
} 

我想像这样组合其中两个对象:

inboundStudents:
countryCode | inbound | outbound
         EG |    2    |     0
         CA |    3    |     0
         CH |    5    |     0

outboundStudents:
countryCode | inbound | outbound
         PE |    0    |     1
         CA |    0    |     4
         CH |    0    |     5


                      -
                      -
                      -
                      -
                      V

combinedStudents:
countryCode | inbound | outbound
         PE |    0    |     1
         CA |    3    |     4
         CH |    5    |     5
         EG |    2    |     0

我尝试了以下 linq 语句,但未能找出正确的语法。我目前在附近遇到语法错误 temp.DefaultIfEmpty(new { first.ID, inbound = 0, outbound=0 }) 在两个语句中。

var leftOuterJoin = 
    from first in inboundActivities
    join last in outboundActivities
    on first.countryCode equals last.countryCode
    into temp
    from last in temp.DefaultIfEmpty
    (new { first.countryCode, inbound = 0, outbound=0 })
    select new CountryMobility
    {
        countryCode = first.countryCode,
        inbound = first.inbound,
        outbound = last.outbound,
    };
var rightOuterJoin = 
    from last in outboundActivities
    join first in inboundActivities
    on last.countryCode equals first.countryCode
    into temp
    from first in temp.DefaultIfEmpty
    (new { last.countryCode, inbound = 0, outbound = 0 })
    select new CountryMobility
    {
        countryCode = last.countryCode,
        inbound = first.inbound,
        outbound = last.outbound,
    };

var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin); 

【问题讨论】:

  • LINQ - Full Outer Join 的可能重复项
  • 您尝试过哪些 linq 语句,它们产生了什么?他们有什么不正确的地方需要帮助?
  • @Josh L. 试过了,但我无法让它正常工作。我认为问题在于它正在输出一个匿名对象,而我无法将其作为我的“CountryMobility”对象输出。
  • 我在您的问题中没有看到对 CoutryMobility 对象的任何引用。因此,任何涉及CountryMobility 的事情肯定与任何解决方案都无关。
  • 您需要编写 3 个查询。一个用于左侧,一个用于右侧,最后一个用于连接。检查这个stackoverflow.com/questions/5489987/linq-full-outer-join

标签: c# sql linq


【解决方案1】:

根据您的最新信息。在我看来,您可以做一些更简单的事情。即您随后按国家/地区代码分组的UNION ALL。 可以使用Concat 方法创建UNION ALL

下面的示例适用于我(在内存集合中使用)。查询显示在Run 方法中。

public class CountryMobility
{
    public string countryCode { get; set; }
    public int inbound { get; set; }
    public int outbound { get; set; }
}

public static class JoinedMobilityQuery
{
    static CountryMobility[] inbound = {
        new CountryMobility() { countryCode = "EG", inbound = 2 },
        new CountryMobility() { countryCode = "CA", inbound = 3 },
        new CountryMobility() { countryCode = "CH", inbound = 5 },
    };
    static CountryMobility[] outbound = {
        new CountryMobility() { countryCode = "PE", outbound = 1 },
        new CountryMobility() { countryCode = "CA", outbound = 4 },
        new CountryMobility() { countryCode = "CH", outbound = 6 },
    };

    static IQueryable<CountryMobility> Inbound()
    {
        return inbound.AsQueryable();
    }

    static IQueryable<CountryMobility> Outbound()
    {
        return outbound.AsQueryable();
    }

    public static void Run()
    {
        var transfers = from t in Inbound().Concat(Outbound())
                        group t by t.countryCode into g
                        select new CountryMobility() {
                            countryCode = g.Key,
                            inbound = g.Sum(x => x.inbound),
                            outbound = g.Sum(x => x.outbound),
                        };
        foreach (var transfer in transfers)
            Console.WriteLine("{0}\t{1}\t{2}", transfer.countryCode, transfer.inbound, transfer.outbound);
    }
}

【讨论】:

  • 谢谢!这很有效,我喜欢它有多简单!
【解决方案2】:

你的 DefaultIfEmpty 抛出一个错误,因为你定义了一个匿名对象,但是你在你的 select 语句中创建了 stronly 类型的对象。它们必须是同一类型。

所以像这样定义一个默认对象:

var defaultActivity = new CountryMobility() { countryCode = String.Empty, outbound = 0, inbound = 0 };

之后,在你的 DefaultIfEmpty() 方法中使用它:

from last in temp.DefaultIfEmpty(defaultActivity)
select new CountryMobility
{
   //...
};

最后但同样重要的是,您必须执行 groupby 才能获得所需的结果:

var fullOuterJoin = leftOuterJoin.Union(rightOuterJoin)
                             .GroupBy (oj => oj.countryCode)
                             .Select (oj => oj.FirstOrDefault()); 

输出:

完整的演示代码:

http://share.linqpad.net/u46gar.linq

【讨论】:

    【解决方案3】:

    你可以这样做

     List<CountryMobility> inboundStudents = new List<CountryMobility>{ 
                new CountryMobility { countryCode="EG", inbound=2, outbound = 0},
                new CountryMobility { countryCode="CA", inbound=3, outbound = 0},
                new CountryMobility { countryCode="CH", inbound=5, outbound = 0}};
    
            List<CountryMobility> outboundStudents = new List<CountryMobility>{ 
                new CountryMobility { countryCode="PE", inbound=0, outbound = 1},
                new CountryMobility { countryCode="CA", inbound=0, outbound = 4},
                new CountryMobility { countryCode="CH", inbound=0, outbound = 5}};
    
                    var joinedList = inboundStudents.Concat(outboundStudents).GroupBy(item => new { item.countryCode});
                    var result = joinedList.Select(x => new 
                    {
                        countryCode = x.Key.countryCode,
                        inbound = x.Sum(i => i.inbound),
                        outbound = x.Sum(i => i.outbound)
                    });
    

    【讨论】:

      猜你喜欢
      • 2014-09-14
      • 2017-06-10
      • 2018-05-30
      • 2020-03-30
      • 2014-08-07
      • 2020-06-10
      • 2015-03-31
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多