首先,您不能从数组创建新的 IQueryable,这将恢复为将所有内容拉入内存并在那里过滤。当您使用 SQL 执行 LINQ 时,您使用的是表达式而不是 c# 代码,这仅适用于内存内容(IEnumerable)。
如果您这样做,您的查询将在 SQL 中运行
from element in MyPredicateContext
where ids.Contains(element.Id)
select new Element
{
Id = element.Id,
Description = element.JobDescription,
}
鉴于 IQueryable 的类型,其中 T 是接口或类。
end 方法看起来像这样
public interface IElement
{
Guid Id { get; }
string JobDescription { get; }
}
public Element[] GetByIds<T>(IQueryable<T> myPredicateContext, Guid[] ids) where T:IElement
{
return (from element in myPredicateContext
where ids.Contains(element.Id)
select new Element
{
Id = element.Id,
Description = element.JobDescription,
}).ToArray();
}
有一些方法可以在没有泛型的情况下做到这一点,但它们更高级一些,并且难以维护。
这是一种适用于所有 T 类型的方法,并且正确的 IQueryable 将产生良好的 sql,正如我指出的那样更高级,您需要查找表达式的工作方式。
public static Element[] GetById<T, Tkey>(IQueryable<T> items,Tkey[] ids)
{
var type = typeof(T);
ParameterExpression param = Expression.Parameter(type);
var list = Expression.Constant(ids);
//The names of the properties you need to get if all models have them and are named the same and are the same type this will work
var idProp = Expression.Property(param, "Id");
var descriptionProp = Expression.Property(param, "JobDescription");
var contains = typeof(Enumerable).GetMethods().First(m => m.Name == "Contains" && m.GetParameters().Count() == 2).MakeGenericMethod(typeof(Tkey));
var where = Expression.Lambda<Func<T, bool>>(Expression.Call(contains, list, idProp), param);
return (items.
Where(where).
Select(Expression.Lambda<Func<T, Element>>(
Expression.MemberInit(
Expression.New(typeof(Element)),
Expression.Bind(typeof(Element).GetProperty("Id"), idProp),
Expression.Bind(typeof(Element).GetProperty("Description"), descriptionProp)),
param))).ToArray();
}
致电GetById(items, new Guid[] { Guid.NewGuid() })