简体   繁体   English

实体框架核心 Lambda Function 未提前终止

[英]Entity Framwork Core Lambda Function not early terminating

I am using asp.net core with entityframework.我正在使用带有实体框架的 asp.net 内核。

When making an API call to get a list of entities i pass an optional filter in json which could look like this:在进行 API 调用以获取实体列表时,我在 json 中传递了一个可选过滤器,该过滤器可能如下所示:

{
  "name": "john",
  "customer.id": 1
}

In my ControllerAction I am first deserializing the JSON and then I am querying against the DB.在我的 ControllerAction 中,我首先反序列化 JSON,然后查询数据库。

var dynamicfilter = filter != null ? JsonConvert.DeserializeObject<Dictionary<string, string>>(filter) : new Dictionary<string, string>();

List<User> Users = _context.Users.Include(u => u.Customer).Where(u =>
    dynamicfilter.Keys.Count > 0 ? (
        (dynamicfilter.ContainsKey("name") ? u.Name.ToLower().Contains(dynamicfilter["name"].ToLower()) : true) &&
        (dynamicfilter.ContainsKey("customer.id") ? u.Customer.ID == Convert.ToInt32(dynamicfilter["customer.id"]) : true)
    ) : true).ToList();

This works as long as all filter parameters are set.只要设置了所有过滤器参数,它就可以工作。 If at least one filter parameter is not set, a null reference is thrown because even if the ContainsKey() is false the code between?如果未设置至少一个过滤器参数,则会抛出 null 引用,因为即使ContainsKey()false ,代码之间的代码是什么? and: is executed.和:被执行。

But if I first load the whole table and apply the filter locally, by doing it like that但是如果我首先加载整个表并在本地应用过滤器,通过这样做

List<User> Users = _context.Users.Include(u => u.Customer).ToList().Where(...

it works like a charm.它就像一个魅力。 Is there a way to make it work on Database-Side too?有没有办法让它在数据库端也能工作?

Just move the logic out of the query.只需将逻辑移出查询即可。 Like:喜欢:

IQueryable<User> query = _context.Users.Include(u => u.Customer);
query = dynamicfilter.ContainsKey("name") 
    ? query.Where(u=>u.Name.ToLower().Contains(dynamicfilter["name"].ToLower()) 
    : query;
query = dynamicfilter.ContainsKey("customer.id") 
    ? query.Where(u=>u.Customer.ID == Convert.ToInt32(dynamicfilter["customer.id"])) 
    : query;

List<User> Users = query.ToList(); // DB query executed here

This way the expression tree will be build in the query object and executed only on enumeration attempt.这样,表达式树将在query object 中构建,并且仅在尝试枚举时执行。 Check MS Docs 检查 MS 文档

This interface inherits the IEnumerable interface so that if it represents a query, the results of that query can be enumerated.此接口继承了 IEnumerable 接口,因此如果它表示一个查询,则可以枚举该查询的结果。 Enumeration forces the expression tree associated with an IQueryable object to be executed.枚举强制执行与 IQueryable object 关联的表达式树。 Queries that do not return enumerable results are executed when the Execute(Expression) method is called.调用 Execute(Expression) 方法时会执行不返回可枚举结果的查询。

On top I would suggest to check all the incoming parameters before you will apply it to the query最重要的是,我建议在将其应用于查询之前检查所有传入参数

if(dynamicfilter.ContainsKey("name") 
    && !string.IsNullOrWhitespace(dynamicfilter["name"]))
{
    var nameFilter = dynamicfilter["name"].ToLower();
    query = query.Where(u=>u.Name.ToLower().Contains(nameFilter);
}

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

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