C# 如何使用反射对实体框架模型的属性执行ToString

C# 如何使用反射对实体框架模型的属性执行ToString,c#,linq,entity-framework,reflection,C#,Linq,Entity Framework,Reflection,我试图写一些东西,对实体框架模型的所有属性进行“包含”查询 例如,我可以在没有问题的情况下执行以下操作: var students = db.Students.AsQueryable(); var test = students.Where(x => x.FirstName.ToString().ToLower().Contains("1")); 但是,当使用反射时(如下面的代码所示),将返回以下错误: LINQ to Entities无法识别方法“System.String ToStr

我试图写一些东西,对实体框架模型的所有属性进行“包含”查询

例如,我可以在没有问题的情况下执行以下操作:

var students = db.Students.AsQueryable();
var test = students.Where(x => x.FirstName.ToString().ToLower().Contains("1"));
但是,当使用反射时(如下面的代码所示),将返回以下错误:

LINQ to Entities无法识别方法“System.String ToString()”方法,并且无法将此方法转换为存储表达式

应该是现在

我已经读到了这个错误,但是正如您在上面看到的,ToString是完全有效的,即使在使用IQueryable时也是如此(这在我的情况下是必需的,因为我不想对数据进行后期筛选)

主要的区别是我需要通过反射调用它

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>>;
private static readonly MethodInfo stringcontains方法=
typeof(string).GetMethod(@“Contains”,
BindingFlags.Instance | BindingFlags.Public,null,new[]{typeof(string)},null);
类型dbType=类型(学生);
var dbFieldMemberInfo=dbType.GetMember(“FirstName”,
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).Single();
//创建一个“x”作为TDB类型
var dbTypeParameter=Expression.Parameter(dbType,@“x”);
//得到x.FirstName
var dbFieldMember=Expression.MakeMemberAccess(dbTypeParameter,dbFieldMemberInfo);
//将标准创建为常量
var-critericonconstant=新表达式[]{Expression.Constant(searchString)};
var-toStringMethod=typeof(Convert.GetMethod)(“ToString”,Type.EmptyTypes);
var toStringCall=Expression.Call(dbFieldMember,toStringMethod);
var fancyContain=Expression.Call(toString调用、StringContainsMethod、criterionConstant);
//创建一个lambda,如x=>x.FirstName.ToString().Contains(标准)
var lambda=Expression.lambda(fancyContain,dbTypeParameter)作为表达式;

这将生成相同的lambda
x.FirstName.ToString()。包含(“”
),但它返回一个错误,即ToString无法使用。显然,从第一个示例以及它被添加到EF 6.1的事实来看,它是可以使用的。这是反射的限制吗?

对于一些应该相当简单的东西来说,这看起来很复杂。我建议在您的表中创建一个
textdata
computed列,它可以简单地连接您感兴趣的所有字段。然后,可以向模型中添加如下属性:

[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string TextData { get; set; }

最后,您可以对这个属性执行LINQ查询,以检查它
。是否包含(…)
您感兴趣的任何文本。只要对列进行索引,搜索就不会太糟糕。您的主要惩罚是插入。

看起来您尝试的是基于所有列进行搜索。最简单、最快速的方法是从EF执行查询并进行全文搜索

 var students = db.Database.SqlQuery<Student>("SELECT * FROM Student WHERE CONTAINS((Name, ID), '12')");
var students=db.Database.SqlQuery(“从包含((名称,ID),'12')的学生中选择*”;
(只需确保清理字符串时没有sql注入)

我认为,当您试图构建表达式树并根据SQL执行它时,SQL不会识别它,因为当您使用Querable时,您还没有执行它


另一种方法是使用
SqlFunctions.StringConvert
而不是
ToString

看起来问题源于在表达式中使用
Convert.ToString()
方法,而不是
ToString()
方法的类型的单独实现,例如
toStringMethod=type.GetMethod(“ToString”,Type.EmptyTypes)

谢谢,尽管这是一个其他人会使用的公共库。我认为sql注入的风险太高,我不知道如何在没有参数查询的情况下100%消除它。基本上,我允许人们连接datatables.net网格并自动搜索他们正在使用的任何实体。此外,我还阅读了关于tSqlFunctions.StringConvert,但我不确定这如何解释我的第一个代码示例的工作原理。在尝试通过反射调用方法时,它似乎失败了。在这两种情况下,我都使用IQueryable。第一个示例生成的sql代码转换为nvarchar,然后转换为ToLower,等等,并且工作正常。我更新了代码示例和标题以使其生效更清楚一点。@KingOfHypocrites您可以将参数用于此方法。谢谢,如果需要,我可以这样做,但我已经有了不需要动态sql语句且完全通用的代码。使用反射调用ToString是唯一不起作用的。谢谢,尽管这是其他人使用的公共库因此,我无法控制他们的数据库结构。我想说,如果您使用EF使用字符串匹配来查询db元数据,那么您就违背了EF的目的,应该寻求不同的解决方案。datacontext不打算用于查询元数据。如果您对此死心塌地,那么可以将其向上或向下推一层,而不是向上推尝试将其转换为查询。对模型属性执行一些字符串魔术,然后编写一个表达式以仅在查询中包含这些属性,或者深入一层创建一个存储过程,或者让上下文直接执行查询。这是一个通用解决方案。基本上,有些人有一个datagrid…他们有一个search框…他们可以在搜索框中键入一个数字或一些文本,它将自动对实体中标记为可搜索的所有字段进行服务器端搜索。如果该字段恰好是一个int字段,我需要使用它来搜索。它允许用户轻松查询其所有字段,而无需进行任何设置或手动case语句。此外,我可以轻松检测属性是否为字符串,但我希望也支持整数字段,而不使用equals。例如,如果我键入10,则数字10可以出现在数字字段的任何位置,因此必须作为字符串进行解析。例如,它也可能是se