2011-05-11 93 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