gpt4 book ai didi

c# - 从在字符串定义的字段上过滤的字符串定义的表名获取数据

转载 作者:行者123 更新时间:2023-11-30 21:34:16 25 4
gpt4 key购买 nike

我正在尝试根据值数组中的动态字段名称返回动态类型的 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);
}

最后一行给我一个错误:

Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.

老实说,这是我今天下午从互联网上的片段中拼凑出来的。我不知道我在这里做什么,这对我来说是新的,我很想学习。只是想避免 SQL 注入(inject),项目的其余部分完全是 Linq,所以我继续努力。我也在学习泛型类型,对此有所了解,但不知道如何在这里使用它们。

最佳答案

这一行代码有很多缺陷:

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

  • 尝试调用可能错误的方法。 Where 有 2 个重载,并且未定义反射首先返回哪个重载。

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

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

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

IQueryable results = Queryable.Where((dynamic)entityTable, (dynamic)lambda);

可以使用以下 Expression.Call 简化整个代码过载:

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

您还可以避免动态 Where 调用并使用类似的基于 Expression.Call 的方法来“调用”它,并结合 IQueryProvider.CreateQuery:

// query.Where(predicate)
// = Queryable.Where<ElementType>(query, predicate)
var whereCall = Expression.Call(
typeof(Queryable),
nameof(Queryable.Where),
new Type[] { query.ElementType },
query.Expression,
predicate
);
// query = query.Where(predicate)
query = query.Provider.CreateQuery(whereCall);

我提供了所有这些,只是因为您说您热衷于学习。处理此类任务(而不是重新发明轮子)的最简单方法是使用一些第 3 方包。例如,使用 System.Linq.Dynamic打包整个代码将是:

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

关于c# - 从在字符串定义的字段上过滤的字符串定义的表名获取数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50415229/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com