LINQ cho các thực thể không nhận ra phương pháp


116

Tôi gặp lỗi sau khi cố gắng thực hiện truy vấn linq:

LINQ to Entities không nhận dạng phương thức 'Boolean IsCharityMatching (System.String, System.String)' và phương thức này không thể được dịch thành một biểu thức lưu trữ.

Tôi đã đọc rất nhiều câu hỏi trước đây trong đó mọi người gặp cùng một lỗi và nếu tôi hiểu chính xác điều này là do LINQ to Entities yêu cầu toàn bộ biểu thức truy vấn linq được dịch sang truy vấn máy chủ và do đó bạn không thể gọi một phương thức bên ngoài trong đó. Tôi vẫn chưa thể chuyển đổi kịch bản của mình thành một thứ gì đó hoạt động được và não của tôi đang bắt đầu tan chảy, vì vậy tôi đã hy vọng ai đó có thể chỉ cho tôi đúng hướng. Chúng tôi đang sử dụng Entity Framework và mẫu đặc tả (và tôi là người mới sử dụng cả hai).

Đây là mã sử dụng đặc điểm kỹ thuật:

ISpecification<Charity> specification = new CharitySearchSpecification(charityTitle, charityReference);

charities = charitiesRepository.Find(specification).OrderBy(p => p.RegisteredName).ToList();

Đây là biểu thức linq:

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    return p => p.IsCharityMatching(this.charityName, this.charityReference);
}

Đây là phương pháp IsCharityMatching:

public bool IsCharityMatching(string name, string referenceNumber)
{
    bool exists = true;

    if (!String.IsNullOrEmpty(name))
    {
        if (!this.registeredName.ToLower().Contains(name.ToLower()) &&
            !this.alias.ToLower().Contains(name.ToLower()) &&
           !this.charityId.ToLower().Contains(name.ToLower()))
        {
            exists = false;
        }
    }

    if (!String.IsNullOrEmpty(referenceNumber))
    {
        if (!this.charityReference.ToLower().Contains(referenceNumber.ToLower()))
        {
            exists = false;
        }
    }

    return exists;
}

Nói cho tôi biết nếu bạn cần nhiều thông tin khác.

Cảm ơn nhiều,

Annelie



Cũng sẽ kiểm tra điều này, cảm ơn!
annelie,

1
Sẽ rất vui khi được biết bạn đang sử dụng Find()như thế nào khi bạn sử dụng IsSatisfied()bên trong nó như thế nào .
Alisson

Câu trả lời:


124

Như bạn đã tìm ra, Entity Framework thực sự không thể chạy mã C # của bạn như một phần của truy vấn. Nó phải có thể chuyển đổi truy vấn thành một câu lệnh SQL thực tế. Để điều đó hoạt động, bạn sẽ phải cấu trúc lại biểu thức truy vấn của mình thành một biểu thức mà Entity Framework có thể xử lý.

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    string name = this.charityName;
    string referenceNumber = this.referenceNumber;
    return p => 
        (string.IsNullOrEmpty(name) || 
            p.registeredName.ToLower().Contains(name.ToLower()) ||
            p.alias.ToLower().Contains(name.ToLower()) ||
            p.charityId.ToLower().Contains(name.ToLower())) &&
        (string.IsNullOrEmpty(referenceNumber) ||
            p.charityReference.ToLower().Contains(referenceNumber.ToLower()));
}

1
khi nghi ngờ, hãy tìm kiếm nó: stackoverflow.com/questions/2352764/…
Chris Hayes

2
Trả lại một cấu trúc đã xây dựng Expression<Func<T,type>>là một cách tiếp cận rất tốt cho việc này.
Travis J

Bạn sẽ sử dụng điều này như thế nào trong biểu thức LINQ? Tôi muốn làm điều gì đó như thế này dưới dạng mệnh đề Where có thể sử dụng lại nhưng đang gặp khó khăn trong việc triển khai nó.
Zorgarath

4
CHỈNH SỬA: nevermind, nó sẽ là:context.Where(IsSatisfied())
Zorgarath

Phần quan trọng: "Entity Framework thực sự không thể chạy mã C # của bạn như là một phần của truy vấn của nó."
Alper

1

Tôi gặp lỗi tương tự trong mã này:

 var articulos_en_almacen = xx.IV00102.Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

đây là lỗi chính xác:

System.NotSupportedException: Phương thức 'LINQ to Entities không nhận dạng được phương thức' Boolean Exists (System.Predicate`1 [conector_gp.Models.almacenes_por_sucursal]) 'và phương thức này không thể được dịch thành một biểu thức lưu trữ.'

Tôi đã giải quyết theo cách này:

var articulos_en_almacen = xx.IV00102.ToList().Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

Tôi đã thêm một .ToList () trước bảng của mình, điều này tách mã Thực thể và mã linq, đồng thời tránh cho biểu thức linq tiếp theo của tôi bị dịch

LƯU Ý: giải pháp này không tối ưu vì tránh lọc thực thể và chỉ cần tải tất cả bảng vào bộ nhớ


1
Thông thường, đây là giải pháp dễ nhất nhưng để không tải tất cả đối tượng, tôi thường chọn ẩn danh trước .ToList () chỉ với những gì tôi cần ... xx.Select (x => new {x.Id, x.DateTimeUpdate }). ToList (). Select (x => new {x.Id, DateTimeUpdate = x.DateTimeUpdate.ToString ("dd / MM / yyyy")})
Diógenes

0

Nếu có ai đang tìm kiếm câu trả lời VB.Net (như tôi ban đầu), thì đây là:

Public Function IsSatisfied() As Expression(Of Func(Of Charity, String, String, Boolean))

Return Function(charity, name, referenceNumber) (String.IsNullOrWhiteSpace(name) Or
                                                         charity.registeredName.ToLower().Contains(name.ToLower()) Or
                                                         charity.alias.ToLower().Contains(name.ToLower()) Or
                                                         charity.charityId.ToLower().Contains(name.ToLower())) And
                                                    (String.IsNullOrEmpty(referenceNumber) Or
                                                     charity.charityReference.ToLower().Contains(referenceNumber.ToLower()))
End Function

-1

Tôi đã gặp sự cố tương tự với vấn đề của bạn và tài liệu LINQ này đã giúp tôi tìm thấy các hàm chuỗi phù hợp để giải quyết các hạn chế.

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.