简体   繁体   English

使用变量构建实体框架 Linq 查询

[英]Building Entity Framework Linq queries with variables

I am struggling to find best practise for something I have occasionally came across number of times and each time I am left with an impression that this is not the most elegant, best and most certainly efficient way to achieve what I want to do.我正在努力为我偶尔遇到的事情找到最佳实践,每次我都留下这样的印象,即这不是实现我想做的最优雅、最好和最肯定有效的方法。

Consider this:考虑一下:

model: model:

public class User
{
  public string firstName {get; set;}
  public string lastName {get; set;}
  public string middleName {get; set;}
  public string someName {get; set;}

 // etc... up to, let's say 20 inputs
}

html: html:

<input type="text" name="firstName">
<input type="text" name="lastName" disabled>
<input type="text" name="middleName" disabled>
<input type="text" name="someName" disabled>```

controller: controller:

private dbcontext db = new dbcontext();
List<User> users = db.Users.Where( x => firstName != null && x.firstName == fisrtName ||
                   lastName != null && x.lastName == lastName ||
// and so on, and so on...

Now, some bloke on the other end will have the option to enable above inputs and query database for some user with the passed parameters.现在,另一端的一些人可以选择启用上述输入并使用传递的参数为某些用户查询数据库。

I hope that by now you get the idea what I am struggling to understand here.我希望现在你明白我在这里努力理解的内容。 I like to use only variables that were enabled and combine them into AND query instead of OR .我喜欢只使用已启用的变量并将它们组合成AND查询而不是OR I know, I know - that && are used for that matter but this doesn't work the way I would like to.我知道,我知道 - &&用于这件事,但这并不像我想要的那样工作。

I do not want to use if statement to check every single variable for null and then create query for every scenario that could happen.我不想使用if 语句检查 null 的每个变量,然后为可能发生的每个场景创建查询。

My appologies if thats a repost, but I couldn't find answer for that.如果那是转发,我很抱歉,但我找不到答案。

Model : Model

public class User
{
  public string firstName {get; set;}
  public string lastName {get; set;}
  public string middleName {get; set;}
  public string someName {get; set;}

 // etc... up to, let's say 20 inputs
}

HTML : HTML

@model YourModel
@Html.TextBoxFor(m => m.firstName, "", new { })
@Html.TextBoxFor(m => m.lastName, "", new { @disabled = true })
@Html.TextBoxFor(m => m.middleName, "", new { @disabled = true })
@Html.TextBoxFor(m => m.someName, "", new { @disabled = true })

Controller : Controller

        private readonly YourContext _db;

        public YourController(YourContext db)
        {
            _db = db;
        }
        [HttpGet]
        public async Task<IActionResult> YouReturningView()
        {
          var model = await _db.YourDbSet.Where(Your Where).FirstAsync();
          return View(model);
        }

I think thats the mode elegant and officient way how to do it.我认为这就是如何做到这一点的优雅和正式的方式。 Generated Html will have all needed attributed that are like in your class.生成的 Html 将具有所有需要的属性,就像在您的 class 中一样。

If you want to query the records based on the fields that are enabled, you need to go for dynamic where clause in linq query如果要根据启用的字段查询记录,则需要 go 用于 linq 查询中的动态 where 子句

below query can be used to enable the where clause dynamically only when data is present in field.仅当字段中存在数据时,以下查询可用于动态启用 where 子句。 If data is present in firstName it will check for the records for firstName based on record, else it will return true and goes for next condition.如果 firstName 中存在数据,它将根据记录检查 firstName 的记录,否则它将返回 true 并进入下一个条件。 If both firstName and middleName has data, then it will get the records based on both first and middle name.如果firstName 和middleName 都有数据,那么它将根据firstName 和middleName 获取记录。 Same approach for all other fields所有其他领域的方法相同

If no data is present in all the fields then it will return all the records from database如果所有字段中都没有数据,那么它将返回数据库中的所有记录

List<User> users = (from u in db.Users
                   where 
                   (firstName != null? u.firstName == firstName:true) &&
                   (lastName != null? u.lastName == lastName:true) &&
                   (middleName != null ? u.middleName == middleName:true) &&
                   (someName != null ? u.someName == someName:true)

                   select new User
                   {
                       firstName = u.firstName,
                       lastName = u.lastName,
                       middleName = u.middleName,
                       someName = u.someName


                   }).ToList();

Assuming the web request is converted to an instance of your User model, you can start with a bit of reflection to get this done.假设 web 请求被转换为您的User model 的实例,您可以从一些反射开始以完成此操作。

To start with, let's assume the object comes back from the web request as a User object that may or may not have all the field populated.首先,让我们假设 object 作为User object 从 web 请求返回,可能会或可能不会填充所有字段。 Let's call it SearchUser .我们称之为SearchUser

First, we can reflect on the User type to get all of the properties.首先,我们可以通过反思User类型来获取所有属性。

var filledProperties = typeof(User).GetProperties()
    .Where(t => t.GetValue(SearchUser) != null 
    && !string.IsNullOrEmpty(t.GetValue(SearchUser).ToString()));

What this is doing is inspecting the SearchUser object and returning an array of PropertyInfo objects that have a non-null value and are not empty strings.这样做是检查SearchUser object 并返回具有非空值且不是空字符串的PropertyInfo对象数组。 This means that your web request could have values for 5 of 20 properties or all 20, and however many are populated will end up in this array.这意味着您的 web 请求可能具有 20 个属性中的 5 个或全部 20 个属性的值,但是填充的许多属性最终会出现在此数组中。

Next, we can use it to query your database.接下来,我们可以使用它来查询您的数据库。

List<User> users = db.Users
    .Where(u => filledProperties.Any(p => p.GetValue(u) != null
    && p.GetValue(u).ToString()
    == p.GetValue(SearchUser).ToString()))
    ToList();

What we've done here is inspect each database user and return it if any of the properties in it match both of the following:我们在这里所做的是检查每个数据库用户,如果其中的任何属性与以下两个匹配,则返回它:

  • The matching DB property to the tested property in filledProperties is not null, and filledProperties中与测试属性匹配的 DB 属性不是 null,并且
  • the matching property in the DB has the same value as the property in the SearchUser object with the same name. DB 中的匹配属性与同名的SearchUser object 中的属性具有相同的值。

The pros of this approach is that no matter how many string properties are available on your User class, this will work, and you don't need to change any of the query code.这种方法的优点是,无论您的User class 上有多少字符串属性可用,都可以使用,并且您无需更改任何查询代码。 Also, it works if some of your properties are null or empty, in either the SearchUser or the Database object.此外,如果您的某些属性在SearchUser或数据库 object 中为 null 或为空,它也可以工作。

The cons are of course that is is using reflection pretty heavily.缺点当然是大量使用反射。 This will be a heavy query to run so if you have a lot of concurrent requests or you have a large table of users, this might not be ideal.这将是一个繁重的查询,因此如果您有很多并发请求或有大量用户表,这可能并不理想。 In that case, you may look toward shadowing the DB data in something like ElastiSearch so you can run your searches faster on a tool that is designed better for the task.在这种情况下,您可能会考虑在 ElastiSearch 之类的东西中隐藏数据库数据,以便您可以在更适合该任务的工具上更快地运行搜索。 That's up to you though, but this gets your example working.但这取决于您,但这可以使您的示例正常工作。

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

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