Linq查询:内部连接带有count()组的子查询

时间:2019-01-27 20:38:49

标签: c# sql linq

我们有一些连接了设备的机器。并非所有机器都配备了设备,并且可以在机器之间移动设备。设备会产生错误,我们需要计算过去一天发生的错误。

我们有四个表:机器(带有ID和代码),设备(带有ID和代码),一个配对表DevicesMachines(Id,IdMachine,IdDevice,从日期时间到To datetime)和错误(Id,IdDevice,Moment日期时间) ,说明)。

有效的SQL查询是这样:

Select m.Id, m.Code, 
   Coalesce(d.Code, 'NA') As DeviceCode,
   Coalesce(Err.ErrorCnt,0) As ErrorCnt
From Machines As m
Left Outer Join (Select IdMachine, IdDevice From DevicesMachines as dm 
Where GetDate() Between dm.From And dm.To) As dm on m.Id=dm.IdMachine
Left Outer Join Devices As d on dm.IdDevice=d.Id
Left outer join 
  ( Select IdMachine, Count(Id) As ErrorCnt From Errors as er 
    Where er.Moment >= DateAdd(day,-1,GetUtcDate()) 
    Group By IdMachine) As Err 
On m.Id=Err.IdMachine

我尝试了很多语法,其中一种语法如下:

using ( DataContextM dcMachines = new dataContextM())
{
  IEnumerable<MachineRow> lstM = 
    from m in dcMachines.Machines
    from dm in dcMachines.DevicesMachines.Where(dm => (dm.IdMachine == m.Id) && (dm.From <= DateTime.Now) && (dm.To >= DateTime.Now)).DefaultIfEmpty()
    from d in dcMachines.Devices.Where(d => d.Id == dm.IdDevice).DefaultIfEmpty()
    from er in dcMachines.Errors
        .Where(er => (er.Moment >= DateTime.Now) && (er.Moment <= DateTime.Now.AddDays(-1))) 
        .GroupBy(er => er.IdMachine)
        .Select(er => new { IdMachine = er.Key, ErrorCnt = er.Count() })
        .Where(er=> er.IdMachine==m.Id).DefaultIfEmpty()
 select new MachineRow
 {
    Id = amId,
    Code = m.Code,
    DeviceCode = (d == null) ? "NA" : d.DeviceCode,
    IdDevice = (d == null) ? 0: d.Id,
    ErrorCnt = (er == null) ? 0 : er.ErrorCnt
  };
}

我找不到正确的Linq语法,需要您的帮助。

谢谢你, 丹尼尔

1 个答案:

答案 0 :(得分:0)

根据您提供的SQL,我创建了等效的EF LINQ表达式:

using (var dcMachines = new DataContextM())
{
    var now = DateTime.Now;
    var utcYesterday = DateTime.UtcNow.AddDays(-1);

    var devicesMachinesQuery =
        from dm in dcMachines.DevicesMachines
        where dm.From <= now && dm.To >= now
        join d in dcMachines.Devices on dm.IdDevice equals d.Id into dItems
        from d in dItems.DefaultIfEmpty()
        select new
        {
            dm.IdMachine,
            dm.IdDevice,
            DeviceCode = d != null ? d.Code : "NA"
        };

    var errorsQuery =
        from err in dcMachines.Errors
        where err.Moment >= utcYesterday
        select err;

    IEnumerable<MachineRow> lstM =
        from m in dcMachines.Machines
        join dm in devicesMachinesQuery on m.Id equals dm.IdMachine into dmItems
        from dm in dmItems.DefaultIfEmpty()
        select new MachineRow
        {
            Id = m.Id,
            Code = m.Code,
            DeviceCode = dm != null ? dm.DeviceCode : "NA",
            IdDevice = dm != null ? dm.IdDevice : 0,
            ErrorCnt = (
                from err in errorsQuery
                where err.IdMachine == m.Id
                select err.Id
                )
                .Count()
        };
}

我在内存中进行了一些测试,它似乎产生了与您提供的SQL查询相同的行为。