2016-07-11 16 views
0

Ich habe folgendes Problem, das ich nicht meinen Kopf um stundenlang eingewickelt bekommen:Generisches LINQ-Erweiterung auf dynamische Navigation Eigenschaft

ich mehrere Instanzen haben, die ich filtern möchten. Sie alle haben eine Navigationseigenschaft des Typs Person gemeinsam - obwohl es in all diesen Entitäten nicht gleich genannt wird.

Die Person Entity hat eine Liste der CompanyRelation -Instances, das, was Relation besagt die Person zu einem Gesellschaft hat

public class Person 
{ 
    public Collection<CompanyRelation> CompanyRelations { get; set; } 
} 

public enum CompanyRelationType 
{ 
    Employee, 
    Manager 
} 

public class Contract 
{ 
    public Person ContractCreator { get; set; } 
} 

public class CompanyRelation 
{ 
    public virtual Guid PersonId { get; set; } 

    public virtual Person Person { get; set; } 

    public virtual Guid CompanyId { get; set; } 

    public virtual Company Company { get; set; } 

    public virtual CompanyRelationType RelationType { get; set; } 
} 

ich jetzt eine allgemeine LINQ schreiben wollen Erweiterung, die für jede Entity-Collection verwendet werden kann und den Pfad zur Navigationseigenschaft und einige statische Filterparameter übernimmt. Da die Entities ich Abfrage auf keine gemeinsame Basis, die LINQ-Erweiterung auf Typ T. generic ist

Inzwischen kam ich mit so etwas wie dies oben:

public static IQueryable<T> HasRelation<T>(this IQueryable<T> query, Expression<Func<T, Person>> personExpr, Guid companyId, CompanyRelationType relationType) 
    { 
     return query = query.Where(tc => tc.ContractCreator.CompanyRelations.Any(cr => cr.CompanyId == companyId));    
    } 

Das offensichtliche Problem hier ist, dass ich nicht Habe eine Eigenschaft "ContractCreator" im generischen Kontext vom Typ T.

Die Frage ist jetzt: Wie kann ich den personExpr, in dem ich den Pfad der Navigationseigenschaft definiere, in ein Formular transformieren, auf das ich meine Filterabfrage schreiben kann und funktioniert immer noch mit LINQ to SQL.

Ich versuchte es auch als Lambda, die ich mit tc aufgerufen, aber da invoke wird nicht von LINQ to SQL, dass hat nicht funktioniert entweder unterstützt:

public static IQueryable<T> HasRelation<T>(this IQueryable<T> query, Func<T, Person> personExpr, Guid companyId, CompanyRelationType relationType) 
    { 
     return query = query.Where(tc => personExpr(tc).CompanyRelations.Any(cr => cr.CompanyId == companyId));    
    } 

Der Vollständigkeit halber und vielleicht zum besseren Verständnis hier So nenn ich die Nebenstelle:

Guid companyId = ... //Some Company's Id 

var result = this.unitOfWork.Contracts  .HasAnyRelation(c => c.ContractCreator, companyId, CompanyRelationType.Employee); 

Ich freue mich wirklich auf deine Antworten!

+0

Sind Sie für 3rd-Party-Bibliotheken öffnen oder Sie wollen eine lokale Lösung? –

+0

Solange die 3rd-Party-Lib für kommerzielle Zwecke frei ist und die lokale Lösung wesentlich verbessert, würde ich es in Betracht ziehen. Ich habe LinqKit bereits integriert, wenn dies hilfreich ist. – angrybobcat

+0

Es hilft auf jeden Fall :) –

Antwort

1

können Sie LinqKitAsExpandable und Invoke Erweiterungsmethoden wie folgt verwenden:

public static IQueryable<T> HasRelation<T>(this IQueryable<T> query, Expression<Func<T, Person>> personExpr, Guid companyId, CompanyRelationType relationType) 
{ 
    return query.AsExpandable().Where(tc => 
     personExpr.Invoke(tc).CompanyRelations.Any(cr => cr.CompanyId == companyId));    
} 
+0

Vielen Dank für Ihre Antwort! Ich habe zuerst die Lösung vor deinem Edit to Expression ausprobiert, habe es aber schon herausgefunden :) – angrybobcat