在LINQ中使用自联接查询

Bea*_*ear 4 c# sql linq unit-of-work

我有一个表,其中包含Id作为主键和LastMeterReadingId(引用同一个表的外键)之类的列 - 类似于Parent Meter Reading.

这就是它的样子

我想得到所有尚未使用的行,如Parent.我想避免当抄表是超过一米读数的父母时的情况.

我知道如何加入同一个表,但我不知道如何只选择那些不是父表的记录.这就是没有条件语句的查询的样子.

return (from m in uow.MeterReadingReadWriteRepository.Query()
                join parent in uow.MeterReadingReadWriteRepository.Query() on m.Id equals parent.LastMeterReadingId

                select new MeterReadingDto()
                {
                    (...)
                }).ToList();
Run Code Online (Sandbox Code Playgroud)

你知道如何以有效的方式实现它吗?

问候.

Iva*_*oev 6

我想得到所有尚未使用的行,如Parent

换句话说,您希望所有没有子项的行.请注意,parent查询中的变量名称具有误导性 - 当您这样做时a join b on a.Id equals b.ParentId,a父项b是孩子.

无论如何,至少有3种方法可以实现您的目标,从现在的数据库查询优化器的角度来看,IMO是等效的(即应该同样有效):

(1)使用!Any(...)等同于SQL NOT EXISTS(...):

from m in uow.MeterReadingReadWriteRepository.Query()
where !uow.MeterReadingReadWriteRepository.Query().Any(child => m.Id == child.LastMeterReadingId)
select ...
Run Code Online (Sandbox Code Playgroud)

(2)使用组连接:

from m in uow.MeterReadingReadWriteRepository.Query()
join child in uow.MeterReadingReadWriteRepository.Query()
on m.Id equals child.LastMeterReadingId into children
where !children.Any()
select ...
Run Code Online (Sandbox Code Playgroud)

(3)使用左外反连接:

from m in uow.MeterReadingReadWriteRepository.Query()
join child in uow.MeterReadingReadWriteRepository.Query()
on m.Id equals  child.LastMeterReadingId into children
from child in children.DefaultIfEmpty()
where child == null
select ...
Run Code Online (Sandbox Code Playgroud)

如果这是EF(LINQ to Entities),则前两个将转换为同一个NOT EXISTS基于SQL 的查询.而最后一个被翻译成"传统的" LEFT JOIN ... WHERE right.PK IS NULL基于SQL 的查询.