2009-05-27 1 views
4

Ich habe das folgende Stück Code:Wie erstellt man einen LINQ-Ausdruck aus einer Entity Framework-Navigationseigenschaft?

Expression<Func<Subscription, Service>> service2= subscription => (from relationship in subscription.ChildRelationships 
    select relationship.SecondService).FirstOrDefault(); 

Es schafft einen Ausdruck, den ich später als Teil einer Abfrage mit dem Entity Framework verwenden kann. Der eigentliche Code, den ich benutze, hat eine where-Klausel, aber ich habe sie aus Gründen der Lesbarkeit weggelassen. Das funktioniert einwandfrei und ich kann es in LINQPad ausführen, das ich zum Testen verwende.

Wenn ich ändern Sie den Code an:

Expression<Func<Subscription, IQueryable<Service>>> service2= subscription => (from relationship in subscription.ChildRelationships 
    select relationship.SecondService); 

Es ist nicht mehr kompiliert und hat den folgenden Fehler:

Cannot convert lambda expression to delegate type 'System.Func<Farmworks.Data.Subscription,System.Linq.IQueryable<Farmworks.Data.Service>>' because some of the return types in the block are not implicitly convertible to the delegate return type

Es scheint, weil ChildRelationships zu sein, die eine Navigationseigenschaft ist nicht implementiert IQueryable. Es ist tatsächlich vom Typ EntityCollection, die IEnumerable implementiert, aber nicht zum Erstellen von Ausdrücken, die mit EF arbeiten.

Ich denke, ich verstehe, warum der zweite Block des Codes nicht funktioniert und möchte wissen, wie man es neu schreibt, so dass es tut. Was mich auch verwirrt, ist, warum der erste Code funktioniert. Es verwendet auch die ChildRelationships-Navigationseigenschaft, hat jedoch kein Problem, ein Ausdruck zu werden, der mit EF funktioniert.

Kann jemand Licht abgeben?

Antwort

0

Ich denke CompiledQuery Klasse, die Sie in diesem Fall helfen können:

Expression<Func<Subscription, IQueryable<Service>>> service2 = 
    CompiledQuery.Compile( 
     subscription => (
      from relationship in subscription.ChildRelationships 
      select relationship.SecondService 
     ) 
    ); 
1

Die Frage ist nicht, dass FirstOrDefault macht irgendwie die Expression Arbeit; Es ist, wie Sie sagen, dass ChildRelationships nicht selbst IQueryable implementiert. Sie können das auf zwei unterschiedliche Arten umgehen, abhängig von Ihren Bedürfnissen.

Sie können die IEnumerable.AsQueryable-Methode verwenden. Dies ist wahrscheinlich am besten, wenn die Dienste bereits aus dem Kontext geladen sind.

Wenn die Dienste nicht geladen sind, können Sie sie nach Bedarf mit den Lade- oder Einschlussmethoden laden und dann die obige Lösung verwenden.

Wenn Sie einen Verweis auf Ihre Object haben, können Sie die Object verwenden, die IQueryable nicht implementiert:

Expression<Func<Subscription, MyEntities, IQueryable<Service>>> service2 = 
    (subscription, context) => (
    from s in context.Subscriptions // here is the IQueryable 
    where s.Id == subscription.Id 
    from relationship in s.ChildRelationships 
    select relationship.SecondService); 
+0

den Code versucht, aber bekam die folgenden: Ein Ausdruck des Typs ‚Data.Service‘ wird in einer nachfolgenden von Klausel in einer Abfrage-Ausdruck mit Quellentyp ‚System.Data.Objects.DataClasses.EntityCollection '. Typinferenz fehlgeschlagen beim Aufruf von 'SelectMany'. – GiddyUpHorsey

+0

OK, mir ist klar, was die Typen hier sind. Ich werde meine Antwort umschreiben. –

0

Haben Sie es brauchen IQueryable < Service sein>? Ich denke, dass Select einen IEnumerable < Service> zurückgibt. LINQ arbeitet direkt auf IEnumerables, so dass Sie einfach service2 als Ausdruck < Func < Abonnement, IEnumerable < Service >>> deklarieren können.