如何编写需要子查询的Linq查询?

时间:2017-06-20 15:21:03

标签: entity-framework linq linq-to-entities

我需要从数据库中提取有关支持服务单的一些信息。每张票与医学成像系统相关联,并且每个系统可以具有或不具有与其相关联的服务封面。如果是这样,可能会有多个服务封面条目,但只有一个我们感兴趣。

我知道这对Linq无效,但我真正想做的是以下......

var tickets = cxt.SupportTickets
  .Select( t => new {
    ID = t.ID,
    Customer = t.Customer.Name,
    var cover = t.System.CoverItems.FirstOrDefault(ci => // some query)
    CoverLevel = cover?.Level.Name,
    Expiry = cover?.Expiry.ToLongDateString()
  });

有没有办法做到这一点?我知道我可以从封面上为我想要的每一点数据重复t.CoverItems.FirstOrDefault(...)位,但除了会产生的绝对可怕的代码混乱之外,它将是非常低效的,因为它需要做同样的事情每张票的子查询多次。

我考虑将其全部分解为foreach循环,但后来我无法看到如何创建tickets集合。我无法创建一个空集合,然后添加对象,因为它们是匿名类型,我不想考虑如何指定泛型类型!

任何想法?

3 个答案:

答案 0 :(得分:2)

您可以提高可读性:

var tickets = cxt.SupportTickets
  .Select(t => new { 
       Ticket = t, 
       CoverItem = t.System.CoverItems.FirstOrDefault(ci => // some query)
    })
  .Select(x => new {
    ID = x.Ticket.ID,
    Customer = x.Ticket.Customer.Name,
    CoverLevel = x.CoverItem?.Level.Name,
    Expiry = x.CoverItem?.Expiry.ToLongDateString()
  });

答案 1 :(得分:2)

您可以使用查询表示法来使用let子句:

var query=from t in cxt.SupportTickets
          let cover = t.System.CoverItems.FirstOrDefault(ci => some query)
          select new {
                      ID = t.ID,
                      Customer = t.Customer.Name,
                      CoverLevel = cover?.Level.Name,
                      Expiry = cover?.Expiry//.ToLongDateString()
                     };

最后会像@TimSchmelter一样回答,但对于类似的事情你可以使用let。另外,我几乎可以肯定EF中不支持ToLongDateString()方法。

答案 2 :(得分:1)

我试过这个(如果你想单独开发一个子查询,因为SoC原理):

var innerQuery =  cxt.SupportTickets
                    .Where(artist => artist.coverId == SomeParameter)
                    .Select(artist => new {
                        artistId = artist.artistId,
                        artistCompleteName = artist.artistName,
                        artistMasterPiece = artist.CoverName
                    });

var tickets = cxt.SupportTickets
  .Where(
    t => innerQuery.Contains(t.coverId)
  )
  .Select( t => new {
    ID = t.ID,
    Customer = t.Customer.Name,
    var cover = t.System.CoverItems.FirstOrDefault()
    CoverLevel = cover?.Level.Name,
    Expiry = cover?.Expiry.ToLongDateString()
  });