具有泛型类属性的 LINQ 表达式
本文关键字:LINQ 表达式 属性 泛型类 | 更新日期: 2023-09-27 18:32:10
我想将IQueryable和ID数组传递给基于这些ID过滤IQueryable的方法。
由于 id 可以是 long 或 int,因此通常应该解决。
我想出了以下内容:
public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
return objects.Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}
不幸的是,我得到了例外:
LINQ to Entities 无法识别方法"System.Object GetValue(System.Object)"方法,并且此方法无法转换为存储表达式。
例外是正常的,因为通过反射获取属性显然无法转换为 SQL。
我会尝试的一件事是创建一个通用接口,该接口公开给定类型的 Id
属性:
public interface HasId<T> {
T Id { get; set; }
}
现在您可以将您的实体声明为实现HasId<int>
,例如,如果Id
的类型为 int
。
下一步是修改您的方法,如下所示:
public static IEnumerable<T> GetModified<TId, T>
(IQueryable<T> objects, TId[] ids) where T : class, HasId<TId>
{
return objects.Where(j => ids.Contains(j.Id));
}
请注意添加的一般限制:where T : class, HasId<TId>
。这使您能够编写简化的j.Id
,它返回一个TId
值,而不是诉诸反射。
请注意,我还没有运行或测试过这段代码;这只是我看到你的问题时得到的一个想法,我希望它有所帮助。
更新:
下面是另一种可能的解决方案,它不需要以任何方式声明接口或更改类:
public static IEnumerable<T> GetModified<TId, T>
(IQueryable<T> objects, TId[] ids, Expression<Func<T, TId>> idSelector)
where T : class
{
return objects.Where(j => ids.Contains(idSelector(j)));
}
我在这里所做的是添加 Expression<Func<T, TId>> idSelector
参数,一个可以返回给定T
实例Id
的表达式。
您可以像这样调用该方法:
var modified = GetModified(dbObjects, yourIdArray, entity => entity.Id);
(只有第三个参数是新的;保持其他参数现在的样子)。
同样,我还没有测试这是否有效甚至无法编译,因为我:(这里没有一台装有 VS 的计算机。
实体框架不支持某些.NET方法,例如GetValue()
,因为它不会转换为SQL(这是实际执行到IQueryable
的代码)。在执行反射之前,请尝试调用ToList
以获取 CLR 对象:
public static IEnumerable<T> GetModified<TId, T>(IQueryable<T> objects, TId[] ids) where T : class
{
return objects.ToList().Where(j => ids.Contains((TId)j.GetType().GetProperty("Id").GetValue(j)));
}