En utilisant EntityFramework , j'obtiens l'erreur " A lambda expression with a statement body cannot be converted to an expression tree
" en essayant de compiler le code suivant:
Obj[] myArray = objects.Select(o =>
{
var someLocalVar = o.someVar;
return new Obj() {
Var1 = someLocalVar,
Var2 = o.var2 };
}).ToArray();
Je ne sais pas ce que signifie l'erreur et surtout comment y remédier. De l'aide?
c#
linq
entity-framework
linq-to-entities
pistache
la source
la source
Réponses:
Un
objects
contexte de base de données Linq-To-SQL? Dans ce cas, vous ne pouvez utiliser que des expressions simples à droite de l'opérateur =>. La raison en est que ces expressions ne sont pas exécutées, mais sont converties en SQL pour être exécutées sur la base de données. Essaye çaArr[] myArray = objects.Select(o => new Obj() { Var1 = o.someVar, Var2 = o.var2 }).ToArray();
la source
Vous pouvez utiliser le corps de l'instruction dans l'expression lamba pour les collections IEnumerable . essaye celui-là:
Obj[] myArray = objects.AsEnumerable().Select(o => { var someLocalVar = o.someVar; return new Obj() { Var1 = someLocalVar, Var2 = o.var2 }; }).ToArray();
Remarque:
réfléchissez bien lorsque vous utilisez cette méthode, car de cette façon, vous aurez tous les résultats de la requête en mémoire, ce qui peut avoir des effets secondaires indésirables sur le reste de votre code.
la source
AsEnumerable()
masques mon problème disparaît!Cela signifie que vous ne pouvez pas utiliser d'expressions lambda avec un "corps de déclaration" (c'est-à-dire des expressions lambda qui utilisent des accolades) aux endroits où l'expression lambda doit être convertie en un arbre d'expression (ce qui est par exemple le cas lors de l'utilisation de linq2sql) .
la source
Sans en savoir plus sur ce que vous faites (Linq2Objects, Linq2Entities, Linq2Sql?), Cela devrait le faire fonctionner:
Arr[] myArray = objects.AsEnumerable().Select(o => { var someLocalVar = o.someVar; return new Obj() { Var1 = someLocalVar, Var2 = o.var2 }; }).ToArray();
la source
.AsEnumerable()
L'objet de retour LINQ to SQL implémentait l'
IQueryable
interface. Donc, pour leSelect
paramètre de prédicat de méthode, vous ne devez fournir qu'une seule expression lambda sans corps.En effet, le code LINQ pour SQL n'est pas exécuté à l'intérieur du programme plutôt que du côté distant comme le serveur SQL ou d'autres. Ce type d'exécution de chargement paresseux a été obtenu en implémentant IQueryable où son délégué expect est encapsulé dans la classe de type Expression comme ci-dessous.
L'arbre d'expression ne prend pas en charge l'expression lambda avec body et sa seule prend en charge l'expression lambda sur une seule ligne comme
var id = cols.Select( col => col.id );
Donc, si vous essayez le code suivant ne fonctionnera pas.
Expression<Func<int,int>> function = x => { return x * 2; }
Ce qui suit fonctionnera comme prévu.
Expression<Func<int,int>> function = x => x * 2;
la source
Utilisez cette surcharge de select:
Obj[] myArray = objects.Select(new Func<Obj,Obj>( o => { var someLocalVar = o.someVar; return new Obj() { Var1 = someLocalVar, Var2 = o.var2 }; })).ToArray();
la source
Expression<Func<Obj,Obj>>
.Cela signifie qu'une expression Lambda de type
TDelegate
qui contient un([parameters]) => { some code };
ne peut pas être convertie en unExpression<TDelegate>
. C'est la règle.Simplifiez votre requête. Celui que vous avez fourni peut être réécrit comme suit et compilera:
Arr[] myArray = objects.Select(o => new Obj() { Var1 = o.someVar, Var2 = o.var2 } ).ToArray();
la source
9 ans trop tard pour la fête, mais une approche différente de votre problème (que personne n'a évoqué?):
Le corps de l'instruction fonctionne bien avec
Func<>
mais ne fonctionnera pas avecExpression<Func<>>
.IQueryable.Select
veut unExpression<>
, car ils peuvent être traduits pour Entity Framework -Func<>
ne peut pas.Donc, soit vous utilisez le
AsEnumerable
et commencez à travailler avec les données en mémoire (non recommandé, sinon vraiment nécessaire), soit vous continuez à travailler avec ceIQueryable<>
qui est recommandé. Il y a quelque choselinq query
qui s'appelle qui facilite certaines choses:IQueryable<Obj> result = from o in objects let someLocalVar = o.someVar select new Obj { Var1 = someLocalVar, Var2 = o.var2 };
avec
let
vous pouvez définir une variable et l'utiliser dans leselect
(ouwhere
, ...) - et vous continuez à travailler avec leIQueryable
jusqu'à ce que vous ayez vraiment besoin d'exécuter et d'obtenir les objets.Ensuite, vous pouvez
Obj[] myArray = result.ToArray()
la source
Un
Arr
type de base est-ilObj
? La classe Obj existe-t-elle? Votre code ne fonctionnerait que si Arr est un type de base d'Obj. Vous pouvez essayer ceci à la place:Obj[] myArray = objects.Select(o => { var someLocalVar = o.someVar; return new Obj() { Var1 = someLocalVar, Var2 = o.var2 }; }).ToArray();
la source
Pour votre cas particulier, le corps est pour créer une variable, et le passage à
IEnumerable
forcera toutes les opérations à être traitées côté client, je propose la solution suivante.Obj[] myArray = objects .Select(o => new { SomeLocalVar = o.someVar, // You can even use any LINQ statement here Info = o, }).Select(o => new Obj() { Var1 = o.SomeLocalVar, Var2 = o.Info.var2, Var3 = o.SomeLocalVar.SubValue1, Var4 = o.SomeLocalVar.SubValue2, }).ToArray();
Edit: Renommer pour la convention de codage C #
la source