C# 从在字符串定义字段上筛选的字符串定义的表名中获取数据

C# 从在字符串定义字段上筛选的字符串定义的表名中获取数据,c#,asp.net-mvc,entity-framework,linq,C#,Asp.net Mvc,Entity Framework,Linq,我试图根据一个值数组中的动态字段名返回动态类型的Where筛选表的内容 以下是我到目前为止的情况: public JsonResult GetRelationShips(string linkingTable, string idField, int[] ids) { var tableType = typeof(context).GetProperty(linkingTable); var entityTable = tableType.GetValu

我试图根据一个值数组中的动态字段名返回动态类型的Where筛选表的内容

以下是我到目前为止的情况:

public JsonResult GetRelationShips(string linkingTable, string idField, int[] ids)
    {
        var tableType = typeof(context).GetProperty(linkingTable);

        var entityTable = tableType.GetValue(db) as IQueryable;

        var method = typeof(List<int>).GetMethod("Contains");

        var eParam = Expression.Parameter(tableType.PropertyType.GetGenericArguments()[0]);

        var call = Expression.Call(Expression.Constant(ids.ToList()), method, Expression.Property(eParam, idField));

        var func = typeof(Func<,>);

        var genericFunc = func.MakeGenericType(tableType.PropertyType.GetGenericArguments()[0], typeof(bool));

        var lambda = Expression.Lambda(genericFunc, call, eParam);


        var results = typeof(System.Linq.Enumerable).GetMethods().Where(x => x.Name == "Where").First().Invoke(db, new object[] { lambda });

        return Json(results);
    }
公共JsonResult GetRelationShips(字符串链接表、字符串idField、int[]ID) { var tableType=typeof(context).GetProperty(linkingTable); var entityTable=tableType.GetValue(db)作为IQueryable; var method=typeof(List).GetMethod(“Contains”); var eParam=Expression.Parameter(tableType.PropertyType.GetGenericArguments()[0]); var call=Expression.call(Expression.Constant(ids.ToList()),方法,Expression.Property(eParam,idField)); var func=类型化(func); var genericFunc=func.MakeGenericType(tableType.PropertyType.GetGenericArguments()[0],typeof(bool)); var lambda=Expression.lambda(genericFunc,call,eParam); var results=typeof(System.Linq.Enumerable).GetMethods().Where(x=>x.Name==“Where”).First().Invoke(db,新对象[]{lambda}); 返回Json(结果); } 最后一行给了我一个错误:

不能对ContainsGenericParameters为true的类型或方法执行后期绑定操作


老实说,今天下午我是从互联网上的片段拼凑而成的。我不知道我在这里做什么,这对我来说是新的,我渴望学习。为了避免SQL注入,项目的其余部分完全是Linq,所以我将继续努力。我也在学习泛型类型,但我不知道如何在这里使用它们。

这一行代码中有很多缺陷:

var results = typeof(System.Linq.Enumerable).GetMethods().Where(x => x.Name == "Where").First().Invoke(db, new object[] { lambda });
  • 正在尝试调用
    可枚举的.Where
    而不是
    可查询的.Where
    。这将导致检索整个表数据并在内存中而不是在数据库端执行过滤

  • 试图调用可能错误的方法
    其中
    有2个重载,未定义反射将首先返回哪个重载

  • 试图调用泛型方法定义,导致出现异常。您必须首先使用
    MakeGenericMethod
    构造一个泛型方法并调用它

  • 试图通过反射调用静态泛型扩展方法,就像调用实例方法一样。相反,您应该将
    null
    作为第一个参数传递给
    Invoke
    ,并将
    newobject[]{entityTable,lambda}
    作为第二个参数传递

您可以通过简单地使用C#动态方法来避免所有这些陷阱:

IQueryable results = Queryable.Where((dynamic)entityTable, (dynamic)lambda);
使用以下重载可以简化整个代码:

public static MethodCallExpression Call(
    Type type, 
    string methodName,
    Type[] typeArguments,
    params Expression[] arguments);
这对于“调用”静态泛型扩展方法非常有用:

var query = (IQueryable)db.GetType().GetProperty(linkingTable).GetValue(db);
// e =>
var entity = Expression.Parameter(query.ElementType, "e");
// ids.Contains(e.idField)
// = Enumerable<int>.Contains(ids, e.idField)
var containsCall = Expression.Call(
    typeof(Enumerable),
    nameof(Enumerable.Contains),
    new Type[] { typeof(int) },
    Expression.Constant(ids),
    Expression.Property(entity, idField)
);
// e => ids.Contains(e.idField)
var predicate = Expression.Lambda(containsCall, entity);
// query = query.Where(predicate);
query = Queryable.Where((dynamic)query, (dynamic)predicate);
我提供所有这些只是因为你说你渴望学习。处理此类任务(而不是重新发明轮子)的最简单方法是使用一些第三方软件包。例如,对于包,整个代码将是:

var query = ((IQueryable)db.GetType().GetProperty(linkingTable).GetValue(db))
    .Where($"@0.Contains({idField})", ids);

谢谢你,看起来不错。我今天没有时间做任何事。一个问题;System.Linq.Dynamic选项仍然是SQL注入的证明吗?它基本上是Linq
IQueryable
查询转换器的字符串,因此根本不涉及SQL或任何类型的可执行代码。对动态Linq:var query=((IQueryable)db.GetType().GetProperty(linkingTable).GetValue(db))。其中($“@0.Contains(outerIt.{idField})”,ids);但谢谢你,这很有效。我决定接受第三方的建议,因为它使团队的其他成员更容易调试项目。
var query = ((IQueryable)db.GetType().GetProperty(linkingTable).GetValue(db))
    .Where($"@0.Contains({idField})", ids);