繁体   English   中英

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

[英]How to Perform ToString On Property of an Entity Framework Model Using Reflection

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

例如,我可以执行以下操作而不会出现问题:

var students = db.Students.AsQueryable();
var test = students.Where(x => x.FirstName.ToString().ToLower().Contains("1"));

但是,当使用反射(如下代码所示)时,将返回以下错误:

LINQ to Entities无法识别方法'System.String ToString()',并且该方法无法转换为商店表达式。

现在应该支持它。

我已经读过这个错误, 但是正如您在上面看到的,即使使用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执行查询并进行全文搜索。

 var students = db.Database.SqlQuery<Student>("SELECT * FROM Student WHERE CONTAINS((Name, ID), '12')");

(只需确保您清洁了没有SQL注入的字符串)

我认为,在尝试构建表达式树并针对SQL执行它时,SQL无法识别它,因为当您使用Querable时,您还没有执行它。

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

看起来问题出在您的表达式中,而不是该类型的ToString()方法的单独实现,例如,在表达式中使用Convert.ToString() ToString()方法,例如toStringMethod = type.GetMethod("ToString", Type.EmptyTypes);

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

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

最后,您可以仅针对此一个属性执行LINQ查询,以检查它是否.Contains(...)是否.Contains(...)您感兴趣的任何文本。只要索引该列,搜索就不会太糟糕。 您的主要惩罚将在插入内容中。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM