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

entity-framework linq

Question

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?

Réponse acceptée

On dirait que vous essayez de faire l'équivalent d'une condition "WHERE ... IN". Découvrez comment rédiger des requêtes de style 'WHERE IN' à l'aide de LINQ to Entities pour un exemple sur la façon d'effectuer 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 dans sa totalité comme une expression lambda.


Réponse populaire

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.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow