web-dev-qa-db-fra.com

Entity Framework - erreur "Impossible de créer une valeur constante de type 'Type de fermeture' ... ''

Pourquoi ai-je l'erreur?

Impossible de créer une valeur constante de type 'Type de fermeture'. Seuls les types primitifs (par exemple, Int32, String et Guid) sont pris en charge dans ce contexte.

Lorsque j'essaie d'énumérer la requête Linq suivante?

IEnumerable<string> searchList = GetSearchList();
using (HREntities entities = new HREntities())
{
   var myList = from person in entities.vSearchPeople
   where upperSearchList.All( (person.FirstName + person.LastName) .Contains).ToList();
}

Mise à jour: Si j'essaye ce qui suit pour essayer d'isoler le problème, j'obtiens la même erreur:

where upperSearchList.All(arg => arg == arg) 

On dirait donc que le problème vient de la méthode All, non? Aucune suggestion?

79
Gus Cavalcanti

On dirait que vous essayez de faire l'équivalent d'une condition "WHERE ... IN". Check out Comment écrire des requêtes de style 'WHERE IN' en utilisant LINQ to Entities pour obtenir un exemple sur la façon de faire ce type de requête avec LINQ to Entities.

De plus, je pense que le message d'erreur est particulièrement inutile dans ce cas car .Contains n'est pas suivi de parenthèses, ce qui amène le compilateur à reconnaître le prédicat entier en tant qu'expression lambda.

68
Daniel Pratt

J'ai passé les six derniers mois à lutter contre cette limitation avec EF 3.5 et bien que je ne sois pas la personne la plus intelligente au monde, je suis presque certaine d'avoir quelque chose d'utile à offrir sur ce sujet.

Le code SQL généré par la croissance d'une arborescence d'expressions "style OR", d'une hauteur de 50 km, se traduira par un plan d'exécution des requêtes médiocre. Je traite quelques millions de lignes et l'impact est considérable.

Il y a un petit bidouillage que j'ai trouvé pour faire un SQL 'in' qui aide si vous cherchez juste un tas d'entités par id:

private IEnumerable<Entity1> getByIds(IEnumerable<int> ids)
{
    string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray());
    return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}");
}

où pkIDColumn est le nom de colonne de votre clé primaire id de votre table Entity1.

MAIS GARDEZ LA LECTURE!

C'est bien, mais cela nécessite que je possède déjà les identifiants de ce que je dois trouver. Parfois, je veux juste que mes expressions touchent d’autres relations et ce que j’ai, ce sont des critères pour ces relations interconnectées.

Si j'avais plus de temps, j'essaierais de représenter cela visuellement, mais je ne vais pas simplement étudier cette phrase un instant: considérons un schéma avec des tables Person, GovernmentId et GovernmentIdType. Andrew Tappert (Person) a deux cartes d'identité (GovernmentId), une de l'Oregon (GovernmentIdType) et une de Washington (GovernmentIdType).

Générez maintenant un edmx à partir de celui-ci.

Maintenant, imaginez que vous vouliez trouver toutes les personnes ayant une certaine valeur d'identification, par exemple 1234567.

Ceci peut être accompli avec une seule base de données touchée avec ceci:

dbContext context = new dbContext();
string idValue = "1234567";
Expression<Func<Person,bool>> expr =
    person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue));

IEnumerable<Person> people = context.Person.AsQueryable().Where(expr);

Voyez-vous la sous-requête ici? Le SQL généré utilisera 'jointures' au lieu de sous-requêtes, mais l'effet est le même. De nos jours, SQL Server optimise les sous-requêtes en jointures, mais quand même ...

La clé de ce fonctionnement est le .Tout dans l’expression.

11
andrew

J'ai trouvé la cause de l'erreur (j'utilise Framework 4.5). Le problème est que EF, un type complexe, passé dans le paramètre "Contains", ne peut pas être traduit en requête SQL. EF ne peut utiliser dans une requête SQL que des types simples tels que int, string ...

this.GetAll().Where(p => !assignedFunctions.Contains(p))

GetAll fournit une liste d'objets de type complexe (par exemple, "Fonction"). Donc, par conséquent, j'essayerais ici de recevoir une instance de ce type complexe dans ma requête SQL, ce qui naturellement ne peut pas fonctionner!

Si je peux extraire de ma liste des paramètres adaptés à ma recherche, je peux utiliser:

var idList = assignedFunctions.Select(f => f.FunctionId);
this.GetAll().Where(p => !idList.Contains(p.FunktionId))

Maintenant, EF n'a plus le type complexe "Fonction" pour fonctionner, mais par exemple avec un type simple (long). Et ça marche bien!

8
peter70

J'ai reçu ce message d'erreur lorsque mon objet tableau utilisé dans la fonction .All est null. Après avoir initialisé l'objet tableau (upperSearchList dans votre cas), l'erreur a disparu. Le message d'erreur était trompeur dans ce cas.

où upperSearchList.All (arg => personne.someproperty.StartsWith (arg)))

0
ang