2012-01-25 46 views
4

考虑以下查询:LINQ到实体查询

var profilelst = 
    (
     from i in dbContext.ProspectProfiles 
     where i.CreateId == currentUser 
     select new ProspectProfile 
     { 
      ProspectId = i.ProspectId, 
      Live = i.Live, 
      Name = i.Name, 
      ServiceETA = i.Opportunities.OrderByDescending(t => t.FollowUpDate) 
       .FirstOrDefault() 
       .ServiceETA.ToString(), 
      FollowUpDate = i.Opportunities.OrderByDescending(t => t.FollowUpDate) 
       .FirstOrDefault() 
       .FollowUpDate 
     } 
    ) 
    .ToList(); 

return profilelst.OrderByDescending(c=>c.FollowUpDate) 
     .Skip(0).Take(endIndex) 
     .ToList(); 

在这里,在此查询,请看看FollowUpDateServiceType,这些都我有机会表取回,有没有其他的解决办法得到这些既..

一对多的关系在表像:ProspectProfile -> Opportunities

无论我写的查询是好的或有任何其他解决办法,可以在更简单的方式来完成。

+0

重新格式化的代码使其可读,但是,实际问题并不清楚。 –

+0

您是否测试过您的第一个查询是否可用?我怀疑。 – Slauma

回答

4

可以提高的唯一的事情是避免通过改变你的代码,这个订货两次:

var profilelst 
    = dbContext.ProspectProfiles 
      .Where(i => i.CreateId == currentUser) 
      .Select(i => 
        { 
         var opportunity 
          = i.Opportunities 
           .OrderByDescending(t => t.FollowUpDate) 
           .First(); 
         return new ProspectProfile 
         { 
          ProspectId = i.ProspectId, 
          Live = i.Live, 
          Name = i.Name, 
          ServiceETA = opportunity.ServiceETA.ToString(), 
          FollowUpDate = opportunity.FollowUpDate 
         } 
        }).ToList(); 

return profilelst.OrderByDescending(c => c.FollowUpDate).Take(endIndex).ToList(); 

我做了一些改动,以您的原始查询:

  1. 我改成了使用方法链式语法。在我看来,阅读起来要容易得多。
  2. 我删除了不必要的Skip(0)
  3. 最大的变化是在Select部分:
    1. 我改变FirstOrDefaultFirst,因为你无论如何访问返回值的属性。如果没有机会,这会引发一个描述性例外。这比你有更好的:在你的情况下,它会抛出一个NullReferenceException。这很糟糕,NullReferenceExceptions总是表明你的程序存在一个错误,而且根本没有描述。
    2. 我将选择机会的部分移出了初始化程序,因此我们只需要执行一次而不是两次。
+0

+1为NullReferenceException – ken2k

+0

我不认为这将与LINQ to Entities一起工作,因为投影到实体中不受支持,'First()'在投影中不受支持,我怀疑在局部变量中使用局部变量支持'Select'表达式。 – Slauma

+0

@Slauma:好点。谨慎提供替代解决方案? –

1

有在查询了不少问题:

  • 不能投射到一个实体(select new ProspectProfile)。 LINQ到实体仅支持突起到匿名类型(select new)或其它类型的其不是用于数字或DateTime类型在LINQ不支持将实体(ServiceETA.ToString()

    您的实体数据模型(select new MySpecialType

  • ToString()的一部分如果Opportunities集合为空,并且ServiceETA是非空值类型(如DateTime),因为EF不能兑现任何值到这样的可变

  • FirstOrDefault().ServiceETA(或FollowUpdate)将抛出异常。

  • 在第一次查询后将使用.ToList()执行数据库中的查询并加载完整的结果。您的后续Take发生在完整列表的内存中,而不是在数据库中。 (你有效地将整个结果列表从数据库加载到内存中,然后丢弃除Take en之外的所有对象。

要解决四个问题,你可以尝试以下方法:

var profilelst = dbContext.ProspectProfiles 
    .Where(p => p.CreateId == currentUser) 
    .Select(p => new 
    { 
     ProspectId = p.ProspectId, 
     Live = p.Live, 
     Name = p.Name, 
     LastOpportunity = p.Opportunities 
      .OrderByDescending(o => o.FollowUpDate) 
      .Select(o => new 
      { 
       ServiceETA = o.ServiceETA, 
       FollowUpDate = o.FollowUpDate 
      }) 
      .FirstOrDefault() 
    }) 
    .OrderByDescending(x => x.LastOpportunity.FollowUpDate) 
    .Skip(startIndex) // can be removed if startIndex is 0 
    .Take(endIndex) 
    .ToList(); 

这会给你一个匿名对象的列表。如果您在实体ProspectProfile的列表中需要结果,则必须复制此查询后的值。请注意,如果ProspectProfile没有OpportunitiesLastOpportunity的结果可能为null