【发布时间】:2023-03-18 07:27:01
【问题描述】:
我正在尝试编写一些东西来对实体框架模型的所有属性进行“包含”查询。
例如,我可以毫无问题地执行以下操作:
var students = db.Students.AsQueryable();
var test = students.Where(x => x.FirstName.ToString().ToLower().Contains("1"));
但是使用反射时(如下代码所示),返回如下错误:
LINQ to Entities 无法识别方法“System.String ToString()”方法,并且该方法无法转换为存储表达式。
现在应该是supported。
我已阅读此错误,但正如您在上面看到的,即使使用 IQueryable,ToString 也是完全有效的(在我的情况下这是必需的,因为我不想发布过滤数据)。
主要区别是我需要通过反射来调用它。
private static readonly MethodInfo StringContainsMethod =
typeof(string).GetMethod(@"Contains",
BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null);
Type dbType = typeof(Student);
var dbFieldMemberInfo = dbType.GetMember("FirstName",
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).Single();
// Create an "x" as TDbType
var dbTypeParameter = Expression.Parameter(dbType, @"x");
// Get at x.FirstName
var dbFieldMember = Expression.MakeMemberAccess(dbTypeParameter, dbFieldMemberInfo);
// Create the criterion as a constant
var criterionConstant = new Expression[] { Expression.Constant(searchString) };
var toStringMethod = typeof(Convert).GetMethod("ToString", Type.EmptyTypes);
var toStringCall = Expression.Call(dbFieldMember, toStringMethod);
var fancyContain = Expression.Call(toStringCall, StringContainsMethod, criterionConstant);
// Create a lambda like x => x.FirstName.ToString().Contains(criterion)
var lambda = Expression.Lambda(fancyContain, dbTypeParameter) as Expression<Func<Student, bool>>;
这会产生完全相同的 lambda x.FirstName.ToString().Contains(""),但它会返回无法使用 ToString 的错误。从第一个示例和它被添加到 EF 6.1 的事实可以清楚地看出,它可以使用。这是反射的限制吗?
【问题讨论】:
-
我想说,如果您使用 EF 使用字符串匹配来查询您的数据库元数据,那么您就违背了 EF 的目的,应该寻求不同的解决方案。数据上下文不打算用于查询元数据。如果您对此一无所知,则将其向上或向下推一层,而不是尝试将其转换为查询。要么对你的模型属性做一些字符串魔术,然后编写一个表达式来只在你的查询中包含这些属性,或者向下一层创建一个存储过程,或者让上下文直接执行一个查询。
-
这是一个通用的解决方案。基本上有人有一个数据网格......他们有一个搜索框......他们可以在搜索框中输入一个数字或一些文本,它会自动对他们标记为可搜索的实体中的所有字段进行服务器端搜索.如果该字段恰好是一个 int 字段,我需要在其上使用 ToString。它允许某人轻松查询所有字段,而无需执行任何设置或手动案例语句。
-
我也可以轻松检测属性是否为字符串,但我还想在不使用等于的情况下支持整数字段。例如,如果我键入 10,则该数字 10 可以出现在数字字段中的任何位置,因此必须将其解析为字符串。例如,它还可以搜索日期字段等。它并不是一种快速的搜索解决方案,只是一种在数据网格上即插即用的搜索方式。
-
这可能是
Func<T>与Expression<Func<T>>的问题。 -
我注意到您正在使用
Convert.ToString()方法创建一个表达式,并让您的变量调用该方法。这与您发布的链接 (e.Id.ToString()) 中的用法有点不同,后者是ToString()的单个类型的实现。您可能需要获取参数的类型,然后调用 thatToString()方法。
标签: c# linq entity-framework reflection