J'ai la méthode d'extension générique suivante:
public static T GetById<T>(this IQueryable<T> collection, Guid id)
where T : IEntity
{
Expression<Func<T, bool>> predicate = e => e.Id == id;
T entity;
// Allow reporting more descriptive error messages.
try
{
entity = collection.SingleOrDefault(predicate);
}
catch (Exception ex)
{
throw new InvalidOperationException(string.Format(
"There was an error retrieving an {0} with id {1}. {2}",
typeof(T).Name, id, ex.Message), ex);
}
if (entity == null)
{
throw new KeyNotFoundException(string.Format(
"{0} with id {1} was not found.",
typeof(T).Name, id));
}
return entity;
}
Malheureusement, Entity Framework ne sait pas comment gérer le predicate
puisque C # a converti le prédicat en ce qui suit:
e => ((IEntity)e).Id == id
Entity Framework lève l'exception suivante:
Impossible de convertir le type «IEntity» en «SomeEntity». LINQ to Entities prend uniquement en charge le cast de types primitifs ou énumération EDM.
Comment pouvons-nous faire fonctionner Entity Framework avec notre IEntity
interface?
Quelques explications supplémentaires concernant le
class
"correctif".Cette réponse montre deux expressions différentes, l'une avec et l'autre sans
where T: class
contrainte. Sans laclass
contrainte, nous avons:et avec la contrainte:
Ces deux expressions sont traitées différemment par le framework d'entité. En regardant les sources EF 6 , on peut constater que l'exception vient d' ici, voir
ValidateAndAdjustCastTypes()
.Ce qui se passe, c'est que EF essaie de
IEntity
convertir en quelque chose qui a du sens dans le monde du modèle de domaine, mais il échoue à le faire, par conséquent l'exception est levée.L'expression avec la
class
contrainte ne contient pas l'Convert()
opérateur, le cast n'est pas essayé et tout va bien.Il reste encore une question ouverte, pourquoi LINQ construit des expressions différentes? J'espère que certains assistants C # seront en mesure d'expliquer cela.
la source
Entity Framework ne prend pas en charge cela par défaut, mais un
ExpressionVisitor
qui traduit l'expression s'écrit facilement:La seule chose que vous devrez faire est de convertir le prédicat passé en utilisant l'expression visiteur comme suit:
Une autre approche - sans flexibilité - consiste à utiliser
DbSet<T>.Find
:la source
J'ai eu la même erreur mais un problème similaire mais différent. J'essayais de créer une fonction d'extension qui retournait IQueryable mais les critères de filtre étaient basés sur la classe de base.
J'ai finalement trouvé la solution qui était pour ma méthode d'extension d'appeler .Select (e => e comme T) où T est la classe enfant et e est la classe de base.
tous les détails sont ici: Créer l'extension IQueryable <T> à l'aide de la classe de base dans EF
la source