带有自定义比较器的 Linq 左外连接

Posted

技术标签:

【中文标题】带有自定义比较器的 Linq 左外连接【英文标题】:Linq left outer join with custom comparator 【发布时间】:2013-09-15 18:27:46 【问题描述】:

我正在尝试创建一个left outer join 查询,该查询也有一个custom comparator

我有以下列表:

List<ColumnInformation> list1;
List<ColumnInformation> list2;

这些包含有关 SQL 列的信息(数据类型、名称、表等)。我已经为班级覆盖了Equals,并创建了operator ==operator !=

我知道怎么make a left outer join:

var leftOuterJoin = from l1 in list1
                    join l2 in list2 on l1.objectID equals l2.objectID into temp
                    from l2 in temp.DefaultIfEmpty(new  l1.ID, Name = default(string) )
                    select new
                    
                        l1.ID,
                        ColumnName1 = l1.Name,
                        ColumnName2 = l2.Name,
                    ;

而且我了解如何制作和使用自定义IEqualityComparer

public class ColumnComparer : IEqualityComparer<ColumnInformation>

    public bool Equals(ColumnInformation x, ColumnInformation y)
    
        return x == y; //this uses my defined == operator
    

    public int GetHashCode(ColumnInformation obj)
    
        return 1; //forcing the join to use Equals, just trust me on this
    


ColumnComparer cc = new ColumnComparer();
var joinedList = list1.Join(list2,
    x => x,
    y => y,
    (x, y) => new x, y,
    cc);

我的问题是:如何同时进行左外连接和使用比较器

据我所知,查询语法没有比较器的关键字,扩展方法没有into关键字的任何东西。

我不在乎结果是查询语法还是扩展方法。

【问题讨论】:

您可以覆盖ColumnInformations Equals 和 GetHashCode,如在 ColumnComparer 中实现的那样。 @HamletHakobyan,我已经覆盖了ColumnInformation 中的Equals。现在我的代码没有触及它。这有什么好处(也适用于 GetHashCode)? 我不得不说你可以用扩展方法在LINQ中做所有你想做的事情但是你不能用查询语法在LINQ中做一些事情。事实上,extension methods 中的join into 等价于GroupJoin @KingKing, GroupJoin,不会从名字中猜到这一点。如果你能提供一个例子,我会很高兴。 很抱歉造成混淆。尝试在ColumnInformation 中实现IEquatable<T>。 【参考方案1】:

您这样做的方式是使用GroupJoinSelectMany(以使结果变平):

ColumnComparer cc = new ColumnComparer();
var joinedList = list1
    .GroupJoin(list2,
        x => x,
        y => y,
        (x, g) => new x, g,
        cc)
    .SelectMany(
        z => z.g.DefaultIfEmpty(),
        (z, b) => new   x = z.x, y = b  
    );

【讨论】:

OP 说“我的问题是:如何同时进行左外连接和使用比较器?”。我想知道这个答案如何响应 OP 的实际需求!? @Alireza,这是一个左外连接(使用DefaultIfEmpty()),并使用我的比较器(cc)。这是一个正确的答案。 @gunr2171 哎呀!抱歉,我没有注意到 'cc'。感谢您的澄清。【参考方案2】:

您可以将子查询与 Where 结合使用:

var leftOuterJoin = from l1 in list1
                    select new 
                   
                      jointList = (from l2 in list2 
                                   where l2.objectID == l1.ObjectID // <-- and you can do any other comparing logic in where clause
                                   select l2).DefaultIfEmpty(),                        
                      l1id = l1.ID,
                      ColumnName1 = l1.Name,
                      ColumnName2 = l2.Name
;

【讨论】:

最后,where 子句将是l2 == l1。我在那个运算符方法中有我的比较逻辑。 @gunr2171 您询问了如何让您的自定义比较器参与到一个 Join 查询中,对吧?您可以调用任何返回布尔值的方法来提供“Where”子句。这不让你满意吗? 别误会,你的回答很好,我只是补充一点说明,但并没有错。我只是碰巧选择了另一个答案,因为这对我来说很有意义。 @gunr2171 好的。感谢您对已接受的答案进行澄清。我没有完全明白。现在我知道了:D

以上是关于带有自定义比较器的 Linq 左外连接的主要内容,如果未能解决你的问题,请参考以下文章

在 Linq 中使用左外连接

Linq中的lambda /方法语法中的左外连接[重复]

Linq左外连接 多字段连接

LINQ:具有多个条件的左外连接

linq中的左外连接

如何使用 Dynamic Linq 进行左外连接?