c# - Expression Tree - Math.Max replacement -
when use expression trees replace method, such math.max, looks replaces in expression tree. when go use in entity framework, throws exception not supporting math.max entity framework. explicitly replacing it.
does know why? , way fix code?
using system; using system.collections.generic; using system.linq; using system.linq.expressions; namespace consoleapplication1 { public static class calculatedatabase { public static void main(string[] args) { var calcs = getcalculatetoamounts(gettestitems(), 0.5m).tolist(); } public static iqueryable<item> gettestitems() { var items = new list<item>(); items.add(new item() { donotitem = true, reductionamount = 2, previousdiscountamount = 3, currentdiscountamount = 10, currentamount = 100, previousamount = 50, currentbillamount = 75 }); return items.asqueryable(); } public class item { public bool donotitem { get; set; } public decimal reductionamount { get; set; } public decimal previousdiscountamount { get; set; } public decimal currentdiscountamount { get; set; } public decimal currentamount { get; set; } public decimal previousamount { get; set; } public decimal currentbillamount { get; set; } } public static iqueryable<calculatetoamount> getcalculatetoamounts(this iqueryable<item> entityitems, decimal percentage) { return entityitems.select(calculateamountexpression(percentage)); } public class calctype { } public class calculatetoamount { public calctype calctype { get; set; } public item item { get; set; } public decimal itemamount1 { get; set; } public decimal itemamount2 { get; set; } public decimal itemamount3 { get; set; } public decimal bonus { get; set; } public decimal discounts { get; set; } public decimal total { get; set; } } private static expression<func<item, calculatetoamount>> calculateamountexpression(this decimal percentage) { expression<func<item, calculatetoamount>> lambda = item => new calculatetoamount() { item = item, bonus = item.donotitem ? 0 : item.currentbillamount * (1 - percentage) + item.reductionamount, discounts = item.previousdiscountamount + item.currentdiscountamount, total = math.max(item.currentamount + item.previousamount, item.currentbillamount) }; var test = mathmodifier.modify(lambda); return test; } public class mathmodifier : expressionvisitor { protected override expression visitmethodcall(methodcallexpression node) { var isminmethod = node.method.name.equals("min", stringcomparison.invariantcultureignorecase); var ismaxmethod = node.method.name.equals("max", stringcomparison.invariantcultureignorecase); if (!isminmethod && !ismaxmethod) return base.visitmethodcall(node); var left = node.arguments[0]; var right = node.arguments[1]; var minmaxreplacemethod = isminmethod ? expression.condition(expression.lessthan(left, right), left, right) : expression.condition(expression.greaterthan(left, right), left, right); return minmaxreplacemethod; } public static expression<func<tin, tout>> modify<tin, tout>(expression<func<tin, tout>> expression) { var modifier = new mathmodifier(); return (expression<func<tin, tout>>)modifier.visit(expression); } } } }
if call
var calcs = getcalculatetoamounts(gettestitems(), 0.5).tolist()
it work. if replace above gettestitems() entity framework _dbcontext.items, not work.
to test code, need add item structure ef project, make migration, , push database.
i wish make less technical question answered wider variety of people. bounty adequate answer. if not, please pm me.
i running exactly provided code ef 6. entity item
named table1. code runs successfully, relpacement of math.max done.
tracing sql sql profiler generates , sends following sql against database:
exec sp_executesql n'select [extent1].[id] [id], [extent1].[donotitem] [donotitem], [extent1].[reductionamount] [reductionamount], [extent1].[previousdiscountamount] [previousdiscountamount], [extent1].[currentdiscountamount] [currentdiscountamount], [extent1].[currentamount] [currentamount], [extent1].[previousamount] [previousamount], [extent1].[currentbillamount] [currentbillamount], case when ([extent1].[donotitem] = 1) cast(0 decimal(18)) else ([extent1].[currentbillamount] * (cast(1 decimal(18)) - @p__linq__0)) + [extent1].[reductionamount] end [c1], [extent1].[previousdiscountamount] + [extent1].[currentdiscountamount] [c2], case when (([extent1].[currentamount] + [extent1].[previousamount]) > [extent1].[currentbillamount]) [extent1].[currentamount] + [extent1].[previousamount] else [extent1].[currentbillamount] end [c3] [dbo].[table1] [extent1]',n'@p__linq__0 decimal(1,1)',@p__linq__0=0.5
conclusion: code provided working, expression tree manipulation working, conditional logic in tree translated sql case expression.
possibly ef test not isolated enough , max.math related ef exception coming other part of code and/or indirectly fired event, overload etc.
Comments
Post a Comment