LINQ To Entities không nhận ra phương thức Last. Có thật không?


144

Trong truy vấn này:

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ó sang cái này để 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 truy vấn đầu tiên.

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


lưu trữ đối tượng IEnumitable của bạn vào một biến mới, sau đó trả về biến.last (). nó sẽ làm việc
Ali.Rashidi

Câu trả lời:


220

Hạn chế đó xuất phát từ thực tế là cuối cùng nó phải dịch truy vấn đó sang SQL và SQL có SELECT TOP(trong T-SQL) nhưng không phải là SELECT BOTTOM(không có điều đó).

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

EDIT: Các nhà cung cấp khác có thể sẽ có các triển khai khác nhau SELECT TOP 1, trên Oracle, nó có thể giống nhưWHERE ROWNUM = 1

BIÊN TẬP:

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

Một lần nữa, tôi không khuyên bạn nên thực hiện lần thứ hai này, nhưng nó giúp minh họa sự khác biệt giữa vị trí và khi biểu thức LINQ được thực thi.


và LINQ To SQL xử lý tình huống này như thế nào?
bevacqua

@ Không, vâng 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 bản ghi từ cơ sở dữ liệu chỉ để lọc chúng xuống năm bản ghi
bevacqua

2
Nếu bạn biết truy vấn của mình sẽ trả về kết quả nhỏ, việc gọi ToListkhông tệ.
Justin Skiles

35

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

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

14

Thay thế Last()bằng bộ chọn LinqOrderByDescending(x => x.ID).Take(1).Single()

Một cái gì đó như thế sẽ hoạt động nếu bạn thích 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());
}

1
Có bất kỳ lý do để sử dụng .Take (1) .Single () thay vì .irstOrDefault ()?
Tot Zam

2
@TotZam Thay thế hợp lệ sẽ là .irst () trong trường hợp đó, vì Single () ném ngoại lệ nếu số lượng vật phẩm không chính xác 1.
MEMark

0

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

dbSet
    .Where(f => f.Id == dbSet.Max(f2 => f2.Id))
    .FirstOrDefault();

0

Đó là bởi vì LINQ to Entities (và cơ sở dữ liệu nói chung) không hỗ trợ tất cả các phương thức LINQ (xem tại đây để biết chi tiết: http://msdn.microsoft.com/en-us/l Library / bb738550.aspx )

Những gì bạn cần ở đây là sắp xếp dữ liệu của bạn theo cách sao cho bản ghi "cuối cùng" trở thành "đầu tiên" và sau đó bạn có thể sử dụng FirstOrDefault. Lưu ý rằng databasese thường không có các khái niệm như "đầu tiên" và "cuối cùng", nó không giống như bản ghi được chèn gần đây nhất sẽ là "cuối cùng" trong bảng.

Phương pháp này có thể giải quyết vấn đề của bạn

db.databaseTable.OrderByDescending(obj => obj.Id).FirstOrDefault();

-2

Thêm một chức năng duy nhất AsEnumerable()trước khi chức năng Chọn làm việc cho tôi.
Thí dụ:

return context.ServerOnlineCharacters
    .OrderByDescending(p => p.ServerStatus.ServerDateTime)
    .GroupBy(p => p.RawName).AsEnumerable()
    .Select(p => p.FirstOrDefault());

Tham chiếu: https://www.codeproject.com/Questions/1005274/LINEQ-to-Entities-does-not-recognize-the-method-Sys


Bạn nên kết hợp mã làm việc từ liên kết vào câu trả lời của bạn. Câu trả lời chỉ liên kết sẽ thu hút sự chú ý tiêu cực. Vui lòng cung cấp câu trả lời đầy đủ bằng cách thêm mã bạn đã tìm thấy để giúp đỡ và giải quyết vấn đề. Điều này giải quyết vấn đề liên kết không hoạt động do lỗi 404 trong tương lai.
Studocwho

1
đã thêm ví dụ vào câu trả lời của tôi
Artem Levitin

Mặt trái của câu trả lời này là nó sẽ mang lại tất cả các kết quả trước phía máy chủ "AsEnumerable" và sau đó chọn cái đầu tiên. Điều này có thể rất không mong muốn. (Tôi đã gặp tình huống như thế này khi kết quả mất hơn 20 giây do các bản ghi 20k + được đưa về phía máy chủ, một khi tôi chuyển nó về phía DB, kết quả trả về sau chưa đầy một giây)
TChadwick
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.