Question

J'ai la requête LINQ suivante:

var aKeyword = "ACT";
var results = from a in db.Activities
              where a.Keywords.Split(',').Contains(aKeyword) == true
              select a;

Mots-clés est un champ délimité par des virgules.

Chaque fois que je lance cette requête, je reçois l'erreur suivante:

"LINQ to Entities ne reconnaît pas la méthode 'Boolean Contient [chaîne] (System.Collections.Generic.IEnumerable`1 [System.String], System.String)' méthode, et cette méthode ne peut pas être traduit dans une expression de magasin. "

Quelle est l'alternative pour ce que je suis en train de faire?

Était-ce utile?

La solution

En réponse à vos considérations de performance sur un grand ensemble de données:

Vous allez faire de correspondant chaîne de caractères génériques non indexé sur le client, donc oui, il y aura perte de performance.

Y at-il une raison pour laquelle vous avez plusieurs mots-clés dans un champ de table? Vous pouvez normaliser que sur, d'avoir une table ActivityKeywords où pour chaque activité que vous avez un certain nombre de mots-clés enregistrements.

Activités (activity_id, ... / * Supprimer le champ des mots-clés * /) ---> ActivityKeywords (activity_id, keyword_id) ---> Mots-clés (keyword_id, valeur)

Consultez la forme non-première normal: http://en.wikipedia.org/wiki/Database_normalization

EDIT: Aussi, même si vous deviez tenir à une colonne, il y a une façon de faire tout Serverside (si vous avez une syntaxe stricte: « keyword1, keyword2, ..., keywordN »):

var aKeyword = "ACT";
var results = (from a in db.Activities
              where a.Keywords.Contains("," + aKeyword) || a.Keywords.Contains(aKeyword + ",")
              select a;

Autres conseils

Votre problème est que LINQ à traduire doit Entités mises tout ce que vous donnez dans SQL pour envoyer à la base de données.

Si tel est vraiment ce que vous devez faire, vous devrez forcer LINQ à entités à retirer toutes les données et LINQ à objets pour évaluer l'état.

Ex:

var aKeyword = "ACT";
var results = from a in db.Activities.ToList()
              where a.Keywords.Split(',').Contains(aKeyword) == true
              select a;

Sachez cependant, que cela va retirer tous les objets de la table Activités. Une autre solution peut être de laisser le DB faire un peu d'un filtre initial, et filtrer sur le reste du chemin après:

var aKeyword = "ACT";
var results = (from a in db.Activities
              where a.Keywords.Contains(aKeyword)
              select a).ToList().Where(a => a.KeyWords.Split(',').Contains(aKeyword));

Cela permettra LINQ à entités ne le filtre, il comprend (string.Contains devient une requête comme) qui filtrera vers le bas certaines des données, puis appliquer le filtre réel que vous voulez via LINQ-à-objets une fois que vous avez les objets en arrière. Les ToList () des forces d'appels LINQ à entités pour exécuter la requête et mettre en place les objets, ce qui permet LINQ-to-objets à la machine qui fait la seconde partie de la requête.

Je suppose la façon dont vous appelez Split. Il devrait prendre un tableau. Peut-être il y a un autre Split en Linq il est de trouver et de vous donner une erreur inhabituelle:

Cela fonctionne pour LINQ to Objects:

 var dataStore = new List<string>
                    {
                        "foo,bar,zoo",
                        "yelp,foo",
                        "fred",
                        ""
                    };
 var results = from a in dataStore
               where a.Split(new[] {','}).Contains("foo")
               select a;

 foreach (var result in results)
 {
     Console.WriteLine("Match: {0}", result);
 }

Sorties les éléments suivants:

Match: foo,bar,zoo
Match: yelp,foo

En fait, penser, avez-vous besoin de la scission du tout? a.Contains("foo") peut être suffisant pour vous (à moins que vous ne voulez pas frapper foobar).

Vous pouvez regarder cette question sur L2E et .Contains une solution qui devrait être plus efficace que deviner un surensemble avant de filtrer côté client.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top