尝试在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或为空,我会尝试查找可以表示名称字段的所有记录。
搜索" enn"当有15种不同的詹妮弗"记录带回ZERO结果。在我们关于如何执行此查询的思路方面,我们是否会偏离基础?
答案 0 :(得分:0)
你应该使用二进制 - 或者不是有条件的。使用条件 - 或者,如果第一个条件的计算结果为false,则不评估其余条件。据推测,当你搜索'enn'时,你得到的结果为0,因为没有'enn'NickNames的客户。
如果您将||
子句中的“Where()
”更改为“|
”,则应该会为您提供所需的结果。
<强> [编辑] 强>
如果您能够使用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”字符串拆分为数组中的数组:
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'。
希望这有帮助!
[注意] - 我没有在db性能方面对此进行测试,它可能不适合搜索超过100k的记录。我相信这仍然是使用EF和LINQ to Entities的最佳答案。
答案 1 :(得分:0)
Linq子句中的names.Contains
次调用不是String.Contains
;它是IEnumerable<string>.Contains
。因此,它正在进行完全比较,而不是它是否存在于字符串内部。
我能想到这样做的唯一方法就是:
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();
答案 2 :(得分:0)
这是我最终得到的代码。基本上使用了ienumerable Names对象上的any,然后查看名称(或其中任何一个)中的“name”是否包含在DB属性中,例如NickName。这确实解决了这个问题。
.WhereIf(!String.IsNullOrEmpty(search.Name), a=> names.Any(b => a.NickName.Contains(b) || a.FirstName.Contains(b) || a.LastName.Contains(b)))
答案 3 :(得分:0)
尝试使用单个字段按名称搜索客户 我的searchViewModel。在客户数据库模型中,名称是 用4个属性表示(FirstName,LastName,MiddleName,&amp; 昵称)。
对我来说,这个问题有两个部分,即搜索和后端过滤器的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。我认为其他答案对前端解析提供了很好的建议