2015-03-23 6 views
10

Ich habe eine generische Methode zum Abfragen von Objekten des Typs TEntity in EF. Ich möchte eine Bedingung als where-Klausel hinzufügen, wenn TEntity eine bestimmte Schnittstelle implementiert. Die Methode, die ich habe, ist:Cast-Entity zu implementierten Schnittstelle in einer generischen Methode mit LINQ für Entity Framework

public TEntity GetByUserID(Guid userID) 
{ 
    var query = this.DbSet; 
    if (typeof (TEntity).IsImplementationOf<IDeletableEntity>()) 
    { 
     query = query 
      .Where((x => !((IDeletableEntity)x).IsDeleted); 
    } 
    return query 
     .FirstOrDefault(x => x.UserID == userID); 
} 

IsImplementationOf <>() ist Methode, die gerade wieder wahr/falsch, wie der Name schon sagt.

Als ich dies für die Entität Adresse ausgeführt, die IDeletableEntity implementieren, bekomme ich einen Fehler:

Unable to cast the type 'Address' to type 'IDeletableEntity'. LINQ to Entities only supports casting EDM primitive or enumeration types.

Irgendwelche Ideen, wie ich, um diese Einschränkung von LINQ gehen kann?

Antwort

-2

Ich denke, das Problem könnte die direkte Besetzung sein, die Sie in Ihrer Aussage tun, sowie Abfrage könnte Implementierung Aufzählungstypen und so IDeletable ist nicht als auf einer Entität implementiert.

LINQ-to-entities casting issue

vorgeschlagen, diese Lösung.

return query.ToList() 
         .Cast<IDeletable>() 
         .Where(e => e.Deleted) 
         .Cast<T>(); 
+0

Diese wird wahrscheinlich funktionieren, aber zuerst in die Datenbank gehen und alle Elemente holen, sie in eine Liste umwandeln und sie dann im Speicher filtern. Die gefundene Lösung sendet die Bedingung an die Datenbank, d. H. Sie erhalten nur die Elemente mit dem korrekten Flag-Wert. – Vladimir

+0

Nochmal, wie ich zu Vladimir gesagt habe, wie kann das funktionieren, es sei denn, ein IDeletable ist zu einem T castable – War

10

Dies ist eine Arbeitslösung:

public TEntity GetByUserID(Guid userID, params Include<TEntity>[] includes) 
{ 
    var query = this.DbSet; 
    query = Where<IDeletableEntity>(query, x => !x.IsDeleted); 
    return query 
     .FirstOrDefault(x => x.UserID == userID); 
} 

public static IQueryable<TEntity> Where<TPredicateWellKnownType>(IQueryable<TEntity> query, Expression<Func<TPredicateWellKnownType, bool>> predicate) 
{ 
    if (typeof(TEntity).IsImplementationOf<TPredicateWellKnownType>()) 
    { 
     query = ((IQueryable<TPredicateWellKnownType>)query) 
      .Where(predicate) 
      .Cast<TEntity>(); 
    } 
    return query; 
} 
+0

Das kann nicht funktionieren, wenn TPredicateWellKnownType nicht zu TEntity castbar ist ... weshalb ich eine Ausnahme zu diesem Effekt bekomme – War

+0

Absolute Genius! Das Problem, das ich hatte, bestand darin, die Syntax zu finden, die es dem Komponisten ermöglichte, das Casting zu verwalten, ohne zu versuchen, dieses Wissen an die SQL-Engine weiterzugeben, ohne den Abfragetyp zu ändern. Sehr elegante Lösung für etwas, das offensichtlich aussieht, wenn wir es für uns gemacht sehen, aber es schien zu hässlich, um es selbst zu versuchen. –

-1

Wenn alle DbSets die 'UserID' Eigenschaft hat dann eine andere Schnittstelle mit dem Namen erstellen 'IUserID' und dann diesen Code versuchen:

protected TEntity GetByUserID<TEntity>(Guid userID) where TEntity : class 
    { 
     var user = this.Set<TEntity>() 
      .ToList() 
      .Cast<IDeletableEntity>() 
      .Where(u => (!u.IsDeleted)) 
      .Cast<IUserID>() 
      .Where(u => (u.UserID == userID)) 
      .FirstOrDefault(); 
     return user; 
    } 
+1

Jetzt führen Sie die gesamte Operation im Speicher aus, und zwar in der Datenbank. – Servy

+0

@Servy Dies kann durch Entfernen der .ToList() - Methode gelöst werden, richtig? – Junior

+0

Sie müssen dann auch sicherstellen, dass der Rest des Codes ordnungsgemäß funktioniert, wenn sie von einem EF-Provider ausgeführt wird, aber ja, die 'ToList' wird den Code zwingen, alle im Speicher auszuführen. – Servy

Verwandte Themen