[英]Filtering for certain sub-types in EF-Core and TPT-inheritance in WebApi
我正在使用 EF-Core 並有一個類似的數據模型(只是一個動物的例子,以保持簡單)。 繼承通過 TPT(每種類型的表)映射到數據庫中。
public abstract class Animal { }
public class Monkey : Animal { }
public class Bear : Animal { }
public class Dog: Animal { }
在我的前端,我展示了所有的動物。 所以我創建了一個基本類型(抽象)的查詢並在前端顯示所有動物。 但現在我想通過查詢字符串添加一個過濾器,只顯示某種類型的動物(例如狗和猴子)。
這樣做的最佳做法是什么?
不幸的是,對於 TPT,我沒有鑒別器來過濾? 這是怎么做到的?
目前,我正在通過字符串數組在我的 WebApi-Conroller 中接收選定的類型,例如:
public IActionResult(string[] types) {
// ...
}
一個想法是將這個字符串數組映射到 Type,然后使用 .OfType。 但是我遇到了無法鏈接 OfType 的問題,因為鏈接時結果集始終為零。
直接在數據庫上進行過濾是完美的,所以出於性能原因,我想避免在內存中進行過濾。
有任何想法嗎?
實際上你不需要訪問鑒別器。 所有繼承模型(添加時的 TPH、TPT 和 TPC)都使用基於類型的查詢條件來過濾基本集。 OfType
只是其中之一,通常 C# 運算符is T
用於過濾, as T
或 cast (T)
用於訪問。
應用基於Type
的過濾器沒有開箱即用的方法,但可以使用Expression
類創建它 - C# 的對應方法is T
是Expression.TypeIs
,它與Expression.OrElse
結合允許您動態構建所需的謂詞.
例如:
public static Expression<Func<T, bool>> MakeFilter<T>(this IEnumerable<Type> types)
{
var parameter = Expression.Parameter(typeof(T), "e");
var body = types.Select(type => Expression.TypeIs(parameter, type))
.Aggregate<Expression>(Expression.OrElse);
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
和頂級查詢助手:
public static IQueryable<T> OfTypes<T>(this IQueryable<T> source, IEnumerable<Type> types)
=> source.Where(types.MakeFilter<T>());
將其應用於您的樣本:
var types = new[] { typeof(Dog), typeof(Monkey) };
var query = db.Set<Animal>().OfTypes(types);
生成以下調試視圖表達式
DbSet<Animal>()
.Where(e => (e is Dog) || (e is Monkey))
並查詢 SqlServer 提供程序:
SELECT [a].[Id], [a].[Name], CASE
WHEN [m].[Id] IS NOT NULL THEN N'Monkey'
WHEN [d].[Id] IS NOT NULL THEN N'Dog'
WHEN [b].[Id] IS NOT NULL THEN N'Bear'
END AS [Discriminator]
FROM [Animals] AS [a]
LEFT JOIN [Bears] AS [b] ON [a].[Id] = [b].[Id]
LEFT JOIN [Dogs] AS [d] ON [a].[Id] = [d].[Id]
LEFT JOIN [Monkeys] AS [m] ON [a].[Id] = [m].[Id]
WHERE ([d].[Id] IS NOT NULL) OR ([m].[Id] IS NOT NULL)
它並不完美(EF Core 團隊有優化的空間——TPH 做到了這一點,添加了一種告訴鑒別器“完整”的方法,但 TPT 仍然缺乏這種能力),但是過濾數據庫方面是需要的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.