简体   繁体   中英

Entity Framwork Core Lambda Function not early terminating

I am using asp.net core with entityframework.

When making an API call to get a list of entities i pass an optional filter in json which could look like this:

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

In my ControllerAction I am first deserializing the JSON and then I am querying against the DB.

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? 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. Check MS Docs

This interface inherits the IEnumerable interface so that if it represents a query, the results of that query can be enumerated. Enumeration forces the expression tree associated with an IQueryable object to be executed. Queries that do not return enumerable results are executed when the Execute(Expression) method is called.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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