简体   繁体   中英

EF Core 3.1 Sum of owned object's properties is failing

It worked in 2.1 but started failing on 3.1

System.InvalidCastException: 'Unable to cast object of type 'System.Linq.Expressions.NewExpression' to type 'System.Linq.Expressions.MethodCallExpression'.'
var ordersCounts = await ordersCountsQuery 
       .Select(x => new TransactionDTO
       {
            Value = new MoneyDTO(ordersCountsQuery.Sum(a => a.TotalPrice.Amount)) // worked perfectly on 2.1
       })
       .FirstOrDefaultAsync();

a.TotalPrice.Amount is decimal on Sql server database

In EF Core 2.1 I have set it up

.ConfigureWarnings(warnings => warnings.Throw(RelationalEventId.QueryClientEvaluationWarning))

It looks like you may be hitting this breaking change between 2.2 and 3.0 versions of the entity framework:

https://docs.microsoft.com/en-us/ef/core/what-is-new/ef-core-3.0/breaking-changes#linq-queries-are-no-longer-evaluated-on-the-client

Old behavior

Before 3.0, when EF Core couldn't convert an expression that was part of a query to either SQL or a parameter, it automatically evaluated the expression on the client. By default, client evaluation of potentially expensive expressions only triggered a warning.

New behavior

Starting with 3.0, EF Core only allows expressions in the top-level projection (the last Select() call in the query) to be evaluated on the client. When expressions in any other part of the query can't be converted to either SQL or a parameter, an exception is thrown.

If this is the case, you'll have to re-write your query to suit (this may have to be two separate queries).


I would note that your query seems to be a bit strangely structured:

var ordersCounts = await ordersCountsQuery 
   .Select(x => new TransactionDTO
   {
        Value = new MoneyDTO(ordersCountsQuery.Sum(a => a.TotalPrice.Amount)) // worked perfectly on 2.1
   })
   .FirstOrDefaultAsync();

Get a list of MoneyDTO (one for every item in the query), each one containing the sum of the total list and select the first.

The following would do the same and likely be slightly more performant (only returning a single value:

var totalPrice = ordersCountsQuery.Sum(a => a.TotalPrice.Amount);

var orderCounts = new TransactionDTO
{
    Value = new MoneyDTO(totalPrice) 
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM