反射 Linq-实体“IN()”函数,用于“包含”搜索整数组
本文关键字:包含 用于 搜索 整数 数组 函数 IN Linq- 反射 实体 | 更新日期: 2023-09-27 18:31:41
我正在为某些类型的搜索构建自己的反射函数。
问题是我想在 ID 列表中搜索一组 ID,并过滤我的搜索/选择查询以仅包含这些特定对象。
这与在 Linq-Entity 框架中使用 "IN()" 相同。但我不能使用a.objid。
return query.Where(a => ObjectsToFind.Contains(a.objid));
但是,"a.objid"导致错误,因为我使用 T 模板。
所以 a 是 "T a"而不是 "MyTable a",所以我可以称它为 "objid" 属性。
我知道有一种方法可以使用参数表达式来做到这一点。但是,我想不通。
这是我试图用上面一行替换的内容:
public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query, string contains)
{
var ObjectsToFind = new List<int>(); // I want to search IN() this function that gets filled in here.
ObjectsToFind = FillObjectsToFind(); // just the object id integers I want to filter
var parameter = Expression.Parameter(typeof(T), "type");
var propertyExpression = Expression.Property(parameter, "objid"); // I look for this
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(int) }); // int type
var vars = Expression.Variable(List<int>,); // I can't use "constant", but what do I use here?
var containsExpression = Expression.Call(propertyExpression, method, vars);
return query.Where(Expression.Lambda<Func<T, bool>>(containsExpression, parameter));
}
用实际的表实体替换"T"会导致很多问题,所以我决定保留 T。
else if (s.ST == "function")
{ // search func
myTable a;
DC2 = MyUtility.WhereFunctionContains(DC2, a => a.objid, s.S);
// s.S is my search query string.
// s.ST means I'm searching for functions (from another associated table)
// I don't understand how a.objid gets called, I wanted to use Template/Reflections.
}
以下是我如何调用 Zev 的函数。
public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query, Expression<Func<T, int>> converter, string contains)
{
FunctionsClass fc = new FunctionsClass();
var ObjectsToFind = new List<int>();
ObjectsToFind = fc.SearchContainFunction(contains); // I grabbed my list of IDs to search
return query.Where(t => ObjectsToFind.Contains(converter(t)));
}
如果我理解正确,您对不同类型的查询有很多:
IQueryable<Person> personsQry = ...
IQueryable<Sale> salesQry = ...
IQueryable<Order> ordersQry = ...
并且您有一个生成List<int>
的方法,称为 FillObjectsToFind
:
public List<int> FillObjectsToFind()
{
//code here
}
您希望能够将上述每个查询限制为仅在返回的列表中包含 id。作为额外的好处,这应该是一个扩展方法,所以你可以这样调用它:
var personsFiltered = personsQry.WhereFunctionContains(...);
var salesFiltered = salesQry.WhereFunctionContains(...);
var ordersFiltered = ordersQry.WhereFunctionContains(...);
问题是每个查询都是单独的类型,您希望编写一个涵盖所有查询的方法。
解决方案的第一部分是定义一个泛型方法:
public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query)
{
//code here
}
但是仍然存在一个问题:我们知道的唯一类型是类型 T
,它不是实际类型,而是实际类型的占位符。由于这些类型可以是任何类型——string
、System.Random
、SqlConnection
、ASP.NET Label
、WPF TextBlock
——因此无法知道如何将每个对象与ints
List
进行比较。
最直接的解决方案是定义一个接口:
interface IHasObjID
{
int ObjID {get;set;}
}
然后每种类型都应实现此接口:
class Person : IHasObjID
{
int objID;
int ObjID
{
get {return objID;}
set {objID = value;}
}
}
//implement sales and orders similarly
完成此操作后,可以对方法允许的类型定义约束。现在该类型肯定具有ObjID
属性,我们可以对此进行查询:
public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query) where T : IHasObjID
{
var intsToFind = FillObjectsToFind();
return query.Where(t => intsToFind.Contains(t.ObjID));
}
这就是王王在这篇评论中告诉你的。
public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query, Expression<Func<T,int>> converter)
{
var intsToFind = FillObjectsToFind();
return query.Where(t => intsToFind.Contains(converter(t)));
}
毕竟,解决方案很简单,使用 Join
:
public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query, Expression<Func<T,int>> converter)
{
var ints = new List<int>() { 1, 2, 3, 4, 5 };
return query.Join(ints,converter,i=>i,(t,i) => t);
}
这样称呼:
var filteredPersons = query.WhereFunctionContains(p => p.PersonID);
如果这仅用于单个类型
MyTable
:
public static IQueryable<MyTable> WhereFunctionContains(this IQueryable<MyTable> query)
{
var ints = new List<int>() { 1, 2, 3, 4, 5 };
return query.Join(ints, mt=>mt.objid, i=>i, (t,i) => t);
}
C# 编程指南中的一些链接(按答案顺序):
- 扩展方法
- 泛 型
- 泛型方法
- 泛型约束
- 接口
- LINQ 内部联接
另外,有关 LINQ 运算符的良好概述,请参阅此处,例如 Select
、 Where
、 Count
和 ToList
。