反射Linq实体"IN()";用于“包含"功能的功能包括:搜索整数组 [英] Reflection Linq-Entity "IN()" function for "contains" searching group of integers

查看:48
本文介绍了反射Linq实体"IN()";用于“包含"功能的功能包括:搜索整数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为某些类型的搜索构建自己的反射函数.

I'm building my own reflection functions for certain types of searches.

问题是我想在ID列表中搜索一组ID,并过滤搜索/选择查询以仅具有这些特定对象.

The problem is that I want to search a group of IDs within a list of IDs and filter my search/select query to have only these specific objects.

这与在Linq-Entity框架中使用"IN()"相同.但是我不能使用a.objid.

return query.Where(a => ObjectsToFind.Contains(a.objid));

但是,因为我使用T模板,所以"a.objid"导致了错误.

However, "a.objid" is causing errors because I use T Template.

所以a是"T a"而不是"MyTable a",因此我可以将其称为"objid"属性.

So a is "T a" instead of "MyTable a" so that I can call it's "objid" property.

我知道有一种使用参数表达式执行此操作的方法.但是,我无法弄清楚.

I know there is a way to do this with parameter expressions. However, I can't figure it out.

这是我尝试将上面的内容替换为:

Here's what I tried to replace that above line with:

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.

Replacing "T" with the actual table entity, causes a lot of problems, so I decided to keep the 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函数的方式.

Here's how I call Zev's function.

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)));
}

推荐答案

如果我对您的理解是正确的,那么您会有许多关于不同类型的查询:

If I understand you correctly, you have a number of queries on different types:

IQueryable<Person> personsQry = ...
IQueryable<Sale>   salesQry   = ...
IQueryable<Order>  ordersQry  = ...

,您有一个生成List<int>的方法,称为FillObjectsToFind:

and you have a method that generates a List<int>, called FillObjectsToFind:

public List<int> FillObjectsToFind()
{
    //code here
}

您希望能够将上述每个查询限制为仅在返回列表中包含ID.另外,这应该是扩展方法,因此您可以这样称呼它:

You want to be able to limit each of the above queries to only have the id in the returned list. As an added bonus, this should be an extension method, so you can call it like this:

var personsFiltered = personsQry.WhereFunctionContains(...);
var salesFiltered   = salesQry.WhereFunctionContains(...);
var ordersFiltered  = ordersQry.WhereFunctionContains(...);

问题是每个查询属于单独的类型,您可能希望编写一种涵盖所有查询的方法.


解决方案的第一部分是定义一个通用方法:

The problem is each query is of a separate type, and you would prefer to write one method that covers all of them.


The first part of the solution is to define a generic method:

public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query)
{
    //code here
}

,但是仍然存在一个问题:我们知道的唯一类型是类型T,它不是真实类型,而是实际类型的占位符.由于这些类型可以是任何类型-stringSystem.RandomSqlConnection,ASP.NET Label,WPF TextBlock-无法知道如何将每个对象与ints中的>.


最直接的解决方案是定义界面:

but there is still a problem: the only type we know of is type T which is not a real type, but a placeholder for actual types. Since these types could be anything -- string, System.Random, SqlConnection, an ASP.NET Label, a WPF TextBlock -- there is no way of knowing how to compare each object to a List of ints.


The most straightforward solution is to define an interface:

interface IHasObjID
{
    int ObjID {get;set;}
}

然后每种类型都应实现此接口:

Then each type should implement this interface:

class Person : IHasObjID
{
    int objID;
    int ObjID
    {
        get {return objID;}
        set {objID = value;}
    }
}

//implement sales and orders similarly

完成后,您可以在方法允许的类型上定义约束.现在,该类型肯定具有ObjID属性,我们可以对此进行查询:

Once that is done, you can define a constraint on the types allowed by the method. Now that the type definitely has an ObjID property, we can query on that:

public static IQueryable<T> WhereFunctionContains<T>(this IQueryable<T> query) where T : IHasObjID
{
    var intsToFind = FillObjectsToFind();
    return query.Where(t => intsToFind.Contains(t.ObjID));
}

国王King

This is what King King was telling you in this comment.


I propose that when calling this function, you also pass in how to get at the integer from the type:

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)));
}

但是,我尚未测试此代码,并且由于我们正在使用Entity Framework和表达式,因此我怀疑仍然存在问题:不能在表达式内调用"表达式. 我想提出以上建议,但它不会与以下错误一起编译-'converter'是'variable',但像'method'一样使用.

However, I haven't tested this code, and since we are working with Entity Framework and expressions I suspect there is still an issue: An expression cannot be "called" within an expression. I wanted to suggest the above, but it doesn't compile with the following error -- 'converter' is a 'variable' but used like a 'method'.

毕竟,使用Join解决方案非常简单:

After all that, the solution is straightforward, using 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:


If this is only used with a single type 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#编程指南中的某些链接(按答案):


Some links from the C# Programming Guide (in order of the answer):

  • 扩展方法
  • 泛型
    • Extension methods
    • Generics
      • Generic methods
      • Generic constraints

      此外,请参阅此处,以获取LINQ运算符的详细概述,例如SelectWhereCountToList.

      Also, see here for a nice overview of LINQ operators, such as Select, Where, Count and ToList.

      这篇关于反射Linq实体"IN()";用于“包含"功能的功能包括:搜索整数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆