6

我一直在嘗試將LINQ表達式重構爲一個方法,並且已經遇到了「Internal .NET Framework Data Provider error 1025.」和「The parameter 'xyz' was not bound in the specified LINQ to Entities query expression.」異常。無法重構使用LINQ to Entities和LinqKit/PredicateBuilder

下面是實體模型的相關部分(使用EF 4.2/LINQ到實體):

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; } 
} 

基本關係模型是這樣的:

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

我想創建一個當給定搜索term時,將嘗試查找Place實體,其OfficialNameterm開頭或者具有PlaceName的實體,其TextAsciiEquivalent從搜索term開始。 (Language是不是在那裏我遇到了問題,但它是查詢的一部分,因爲PlaceName S的關係只匹配了CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName

下面的代碼確實工作

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) 
      ) 
     ) 
    ); 
} 

接下來我要做的是重構NonOfficialNameMatches方法,將name => ...表達式提取到一個單獨的方法中,以便它可以被其他查詢重用。下面是一個例子,我已經盡力了,這不起作用並拋出異常「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) 
       ) 
      ); 
} 

當我沒有.AsExpandable()NonOfficialNameMatches,然後我得到了’Internal .NET Framework Data Provider error 1025.」異常。

我跟着other advice here,例如在謂詞上調用.Expand()的幾種組合,但總是以上述例外之一結束。

甚至有可能將這個表達式分解成一個單獨的方法,使用LINQ to Entities和LinqKit/PredicateBuilder?如果是這樣,怎麼樣?我究竟做錯了什麼?

回答

7

下面的方法應該工作:

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(); 
} 

編輯:添加更多的解釋

PlaceNameMatches方法的工作原理,你寫的。你的問題在於你如何使用該方法。如果要分解表達式的部分,請按照上述方法中的3個步驟進行分解。

  1. 將局部變量設置爲由方法創建的表達式。

  2. 將另一個局部變量設置爲調用局部變量表達式的新表達式。

  3. 調用LinkKit Expand方法:這將擴大任何調用表達式

+0

+100,謝謝我開始覺得這個問題永遠不會得到回答。額外的解釋也有幫助。 – danludwig