"A Lambda Expression with a Statement Body Cannot Be Converted to an Expression Tree"

A lambda expression with a statement body cannot be converted to an expression tree(Lambda and Linq)

The error message is quite clear: you have a lambda expression with a statement body, and that simply cannot be converted to an expression tree (at least not automatically by the compiler). Because of that, your linq provider cannot create a query from it to send to the database (and even if you created the expression tree manually, which is not trivial, your linq provider would not be able to convert it to a SQL query).

You have two options. Option one is to rewrite your query such that it does not contain a statement body, as others have shown.

The other option is to execute part of the query in memory, using linq to objects. You have to be careful with this approach, and avoid getting too much data from the database. But the way to do it would be:

IEnumerable<IGrouping<int, AnimalFood>> animalFoods = 
db.AnimalFoods.GroupBy(x => x.FoodId).AsEnumerable();
IEnumerable<FoodSummaryViewModel> foodSummaryViewModel = animalFoods.Select(g =>
{
var animalFood = g.FirstOrDefault();
return new FoodSummaryViewModel()
{
FoodName = animalFood.Food.FoodName,
FoodPrice = animalFood.Food.UnitPrice,
TotalFoodQuantity = g.Sum(x => x.Animal.AnimalQuantity * x.FoodQuantity),
TotalPrice = g.Sum(x => x.Animal.AnimalQuantity * x.FoodQuantity) * animalFood.Food.UnitPrice
};
});
return foodSummaryViewModel.ToList();

That may give you what you think you want, but it may not be a good idea though. Your selector is using the AnimalFood.Animal.AnimalQuatity property chain, and that may cause lazy loading, depending on your Linq provider. And if you have configured it to use eager loading, you may not be better of, because you may be loading way too much data.

So you probably would be better of rewriting your query. Are you sure something like this doesn't do the job:

var q = from food in db.Foods
select new FoodSummaryViewModel
{
FoodName = food.FoodName,
FoodPrice = food.UnitPrice,
TotalFoodQuantity = (from fa in food.AnimalFoods
select fa.Animal.AnimalQuantity).Sum() * food.FoodQuantity
TotalPrice = (from fa in food.AnimalFoods
select fa.Animal.AnimalQuantity).Sum() * food.FoodQuantity * food.UnitPrice
};
return q.ToList();

Lambda expression with statement body error in previously working code

Amend: The GroupBy extension method you are using takes an expression lambda as it's second parameter. Your lambda contains a { return ... } statement that can't be translated into an Expression tree. Please see CS0834.

You could avoid this error by writing:

var gruppedList = pln
.GroupBy(i => i.ItemID)
.Select(g => new tabStockPlanner { ItemID = g.key, ExpectedYieldInTonnes = g.Sum(i => i.ExpectedYieldInTonnes) })
.OrderByDescending(t => t.ExpectedYieldInTonnes)
.ToList();

I like to use the overload of GroupBy that only takes keySelector (without the element selector). This way the LINQ pipeline becomes more readable in my opinion as each function has a single task.

Hope it helps you

A lambda expression with a statement body cannot be converted to an expression tree in nopCommerce

The error message is exactly what it says. You have a lambda expression. It has a statement body. A lambda expression with a statement body can not be converted to an expression tree. But Join requires an expression tree to use with EF. You should try replacing what you have with a lambda expression that doesn't have a body like:

(cev, c) => new CustomerEventRolesModel {
Id = cev.Id,
CustomerId = c.Id
}

And so on.

By the way,

ContactName = c.GetAttribute<string>(SystemCustomerAttributeNames.FirstName)

will NOT work with EF. Period. You better figure something else out.

Lambda Expression with a statement body can not been converted

You are doing a query to Entity Framework or LINQ2SQL:

decimal currentTotal = 0;

var query = test
.OrderBy(i => i.Date)
.Select(i => new
{
Date = i.Date,
Amount = i.Amount
})

// Above lines executed on SQL
.AsEnumerable()
// Below lines executed locally

.Select(i =>
{
currentTotal += i.Amount;
return new
{
Date = i.Date,
Amount = i.Amount,
RunningTotal = currentTotal
};
}
);

You can't execute your add to currentTotal on the SQL Server, so you use AsEnumerable() to execute it locally.

Explanation:

When you program with EF/LINQ2SQL, the query you build with IQueryable<T> is translated in the SQL language and executed on the SQL Server. So the .OrderBy() becomes a ORDER BY, all the .Where() become a WHERE and so on. Clearly if in the LINQ query you put something that can't be translated to SQL, then you get an exception when the query is translated. Now, there are two problems in your query.

For some limitations of C#, only expressions written without { ... } blocks (and some other limitations... no if, no return, ...) can be translated to Expression<Func<>>. For this reason your program can't be compiled.

Even if it was possible to compile it directly, the SQL Server doesn't know anything of your currentTotal variable, so you would get a NotSupportedException at runtime.

The solution: you create a "legal" query with only the pieces that can be executed by SQL... You .Select() the columns you'll need. Then with .AsEnumerable() you tell the EF that from the .AsEnumerable() onward it mustn't translate the query to SQL, and must execute the query "locally". So the .OrderBy() and the first .Select() will be executed SQL-side, while the second .Select() (with the currentTotal) will be executed locally.

A lambda expression with a statement body cannot be converted to an expression tree

Expression trees were originally created for LINQ, which is about queries. Queries are generally function-based, so single-expression lambdas fit really well, without needing to worry about control flow within the expression tree etc. I suspect that translating expression trees for arbitrary statement lambdas into SQL etc would be a fool's errand.

Expression trees were later enhanced for .NET 4 (largely for the sake of the DLR, I believe) but the C# 4 compiler doesn't actually need to create complicated expression trees from lambda expressions for that - so it's mostly that there just isn't enough benefit for it to be worth it.

To put it another way: what's your use case that would justify the probably-large amount of effort which it would take to include it? Maybe there is such a use case, and maybe in a future version of C# the team will decide it's worth it. But for the moment, being able to convert expression lambdas into expression trees has a clear benefit - but the extra effort of doing the same for statement lambdas doesn't have a corresponding benefit.

EDIT: There's absolutely no reason why the C# compiler would need to have an expression tree representation of code (in terms of System.Linq.Expressions), but it will have an abstract syntax tree.

I suspect what you really want is Roslyn - it's still in CTP, but it's basically a compiler API. The Roslyn AST isn't designed to be used in the same scenarios as expression trees, but if you're interested in compiler transformations, it may well still be what you want.



Related Topics



Leave a reply



Submit