6

Tôi đã cố gắng cấu trúc lại một biểu thức LINQ thành một phương thức và đã chạy vào cả hai trường hợp ngoại lệ "Internal .NET Framework Data Provider error 1025." và "The parameter 'xyz' was not bound in the specified LINQ to Entities query expression.".Không thể cấu trúc lại bằng LINQ to Entities và LinqKit/PredicateBuilder

Sau đây là các bộ phận liên quan của mô hình thực thể (sử dụng EF 4.2/LINQ to Entities):

public class Place : Entity 
{ 
    public string OfficialName { get; protected internal set; } 
    public virtual ICollection<PlaceName> { get; protected internal set; } 
} 

public class PlaceName : Entity 
{ 
    public string Text { get; protected internal set; } 
    public string AsciiEquivalent { get; protected internal set; } 
    public virtual Language TranslationTo { get; protected internal set; } 
} 

public class Language : Entity 
{ 
    public string TwoLetterIsoCode { get; protected internal set; } 
} 

Các mô hình quan hệ cơ bản là thế này:

Place (1) <-----> (0..*) PlaceName (0..*) <-----> (0..1) Language 

tôi đang cố gắng để tạo ra một truy vấn sẽ, khi được tìm kiếm term, hãy thử tìm các đối tượng PlaceOfficialName bắt đầu bằng số term HOẶC người có số PlaceNameText hoặc AsciiEquivalent bắt đầu với tìm kiếm term. (Language không phải là nơi tôi đang gặp rắc rối, mặc dù nó là một phần của truy vấn, vì PlaceName s chỉ nên phù hợp cho CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName.)

Các mã sau không làm việc:

internal static IQueryable<Place> WithName(this IQueryable<Place> queryable, 
    string term) 
{ 
    var matchesName = OfficialNameMatches(term) 
     .Or(NonOfficialNameMatches(term)); 
    return queryable.AsExpandable().Where(matchesName); 
} 

private static Expression<Func<Place, bool>> OfficialNameMatches(string term) 
{ 
    return place => place.OfficialName.StartsWith(term); 
} 

private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term) 
{ 
    var currentLanguage = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName; 
    return place => place.Names.Any(
     name => 
     name.TranslationToLanguage != null 
     && 
     name.TranslationToLanguage.TwoLetterIsoCode == currentLanguage 
     && 
     (
      name.Text.StartsWith(term) 
      || 
      (
       name.AsciiEquivalent != null 
       && 
       name.AsciiEquivalent.StartsWith(term) 
      ) 
     ) 
    ); 
} 

Những gì tôi đang cố gắng làm tiếp theo là refactor phương pháp NonOfficialNameMatches để trích xuất các biểu thức name => ... ra thành một phương pháp riêng biệt, để nó có thể được tái sử dụng bởi các truy vấn khác. Dưới đây là một ví dụ tôi đã cố gắng, mà không hoạt động và ném ngoại lệ "The parameter 'place' was not bound in the specified LINQ to Entities query expression. ':

private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term) 
{ 
    return place => place.Names.AsQueryable().AsExpandable() 
     .Any(PlaceNameMatches(term)); 
} 

public static Expression<Func<PlaceName, bool>> PlaceNameMatches(string term) 
{ 
    var currentLanguage = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName; 
    return name => 
      name.TranslationToLanguage != null 
      && 
      name.TranslationToLanguage.TwoLetterIsoCode == currentLanguage 
      && 
      (
       name.Text.StartsWith(term) 
       || 
       (
        name.AsciiEquivalent != null 
        && 
        name.AsciiEquivalent.StartsWith(term) 
       ) 
      ); 
} 

Khi tôi không có chuỗi .AsExpandable() trong NonOfficialNameMatches, sau đó tôi nhận được' Internal .NET Framework Data Provider error 1025." ngoại lệ.

Tôi đã theo dõi other advice here chẳng hạn như một số kết hợp gọi .Expand() trên các vị từ, nhưng luôn luôn kết thúc bằng một trong các ngoại lệ nói trên.

Thậm chí có thể đưa ra biểu thức này thành một phương pháp riêng biệt bằng cách sử dụng LINQ to Entities với LinqKit/PredicateBuilder không? Nếu có, làm thế nào? Tôi đang làm gì sai?

Trả lời

7

phương pháp dưới đây sẽ làm việc:

private static Expression<Func<Place, bool>> NonOfficialNameMatches(string term) 
{ 
    Expression<Func<PlaceName, bool>> placeNameExpr = PlaceNameMatches(term); 
    Expression<Func<Place, bool>> placeExpr = 
     place => place.Names.Any(name => placeNameExpr.Invoke(name)); 
    return placeExpr.Expand(); 
} 

EDIT: Thêm giải trình bổ sung

Phương pháp PlaceNameMatches làm việc như bạn đã viết nó. Các vấn đề của bạn là cách bạn sử dụng phương pháp. Nếu bạn muốn đưa ra các phần của một biểu thức, hãy làm theo 3 bước tôi đã làm trong phương thức trên.

  1. Đặt biến cục bộ thành biểu thức được tạo bởi phương thức.

  2. Đặt biến cục bộ khác thành biểu thức mới Gọi biểu thức biến cục bộ.

  3. Gọi LinkKit Expand phương pháp: điều này sẽ mở rộng bất kỳ biểu thức Viện dẫn

+0

+100, cảm ơn bạn tôi đã bắt đầu nghĩ câu hỏi này sẽ không bao giờ được trả lời. Lời giải thích bổ sung cũng giúp ích. – danludwig

Các vấn đề liên quan