EF查询-单个VM字段到多个DB属性

本文关键字:DB 属性 字段 查询 单个 VM EF | 更新日期: 2023-09-27 18:27:19

尝试在searchViewModel中使用单个字段按名称搜索客户。在客户数据库模型中,名称由4个属性(FirstNameLastNameMiddleNameNickName)表示。

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"会返回零结果。在如何执行这个查询的问题上,我们的思路是否偏离了底线?

EF查询-单个VM字段到多个DB属性

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)))