使用Entity Framework,我有一个类层次结构,它们映射到同一个表。类似于Cat : Animal
,Dog : Animal
,Goat : Animal
。
当然,EF内部使用Discriminator列来处理它们。
现在,我想写一些类似的东西:
var houseAnimals = new List<Type>(new [] { typeof(Cat), typeof(Dog) });
this.dataRepository.Animals.Where(a => houseAnimals.Contains(a.GetType()));
当然,这不会起作用,因为LINQ-to-SQL不支持.GetType()
。但是,这可行:
this.dataRepository.Animals.Where(a => a is Cat);
我不想a is Cat || a is Dog
,因为此列表是在运行时动态构建的。
基于this post,我了解EF会将其转换为SQL查询,其中包含&#39; Discriminator in&#39;声明。所以,这给了我一些希望,我需要做的事情。这样:
this.dataRepository.Animals.Where(a => a is **in** houseAnimals);
会很好,但当然没有这样的语法。
问题是,我可以使用什么语法来实现这一目标?我在这里错过了什么吗?这是EF中缺少的功能吗?我不可能是唯一一个想要进行此类查询的人。
基于这个例子,请不要将我的方法和执行此查询的需要放在一边,因为为了解释我的需要,我已经简化了很多。做.ToList()
也不是一种选择。
答案 0 :(得分:2)
EF不提供开箱即用的此类功能。但是编写一个自定义扩展方法并不难,在Expression.TypeIs
和Expression.OrElse
的帮助下动态构建谓词:
public static class QueryableExtensions
{
public static IQueryable<T> OfType<T>(this IQueryable<T> source, IEnumerable<Type> types)
{
var parameter = Expression.Parameter(typeof(T), "a");
var body = types
.Select(type => Expression.TypeIs(parameter, type))
.Aggregate<Expression>(Expression.OrElse);
var predicate = Expression.Lambda<Func<T, bool>>(body, parameter);
return source.Where(predicate);
}
}
假设您的存储库返回IQueryable<Animal>
,则使用情况为:
this.dataRepository.Animals.OfType(houseAnimals);