6

Ich habe versucht, einen LINQ-Ausdruck in eine Methode zu refactor, und habe in beiden "Internal .NET Framework Data Provider error 1025." und "The parameter 'xyz' was not bound in the specified LINQ to Entities query expression." Ausnahmen ausgeführt.Kann nicht mit LINQ to Entities und LinqKit/PredicateBuilder refactoring

Hier sind die relevanten Teile des Entity-Modell (mit 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; } 
} 

Das grundlegende relationale Modell ist dies:

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

Ich versuche, eine zu schaffen Abfrage, die, wenn eine Suche term gegeben wird, versuchen, Place Einheiten zu finden, deren OfficialName beginnt mit der term ODER wer hat eine PlaceName wessen Text oder AsciiEquivalent beginnt mit der Suche term. (Language ist nicht, wo ich Probleme habe, obwohl es Teil der Abfrage ist, weil PlaceName s nur für die CultureInfo.CurrentUICulture.TwoLetterIsoLanguageName übereinstimmen sollte.)

Der folgende Code funktioniert:

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

Was ich als nächstes versuchen will, ist die NonOfficialNameMatches Methode umzuformen, um den name => ... Ausdruck in eine separate Methode zu extrahieren, so dass sie von anderen Abfragen wiederverwendet werden kann. Hier ist ein Beispiel, das ich versucht habe, die nicht funktioniert und wirft die Ausnahme „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) 
       ) 
      ); 
} 

Wenn ich nicht die .AsExpandable() Kette in NonOfficialNameMatches haben, dann erhalte ich die‘Internal .NET Framework Data Provider error 1025.“ Ausnahme.

Ich habe other advice here wie mehrere Kombinationen von Aufruf .Expand() auf die Prädikate gefolgt, aber immer mit einer der oben genannten Ausnahmen enden.

Ist es sogar möglich, diesen Ausdruck in eine separate Methode auszufiltern, die LINQ zu Entities mit LinqKit/PredicateBuilder verwendet? Wenn ja, wie? Was mache ich falsch?

Antwort

7

sollte das Verfahren unter arbeiten:

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: zusätzliche Erläuterungen Hinzufügen

Die PlaceNameMatches Methode funktioniert, wie Sie es geschrieben haben. Ihre Probleme bestanden darin, wie Sie die Methode verwendet haben. Wenn Sie Teile eines Ausdrucks ausklammern möchten, folgen Sie den 3 Schritten, die ich in der obigen Methode ausgeführt habe.

  1. Setzen Sie eine lokale Variable auf den von einer Methode erstellten Ausdruck.

  2. Eine weitere lokale Variable auf einen neuen Ausdruck setzen, der den Ausdruck der lokalen Variablen aufruft.

  3. Rufen Sie die LinkKit Expand Methode: dieses alle aufgerufen, erweitern Ausdrücke

+0

+100, danke ich begann diese Frage zu denken, würde nie beantwortet werden. Die zusätzliche Erklärung hilft auch. – danludwig

Verwandte Themen