EF查询-单个VM字段到多个DB属性
本文关键字:DB 属性 字段 查询 单个 VM EF | 更新日期: 2023-09-27 18:27:19
尝试在searchViewModel中使用单个字段按名称搜索客户。在客户数据库模型中,名称由4个属性(FirstName
、LastName
、MiddleName
和NickName
)表示。
var names = search.Name.Trim().Split(' ').OrderBy(s => s).Select(s => s.ToLower());
.WhereIf(!String.IsNullOrEmpty(search.Name), a => names.Contains(a.NickName.ToLower()) || names.Contains(a.FirstName) || names.Contains(a.LastName.ToLower()))
WhereIf
对您来说可能不熟悉,但它实际上只是在第一个结果为true的情况下将if语句添加到查询中。在本例中,如果name的搜索属性不为null或为空,我将尝试查找可以表示name字段的所有记录。
当有15条不同的"詹妮弗"记录时,搜索"enn"会返回零结果。在如何执行这个查询的问题上,我们的思路是否偏离了底线?
Linq子句中的names.Contains
调用不是String.Contains
;它是CCD_ 8。因此,它是在做一个完整的比较,而不是它是否存在于字符串内部。
我能想到的唯一方法是:
IEnumerable<string> names = search.Name.Trim().Split(' ').OrderBy(s => s).Select(s => s.ToLower());
IQueryable<User> users = db.Users;
foreach (string name in names)
{
users = users.Where(u => u.NickName.ToLower().Contains(name) || u.FirstName.ToLower().Contains(name) || u.LastName.ToLower().Contains(name));
}
return users.ToList();
您应该使用二进制或,而不是条件。对于条件或,如果第一个条件的计算结果为false,则不计算其余条件。据推测,当你搜索"enn"时,你会得到0个结果,因为没有昵称为"enn"的客户。
如果您将Where()
子句中的"||
"更改为"|
",则会得到您想要的结果。
[EDIT]
如果您能够使用LINQKit,PredicateBuilder
应该可以让您做您想要做的事情。
因此,给定一个虚拟客户列表:
List<Customer> customers = new List<Customer>()
{
new Customer { FirstName = "Jenn", LastName = "Doe" },
new Customer { FirstName = "Jennifer" },
new Customer { FirstName = "Jenn Doh" },
new Customer { FirstName = "Bob" },
new Customer { FirstName = "Love", LastName = "Jenn" },
new Customer { FirstName = "Jennifer", MiddleName = "Love", LastName = "Hewitt", NickName = "J Love" },
new Customer { FirstName = "J", LastName = "Love" }
};
以及给定的输入值:
string input = "Love"; // 3 results
将"name"字符串从"single field"拆分为一个数组,如示例中所示:
var parseName = input.Trim().Split(' ').OrderBy(s => s).Select(s => s.ToLower());
使用PredicateBuilder,循环遍历数组并构建要在Where()子句中使用的表达式:
var predicate = PredicateBuilder.False<Customer>();
foreach (var item in parseName)
{
predicate = predicate.Or(m => m.FirstName.Contains(item) | m.LastName.Contains(item) | m.MiddleName.Contains(item) | m.NickName.Contains(item));
}
并执行您的查询:
var results = db.Customers.AsExpandable().Where(predicate);
如果使用EF,则需要AsExpandable()。
这应该会返回3个结果,因为在List()中,有三个例子的First、Last、Middle或NickName字段中都有"Love"。
希望这能有所帮助!
[注意]-我还没有测试过数据库性能,它可能不适合搜索超过100k条记录。我相信这仍然是使用EF和LINQ to Entities的最佳答案。
尝试使用单个字段在中按名称搜索客户我的searchViewModel。在客户数据库模型中,名称为用4个属性(FirstName、LastName、MiddleName、&NickName)。
对我来说,这个问题有两个部分,用于搜索的GUI解析和后端过滤器。
如果您有一个强类型的Person模型,其中包含FirstName、LastName、MiddleName和NickName字段,则对集合的过滤很简单。假设您有个人列表
List<Person> mylist = GetPersons();
var stuff = mylist.where(p=>p.FirstName.Contains(firstname)
&& p.LastName.Contains(lastname) ...
如果你没有查询的模型,那么创建类很简单,但在发出查询时,有一件很酷的事情,你可以使用EF SQLQuery并传递一个类型,SQL将创建这样的强类型结果:
//allow the db to do the work
public IEnumerable<Person> GetPersons(){
using(var db = new MyEntities()){
var stuff = db.Database.SqlQuery<Person>(querystring, parameters);
return stuff.ToList();
}}
如果使用单个字段作为输入,那么解析当然非常重要,因为用户不会遵守规则(通常),这会使解析更加重要。为此,您可以使用如图所示的内置字符串函数或REGEX。我认为其他答案为前端解析提供了很好的建议
这是我最终得到的代码。本质上是在ienumerableNames对象上使用any,然后查看名称(或其中任何名称)中的"名称"是否包含在DB属性(如NickName)中。这确实解决了问题。
.WhereIf(!String.IsNullOrEmpty(search.Name), a=> names.Any(b => a.NickName.Contains(b) || a.FirstName.Contains(b) || a.LastName.Contains(b)))