使用自定义比较器进行 Linq 左外连接

7
我将尝试制作一个带有自定义比较器的左连接查询。
我有以下列表:
List<ColumnInformation> list1;
List<ColumnInformation> list2;

这些保存了关于SQL列的信息(数据类型、名称、表等)。我已经重写了该类的Equals方法,并创建了一个operator ==operator !=

我理解如何进行左外连接

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 中在 ColumnComparer 中实现的 Equals 和 GetHashCode 方法。 - Hamlet Hakobyan
@HamletHakobyan,我已经在ColumnInformation中重写了Equals。现在我的代码没有触及它。这样做有什么好处(包括GetHashCode)? - gunr2171
我必须说,使用扩展方法可以在LINQ中实现你想要的所有功能,但是使用查询语法无法完成某些操作。事实上,在扩展方法中,“join into”的等效操作是“GroupJoin”。 - King King
@KingKing,从名字上看不出来GroupJoin是什么意思。如果您能提供一个例子,我会非常高兴。 - gunr2171
抱歉造成困惑。请尝试在“ColumnInformation”中实现IEquatable<T> - Hamlet Hakobyan
2个回答

5
你可以使用 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 的实际需求!? - Alireza
1
@Alireza,这个使用了左外连接(使用DefaultIfEmpty()),并且使用了我的比较器(cc)。这是一个正确的答案。 - gunr2171
@gunr2171 哎呀!抱歉,我没有注意到 **'cc'**。感谢您的澄清。 - Alireza

0

您可以结合 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
@gunr2171 你问如何将自定义比较器用于Join查询,对吗? 你可以调用任何返回布尔值的方法来提供“Where”子句。 这难道不满足您的要求吗? - Alireza
不要误会,你的回答很好,我只是想补充一点说明,但并没有错。我只是选择了另一个答案,因为它对我来说更有意义。 - gunr2171
@gunr2171 好的,谢谢你对被接受答案的澄清。我之前没有完全理解,现在我明白了:D - Alireza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接