6

Próbowałem przekształcić wyrażenie LINQ w metodę i pracowałem zarówno nad wyjątkami "Internal .NET Framework Data Provider error 1025." i "".Nie można naprawić za pomocą LINQ do jednostek i LinqKit/PredicateBuilder

Oto odpowiednie części modelu jednostki (przy użyciu EF 4.2/LINQ do podmiotów):

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

Podstawowy model relacyjny jest taka:

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

Próbuję utworzyć zapytanie, które po uzyskaniu wyniku wyszukiwania term, spróbuje znaleźć Place podmiotów, których OfficialName rozpoczyna się od OR, który ma PlaceName, którego którego zaczyna się od wyszukiwania term. (Language nie jest, gdy mam problemy, choć jest częścią zapytania, ponieważ PlaceName s powinien odpowiadać tylko za CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName.)

Poniższy kod działa:

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

Co staram się zrobić dalej jest refactor NonOfficialNameMatches metoda wyodrębnić wyrażenie name => ... na osobną metodę, dzięki czemu może być ponownie wykorzystane przez inne zapytania. Oto jeden z przykładów próbowałem, który nie działa i zgłasza wyjątek „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) 
       ) 
      ); 
} 

Kiedy nie mam łańcuch .AsExpandable() w NonOfficialNameMatches, a następnie uzyskać»Internal .NET Framework Data Provider error 1025.” wyjątek.

Śledziłem other advice here, takie jak kilka kombinacji wywoływania .Expand() na predykatach, ale zawsze kończy się jednym z wyżej wymienionych wyjątków.

Czy można nawet wyodrębnić to wyrażenie w osobnej metodzie, używając LINQ do jednostek z LinqKit/PredicateBuilder? Jeśli tak, w jaki sposób? Co ja robię źle?

Odpowiedz

7

Poniższa metoda powinna działać:

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: Dodawanie dodatkowych wyjaśnień

PlaceNameMatches metoda działa, jak to napisał. Twoje problemy dotyczyły sposobu użycia tej metody. Jeśli chcesz odfiltrować części wyrażenia, wykonaj 3 kroki, które zrobiłem w powyższej metodzie.

  1. Ustawienie zmiennej lokalnej na wyrażenie utworzone za pomocą metody.

  2. Ustaw inną zmienną lokalną na nowe wyrażenie wywołujące wyrażenie zmiennej lokalnej.

  3. Wywołać LinkKit Expand metoda: będzie rozwijać żadnej wywołany wyrażenia

+0

+100, dziękuję Zaczęłam myśleć, że to pytanie nie dostanie odpowiedzi. Dodatkowe wyjaśnienie też pomaga. – danludwig

Powiązane problemy