我在舊的物體框架(.NET 框架)中有以下查詢:
db.ProductVariations
.Where(pv => pv.Product.Categories
.Any(cat => categorySearchStrings
.Any(categorySearchString => cat.SearchTree.StartsWith(categorySearchString))));
我意識到這并不漂亮,但我正在重構一個遺留應用程式,我們必須選擇我們的戰斗。
因此,您可以傳遞一個搜索字串串列 (the categorySearchStrings),例如:
"38.54.", "45."
這基本上是一個搜索樹的實作,其中我們資料庫中的每個類別都有一個SearchTree屬性。因此,具有搜索樹的類別38.54.99會匹配,但38.不會匹配。
一個產品可以有多個類別,我們可以將多個搜索樹字串傳遞給查詢。所以我們正在比較兩個集合。
這被翻譯成
SELECT
[GroupBy1].[A1] AS [C1]
FROM ( SELECT
COUNT(1) AS [A1]
FROM [dbo].[ProductVariation] AS [Extent1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM ( SELECT
[Extent3].[SearchTree] AS [SearchTree]
FROM [dbo].[ProductCategory] AS [Extent2]
INNER JOIN [dbo].[Category] AS [Extent3] ON [Extent2].[CategoryId] = [Extent3].[Id]
WHERE [Extent1].[ProductId] = [Extent2].[ProductId]
) AS [Project1]
WHERE EXISTS (SELECT
1 AS [C1]
FROM ( SELECT 1 AS X ) AS [SingleRowTable1]
WHERE ( CAST(CHARINDEX(N'38.', [Project1].[SearchTree]) AS int)) = 1
)
)
) AS [GroupBy1]
我正在嘗試遷移到 Entity Framework Core(6,在 .NET 6 上運行),但這現在給了我以下錯誤:
System.InvalidOperationException : The LINQ expression 'categorySearchString => categorySearchString == "" || EntityShaperExpression:
Company.Data.Models.Category
ValueBufferExpression:
ProjectionBindingExpression: Inner
IsNullable: False
.SearchTree != null && categorySearchString != null && EntityShaperExpression:
Company.Data.Models.Category
ValueBufferExpression:
ProjectionBindingExpression: Inner
IsNullable: False
.SearchTree.StartsWith(categorySearchString)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
我認為切換到客戶評估并不是一個真正的選擇,因為要檢索的資料太多。另外,除了這個 Where 子句之外,還有更多的事情要做。我簡化了它。
我也嘗試將其重寫為:
.Where(pv => pv.Product.Categories.Select(c => c.SearchTree).Any(st => categorySearchStrings.Any(ss => st.StartsWith(ss))));
但我只是得到同樣的錯誤。
是否可以使用 EF Core 執行此操作?
uj5u.com熱心網友回復:
我傾向于構建一個動態運算式樹來表示過濾器:
var cat = Expression.Parameter(typeof(Category), "cat");
var parts = new List<Expression>(categorySearchStrings.Count);
var startsWithMethod = typeof(string).GetMethod(nameof(string.StartsWith), new[] { typeof(string) });
foreach (string categorySearchString in categorySearchStrings)
{
var searchTree = Expression.Property(cat, nameof(Category.SearchTree));
var value = Expression.Constant(categorySearchString);
var startsWith = Expression.Call(searchTree, startsWithMethod, value);
parts.Add(startsWith);
}
var body = parts.Aggregate(Expression.OrElse);
var categoryFilter = Expression.Lambda<Func<Category, bool>>(body, cat);
var pv = Expression.Parameter(typeof(ProductVariation), "pv");
var product = Expression.Property(pv, nameof(ProductVariation.Product));
var categories = Expression.Property(product, nameof(Product.Categories));
var any = Expression.Call(typeof(Enumerable), nameof(Enumerable.Any), new[] { typeof(Category) }, categories, categoryFilter);
var finalFilter = Expression.Lambda<Func<ProductVariation, bool>>(any, pv);
db.ProductVariations
.Where(finalFilter)
...
您還應該在 efcore 存盤庫中將此問題報告為問題,以查看它是否可以在未來版本中修復。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/414419.html
標籤:
