我有以下查詢:
product = product.OrderByDescending(d => d.ProductAttributeItem
.Where(ai => ai.AttributeItem.AttributeId == (int)DefaultAttributes.Name)
.SelectMany(p => p.AttributeItem.AttributeItemValue)
.Any(o => EF.Functions.Like(o.Value, "%apple%") || EF.Functions.Like(o.Value, "%samsung%"))
這實際上作業得很好。product是一個相當復雜的查詢,其中包含許多基于輸入過濾器的謂詞。這里我們對Any()查詢的部分感興趣,特別是謂詞部分——如何EF.Functions.Like(o.Value, "%apple%") || EF.Functions.Like(o.Value, "%samsung%")動態生成。
我已經在我們的專案中使用了一些謂詞構建器擴展方法,它們非常適用于非嵌套情況,例如:
var condition = PredicateBuilder.True<AttributeItemValue>();
if(filters.OnlyActivated)
condition = condition.And(product => product.IsActive);
product = _context.Product.Where(condition);
所以我試圖在回圈中構建謂詞:
var aivCond = PredicateBuilder.True<AttributeItemValue>();
foreach (var s in searchQueryArray)
{
aivCond = aivCond.Or(f =>
EF.Functions.Like(f.Value, "%" s "%"));
}
所以現在aivCondis 是型別,Expression<Func<AttributItemValue, bool>但這不能用于替換 lambda inAny()因為它期望Func<TSource, bool>. 試圖以這種方式編譯它,aivCond.Compile()但出現以下錯誤:
System.ArgumentException: Expression of type 'System.Func`2[AttributeItemValue,System.Boolean]' cannot be used for parameter of type 'System.Linq.Expressions.Expression`1[System.Func`2[AttributeItemValue,System.Boolean]]' of method 'Boolean Any[AttributeItemValue](System.Linq.IQueryable`1[AttributeItemValue]
我還嘗試從字串構建 lambda 運算式:
var filter = "f => EF.Functions.Like(f.Value, \"%apple%\") || f => EF.Functions.Like(f.Value, \"%samsung%\")";
var options = ScriptOptions.Default
.AddReferences(typeof(AttributeItemValue).Assembly)
.AddReferences(typeof(Microsoft.EntityFrameworkCore.EF).Assembly)
.AddReferences(typeof(DbFunctions).Assembly)
.AddImports("Microsoft.EntityFrameworkCore");
Func<AttributeItemValue, bool> filterExpression = await CSharpScript.EvaluateAsync<Func<AttributeItemValue, bool>>(filter, options);
沒有運氣。
I know I missing knowledge for expression trees, compiling and invocation for delegates so any help(and explanation) would be really appreciated!
EDIT / SOLUTION
So there is a solution thanks to the help of Richard Deeming. He was right for starting the predicate with False. I stupidly copy/pasted code from a different method without noticing.
As about his second comment, adding AsQueryable() allows to pass an Expression<Func<TSource, bool>> which is pretty obvious but not for me. This translates fine and the compiler is ok.
Anyway, there is another approach, using LINQKit's AsExpandble() method and the inbuilt Compile() method in the Expression class and as described in LINQKit:
Compile is an inbuilt method in the Expression class. It converts the Expression<Func<Purchase,bool> into a plain Func<Purchase,bool> which satisfies the compiler. Of course, if this method actually ran, we'd end up with compiled IL code instead of an expression tree, and LINQ to SQL or Entity Framework would throw an exception. But here's the clever part: Compile never actually runs; nor does LINQ to SQL or Entity Framework ever get to see it. The call to Compile gets stripped out entirely by a special wrapper that was created by calling AsExpandable, and substituted for a correct expression tree.
So the code would look like this:
product = product.AsExpandable().OrderBy(d => d.ProductAttributeItem
.Where(ai => ai.AttributeItem.AttributeId == (int)DefaultAttributes.Name)
.SelectMany(p => p.AttributeItem.AttributeItemValue)
.Any(aivCond.Compile()));
Thank you everyone for the help and I hope this question helps somebody lost in the code... !
uj5u.com熱心網友回復:
正如在評論中提到的,你只需要使用該AsQueryable方法的集合中傳遞Expression<Func<TItem, bool>>的過濾器。
product = product.OrderByDescending(d => d.ProductAttributeItem
.Where(ai => ai.AttributeItem.AttributeId == (int)DefaultAttributes.Name)
.SelectMany(p => p.AttributeItem.AttributeItemValue)
.AsQueryable().Any(aivCond);
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/313317.html
標籤:c# entity-framework linq-to-entities predicatebuilder
上一篇:如何洗掉自參考物體?
