我正在尝试写一些能做"包含"查询实体框架模型的所有属性。
我可以执行以下操作,例如没有问题:
var students = db.Students.AsQueryable();
var test = students.Where(x => x.FirstName.ToString().ToLower().Contains("1"));
但是,当使用反射时(如下面的代码所示),将返回以下错误:
LINQ to Entities无法识别方法' System.String ToString()'方法,并且此方法无法转换为商店表达式。
现在应该是supported。
我已经读过这个错误,但正如您所见,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>>;
这会产生完全相同的lambda x.FirstName.ToString().Contains("")
但它会返回一个不能使用ToString的错误。显然,从第一个例子和它添加到EF 6.1的事实,它可以使用。这是反思的限制吗?
答案 0 :(得分:2)
您尝试执行的操作似乎是基于所有列进行搜索,最简单,最快捷的方式是从EF执行查询并进行全文搜索。
var students = db.Database.SqlQuery<Student>("SELECT * FROM Student WHERE CONTAINS((Name, ID), '12')");
(只需确保清除字符串没有sql注入)
我认为当您尝试构建表达式树并对SQL执行它时,SQL无法识别它,因为当您使用Querable时尚未执行它。
另一种方法是使用SqlFunctions.StringConvert
代替ToString
答案 1 :(得分:1)
对于应该相当简单的事情来说,这看起来很复杂。我建议在表格中创建一个textdata
计算列,简单地连接您感兴趣的所有字段。然后您可以像这样在模型中添加属性:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public string TextData { get; set; }
最后,您可以针对这一个属性执行LINQ查询,以检查它是否.Contains(...)
您感兴趣的任何文本。只要您对列进行索引,搜索就不应该是太糟糕了。您的主要处罚将是插入。