2011-09-03 27 views
111

Trong truy vấn này:LINQ To Entities không nhận ra phương thức Cuối cùng. Có thật không?

public static IEnumerable<IServerOnlineCharacter> GetUpdated() 
{ 
    var context = DataContext.GetDataContext(); 
    return context.ServerOnlineCharacters 
     .OrderBy(p => p.ServerStatus.ServerDateTime) 
     .GroupBy(p => p.RawName) 
     .Select(p => p.Last()); 
} 

tôi đã phải chuyển nó đến đây cho nó hoạt động

public static IEnumerable<IServerOnlineCharacter> GetUpdated() 
{ 
    var context = DataContext.GetDataContext(); 
    return context.ServerOnlineCharacters 
     .OrderByDescending(p => p.ServerStatus.ServerDateTime) 
     .GroupBy(p => p.RawName) 
     .Select(p => p.FirstOrDefault()); 
} 

Tôi thậm chí không thể sử dụng p.First(), để phản ánh các truy vấn đầu tiên.

Tại sao có những hạn chế cơ bản như vậy trong hệ thống ORM mạnh mẽ như thế nào?

+0

lưu đối tượng IEnumrable của bạn vào một biến mới, sau đó trả về biến.last(). nó sẽ hoạt động. –

Trả lời

174

Đó giới hạn đi xuống đến một thực tế mà cuối cùng nó phải dịch truy vấn đó để SQL và SQL có SELECT TOP (trong T-SQL) nhưng không phải là một (không có điều đó) SELECT BOTTOM.

Có một cách dễ dàng, mặc dù chỉ cần đơn đặt hàng giảm dần và sau đó thực hiện First(), đó là những gì bạn đã làm.

EDIT: các nhà cung cấp khác có thể sẽ phải triển khai khác nhau của SELECT TOP 1, trên Oracle nó có lẽ sẽ là một cái gì đó giống như WHERE ROWNUM = 1

EDIT:

Một kém hiệu quả thay thế - Tôi KHÔNG đề nghị điều này! - là để gọi .ToList() trên dữ liệu của bạn trước .Last(), sẽ ngay lập tức thực hiện LINQ to Entities Expression đã được xây dựng đến thời điểm đó và sau đó .Last() của bạn sẽ hoạt động, bởi vì tại thời điểm đó, .Last() được thực thi một cách hiệu quả thay vào đó, ngữ cảnh của một đối tượng LINQ to Objects. (Và như bạn đã chỉ ra, nó có thể mang lại hàng ngàn hồ sơ và tải trọng chất thải của CPU vật chất hóa các vật thể sẽ không bao giờ được sử dụng)

Một lần nữa, tôi sẽ không minh họa sự khác biệt giữa và khi biểu thức LINQ được thực hiện.

+0

và LINQ to SQL đối phó với tình huống này như thế nào? – bevacqua

+1

@Nico: Nó cũng ném. – jason

+0

@Neil có tôi biết tôi có thể gọi ToList, nhưng tôi không muốn lấy hàng ngàn hồ sơ từ cơ sở dữ liệu chỉ để lọc chúng xuống năm hồ sơ – bevacqua

12

Thay Last() bởi một chọn LINQ OrderByDescending(x => x.ID).Take(1).Single()

Something như đó sẽ là tác phẩm nếu bạn prefert làm điều đó trong LINQ:

public static IEnumerable<IServerOnlineCharacter> GetUpdated() 
{ 
    var context = DataContext.GetDataContext(); 
    return context.ServerOnlineCharacters.OrderBy(p => p.ServerStatus.ServerDateTime).GroupBy(p => p.RawName).Select(p => p.OrderByDescending(x => x.Id).Take(1).Single()); 
} 
+0

Điều này làm việc hoàn hảo cho tôi. –

+1

Có lý do nào để sử dụng không. Hãy (1) .Single() thay vì .FirstOrDefault()? –

+1

@TotZam Việc thay thế hợp lệ sẽ là .First() trong trường hợp đó, vì Single() ném một ngoại lệ nếu số mục không chính xác 1. – MEMark

17

Thay vì Last(), Hãy thử điều này:

model.OrderByDescending(o => o.Id).FirstOrDefault(); 
0

Tuy nhiên, một cách khác lấy phần tử cuối cùng mà không có OrderByDescending và tải tất cả các thực thể:

dbSet 
    .Where(f => f.Id == dbSet.Max(f2 => f2.Id)) 
    .FirstOrDefault(); 
Các vấn đề liên quan