2011-05-11 68 views
2

我希望能够以某种方式打破了下面的代码:重构LINQ to Entities查询与设变量和子查询

return from e in _context.Employees 
     let HasWatchedAllVideos = 
     (
      from ev in _context.EmployeeVideos 
      where ev.EmployeeId == e.Id && ev.EndTime.HasValue 
      select ev.Id 
     ).Count() == _context.Videos.Count() 
     let EndTime = HasWatchedAllVideos ? 
     (
      from ev in _context.EmployeeVideos 
      where ev.EmployeeId == e.Id 
      select ev.EndTime 
     ).Max() : null 
     let StartTime = 
     (
      from ev in _context.EmployeeVideos 
      where ev.EmployeeId == e.Id 
      select ev.StartTime 
     ).Min() 
     select new EmployeeListItem 
     { 
      Id = e.Id, 
      FirstName = e.FirstName, 
      LastName = e.LastName, 
      Company = e.Company, 
      HasWatchedAllVideos = HasWatchedAllVideos, 
      StartTime = StartTime, 
      EndTime = EndTime 
     }; 

例如,我正在寻找一种方式来分解出:

let HasWatchedAllVideos = 
(
    from ev in _context.EmployeeVideos 
    where ev.EmployeeId == e.Id && ev.EndTime.HasValue 
    select ev.Id 
).Count() == _context.Videos.Count() 

为一个单独的方法为可重用性的目的,但我无法弄清楚如何去做这件事。我曾尝试过:

private bool HasWatchedAllVideos(int employeeId) 
{ 
    return (from ev in _context.EmployeeVideos 
      where ev.EmployeeId == employeeId && ev.EndTime.HasValue 
      select ev.Id 
      ).Count() == _context.Videos.Count(); 
} 

这给了我旧的最爱'LINQ to Entities does not recognized the method'exception。

+0

可能重复LINQ IQueryable表达式删除重复部分的查询](http://stackoverflow.com/questions/769351/refactoring-linq-iqueryable-expression-to-remove-duplicated-portions-of-queries) – Merritt 2011-05-12 18:49:32

回答

0

这个问题可能不会得到很多的行动,所以我发布一个相关的问题是帮助我试图找到一个更好的解决方案:

refactoring LINQ IQueryable expression to remove duplicated portions of queries

下面是我的特殊变异代码的溶液:

public class AdaTrainingService : ADATraining.Web.Models.IAdaTrainingService, IDisposable 
{ 
    private ADATrainingEntities _context = new ADATrainingEntities(); 

    public IQueryable<EmployeeListItem> GetEmployeeListing() 
    { 
     return from e in _context.Employees 
       join evsws in EmployeeVideoAggregatesView() on e.Id equals evsws.EmployeeId 
       select new EmployeeListItem 
       { 
        Id = e.Id, 
        FirstName = e.FirstName, 
        LastName = e.LastName, 
        Company = e.Company, 
        HasWatchedAllVideos = evsws.HasWatchedAllVideos, 
        StartTime = evsws.StartTime, 
        EndTime = evsws.EndTime 
       }; 
    } 

    private class EmployeeVideoSeriesWatchingStats 
    { 
     public int EmployeeId { get; set; } 
     public DateTime? StartTime { get; set; } 
     public DateTime? EndTime { get; set; } 
     public bool HasWatchedAllVideos { get; set; } 
    } 

    private IQueryable<EmployeeVideoSeriesWatchingStats> EmployeeVideoAggregatesView() 
    { 
     return from ev in _context.EmployeeVideos 
       group ev by ev.EmployeeId into myGroup 
       select new EmployeeVideoSeriesWatchingStats 
       { 
        EmployeeId = myGroup.Key, 
        StartTime = myGroup.Min(x => x.StartTime), 
        EndTime = myGroup.Max(x => x.EndTime), 
        HasWatchedAllVideos = myGroup.Count() == _context.Videos.Count() 
       }; 
    } 

    public void Dispose() 
    { 
     _context.Dispose(); 
    } 
} 

- UPDATE 5/13/2011 -

上面的例子进行内加入并不会活像K中要包括所有员工即使EmployeeVideoAggregatesView()不返回任何结果的情况下,这样允许左外连接,我不得不调整一下代码:重构的

public IQueryable<EmployeeDetails> GetEmployeeListing() 
{ 
    return from e in _context.Employees 
      join evsws in EmployeeVideoAggregatesView() on e.Id equals evsws.EmployeeId into myJoin 
      from mj in myJoin.DefaultIfEmpty() 
      select new EmployeeDetails 
      { 
       Id = e.Id, 
       FirstName = e.FirstName, 
       LastName = e.LastName, 
       Company = e.Company, 
       BadgeNumber = e.BadgeNumber, 
       Title = e.Title, 
       HasWatchedAllVideos = (mj.HasWatchedAllVideos == null) ? false : mj.HasWatchedAllVideos, 
       StartTime = mj.StartTime, 
       EndTime = mj.EndTime 
      }; 
} 
0
// don't count every time 
var totalCount = _context.Videos.Count(); 

from e in _context.Employees 
let HasWatchedAllVideos = 
    totalCount == 
    _context.EmployeeVideos.Count(ev => ev.EmployeeId == e.Id && ev.EndTime.HasValue) 

// count just once per employee 
let employeeVideos = _context.EmployeeVideos.Count(ev => ev.EmployeeId == e.Id) 

let EndTime = HasWatchedAllVideos ? employeeVideos.Max() : null 
let StartTime = HasWatchedAllVideos ? employeeVideos.Min() : null 

select new EmployeeListItem 
{ 
    Id = e.Id, 
    FirstName = e.FirstName, 
    LastName = e.LastName, 
    Company = e.Company, 
    HasWatchedAllVideos = HasWatchedAllVideos, 
    StartTime = StartTime, 
    EndTime = EndTime 
}; 
+0

谢谢你的时间,但这不是我的意思。 – Merritt 2011-05-13 18:54:27

+0

让我多说一点:我试图找出在其他地方重用我的查询部分的方法。你的例子是我最初发布的一个清理器(我相信性能更高)版本,但是我试图解决这个问题:即我不能将EndTime/StartTime/HasWatchedAllvideos的概念分解为可重用的大量的代码。 – Merritt 2011-05-13 19:37:43

+0

@Merritt:计算指数如何?插入速度会降低,以计算所有视频,节省最小和最大,但我认为读取(它更频繁地发生)速度将显着增加。 – abatishchev 2011-05-14 07:51:37