在LINQ中使用自联接查询

时间:2016-04-26 11:26:15

标签: c# sql linq unit-of-work

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

That's how it's looks like

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

我知道如何加入同一张桌子,但我不知道如何只选择那些不是父母的记录。这就是在没有条件声明的情况下查询的样子。

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

                select new MeterReadingDto()
                {
                    (...)
                }).ToList();

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

问候。

4 个答案:

答案 0 :(得分:6)

  

我想获取所有尚未使用的行,如父

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

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

(1)使用等同于SQL !Any(...)的{​​{1}}:

NOT EXISTS(...)

(2)使用group join

from m in uow.MeterReadingReadWriteRepository.Query()
where !uow.MeterReadingReadWriteRepository.Query().Any(child => m.Id == child.LastMeterReadingId)
select ...

(3)使用左外反连接:

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

如果这是EF(LINQ to Entities),则前两个将转换为基于SQL 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 ... 的同一个查询。而最后一个被翻译成"传统"基于SQL NOT EXISTS的查询。

答案 1 :(得分:0)

你可以添加

where !(from child in uow.MeterReadingReadWriteRepository.Query() where child.Id == m.LastMeterReadingId select child).Any()

不确定这会如何聪明地进行优化。将uow.MeterReadingReadWriteRepository.Query()分解出去也会更好。

您是否在外键约束中的Meter Reading实体中没有Child关系/集合? - 这会使查询更直接。

答案 2 :(得分:0)

var readings = uow.MeterReadingReadWriteRepository.Query();

var parents = readings
        .Join(readings, child => child.Id, parent => parent.LastMeterReadingId,
                (child, parent) => new {parent.Id})
        .Distinct()
        .ToDictionary(a => a.Id);

var result = (from m in readings
                  where !parents.Contains(m.Id) 
                  select new
                    {
                       Id = m.Id
                    }).ToList();

答案 3 :(得分:0)

谢谢@Ben Jackson

   <related-products [id]="product.id"></related-products>

这是大多数值属性的样子。也许我应该使用JOIN的T-SQL查询到条件语句之前提到的CTE?我会尽快尝试你的解决方案。