简体   繁体   English

Linq 查询:按子查询使用 count() 组进行内部连接

[英]Linq query: inner join with a count() group by subquery

We have some Machines having Devices attached.我们有一些附有设备的机器。 Not all the machines have devices atached and the devices cand be moved between machines.并非所有机器都连接了设备,并且设备可以在机器之间移动。 The devices generate Errors and we need to count those errors occured in the past day.设备产生错误,我们需要计算过去一天发生的错误。

We have four tables: Machines (with Id and Code), Devices (with Id and Code), a pairing table DevicesMachines (Id, IdMachine, IdDevice, From datetime, To datetime) and Errors(Id, IdDevice, Moment datetime, Description).我们有四个表: Machines (with Id and Code), Devices (with Id and Code), 配对表 DevicesMachines (Id, IdMachine, IdDevice, From datetime, To datetime) 和 Errors(Id, IdDevice, Moment datetime, Description) .

The working SQL query is this:工作 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

I have tried many syntaxes, one of which is below:我尝试了很多语法,其中之一如下:

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
  };
}

I failed to find the right Linq syntax and I need your help.我没有找到正确的 Linq 语法,我需要你的帮助。

Thank you, Daniel谢谢你,丹尼尔

Based on the SQL you provided, I created what I think is the equivalent EF LINQ expression:根据您提供的 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()
        };
}

I made some tests in memory and it seems to yield the same behavior as your provided SQL query.我在内存中做了一些测试,它似乎产生与您提供的 SQL 查询相同的行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM