Linq to SQL 使用 Lambda 语法左外部联接,并在 2 列上联接(复合联接键)



我正在尝试使用 Linq to SQL 作为 Lambda 表达式在 2 列上制作内部连接。正常查询如下所示。

SELECT * FROM participants 
LEFT OUTER JOIN prereg_participants ON prereg_participants.barcode = participants.barcode
AND participants.event_id = prereg_participants.event_id
WHERE (participants.event_id = 123)

我成功地使用以下代码在一列上制作了左外部连接。

var dnrs = context.participants.GroupJoin(
context.prereg_participants,
x => x.barcode,
y => y.barcode,
(x, y) => new { deelnr = x, vi = y })
.SelectMany(
x => x.vi.DefaultIfEmpty(),
(x, y) => new { deelnr = x, vi = y })
.Where(x => x.deelnr.deelnr.event_id == 123)
.ToList();

问题是,使用上述 Lambda,我得到了太多的结果,因为它缺少AND participants.event_id = prereg_participants.event_id部分。但无论我尝试什么,我都没有获得正确数量的参与者。

我查看了以下现有问题,但没有一个在编写正确的 lambda 时解决了我的问题。大多数解决方案都是 lambda 格式的 nog 或不是多列上的左外部连接。

如何在 LINQ 中对单个联接中的多个字段进行联接

LINQ to SQL - 具有多个联接条件的左外联接

按 Lambda 表达式使用两列以上的列进行分组

其中大部分来自这个谷歌搜索

查询:

var petOwners =
from person in People
join pet in Pets
on new
{
person.Id,
person.Age,
}
equals new
{
pet.Id,
Age = pet.Age * 2, // owner is twice age of pet
}
into pets
from pet in pets.DefaultIfEmpty()
select new PetOwner
{
Person = person,
Pet = pet,
};

λ:

var petOwners = People.GroupJoin(
Pets,
person => new { person.Id, person.Age },
pet => new { pet.Id, Age = pet.Age * 2 },
(person, pet) => new
{
Person = person,
Pets = pet,
}).SelectMany(
pet => pet.Pets.DefaultIfEmpty(),
(people, pet) => new
{
people.Person,
Pet = pet,
});

查看代码,或克隆我的 git 存储库,然后玩!

我能够在复合外键对上获得此LEFT OUTER JOINbarcode, event_id在 Linq2Sql 和实体框架中工作,并根据此查询语法示例转换为 lambda 语法。

这通过创建一个匿名投影来工作,该投影用于匹配连接条件的左侧和右侧:

var dnrs = context.participants.GroupJoin(
context.prereg_participants,
x => new { JoinCol1 = x.barcode, JoinCol2 = x.event_id }, // Left table join key
y => new { JoinCol1 = y.barcode, JoinCol2 = y.event_id }, // Right table join key
...

笔记

这种方法依赖于赋予相同匿名类的自动等式,即:

由于匿名类型的 Equals 和 GetHashCode

方法是根据属性的 Equals 和 GetHashCode 方法定义的,因此仅当同一匿名类型的两个实例的所有属性都相等时,它们才相等。

因此,对于连接键的两个投影需要具有相同的类型才能equal,编译器需要将它们视为幕后的同一匿名类,即:

  • 两个匿名投影中的联接列数必须相同
  • 字段类型必须与类型相同且可兼容
  • 如果字段名称不同,则需要为它们设置别名(我用过JoinColx(

我在GitHub上放了一个示例应用程序。

遗憾的是,表达式树中尚不支持值元组,因此您需要在投影中坚持使用匿名类型。

如果是左外部连接,其中左实体与右实体可以有零个或最多一个连接,则可以使用:

// Let's have enumerables "left" and "right"
// and we want to join both full entities with nulls if there's none on the right.
left.GroupJoin(
right,
l => l.LeftKey,
r => r.RightKey,
(l, r) => new { Left = l, Right = r.FirstOrDefault() });

如果要仅使用右边的一个属性加入左边:

// Let's have enumerables "left" and "right"
// and we want to join right's attribute RightId and to set 0 for those having no Id.
left.GroupJoin(
right,
l => l.LeftKey,
r => r.RightKey,
(l, r) => new { Left = l, RightId = r.FirstOrDefault()?.RightId ?? 0 });

您可以通过使用匿名类型来执行此操作。

例:

var result = from a in context.participants
join b context.prereg_participants on new { X = a.barcode, Y = a.event_id } equals new { X = b.barcode, Y = b.event_id } into A
from b in A.DefaultIfEmpty()
where a.event_id = 123

相关内容

最新更新