使用实体框架创建动态查询

Edu*_*ard 39 c# linq entity-framework entity-framework-4

我想知道使用实体框架和linq创建动态查询的最佳方法是什么.

我想创建一个服务,它有许多参数用于排序和过滤(超过50).我将从gui获取这些将被填写的对象...并且查询将从单个服务方法执行.

我环顾四周然后看到我可以动态创建一个可以在方法结束时执行的字符串.我不太喜欢这种方式.有一个更好的方法吗?最好是带编译检查的类型安全?

Sla*_*uma 54

你可以IQueryable<T>一步一步撰写.假设你有一个FilterDefinition描述用户想要过滤的方法的类......

public class FilterDefinition
{
    public bool FilterByName { get; set; }
    public string NameFrom { get; set; }
    public string NameTo { get; set; }

    public bool FilterByQuantity { get; set; }
    public double QuantityFrom { get; set; }
    public double QuantityTo { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

...然后你可以像这样构建一个查询:

public IQueryable<SomeEntity> GetQuery(FilterDefinition filter)
{
    IQueryable<SomeEntity> query = context.Set<SomeEntity>();
    // assuming that you return all records when nothing is specified in the filter

    if (filter.FilterByName)
        query = query.Where(t => 
            t.Name >= filter.NameFrom && t.Name <= filter.NameTo);

    if (filter.FilterByQuantity)
        query = query.Where(t => 
            t.Quantity >= filter.QuantityFrom && t.Quantity <= filter.QuantityTo);

    return query;
}
Run Code Online (Sandbox Code Playgroud)

  • @t-edd:不,它利用了"延迟执行"(http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx).这意味着在上面的例子中组成的`IQueryable <T>`只是一个描述如何过滤数据的查询表达式.查询的实际执行根本不在示例中.然后通过将"greedy"运算符应用于`IQueryable <T>`来执行查询,例如`query.ToList()`.此时 - 而不是更早 - 查询表达式被转换为SQL并发送到服务器. (7认同)

Bra*_*der 33

我所知道的另一种方法是根据你的过滤器vaues构建一个IQueryable.

    public List<Contact> Get(FilterValues filter)
    {
        using (var context = new AdventureWorksEntities())
        {
            IQueryable<Contact> query = context.Contacts.Where(c => c.ModifiedDate > DateTime.Now);

            if (!string.IsNullOrEmpty(filter.FirstName))
            {
                query = query.Where(c => c.FirstName == filter.FirstName);
            }

            if (!string.IsNullOrEmpty(filter.LastName))
            {
                query = query.Where(c => c.LastName == filter.LastName);
            }

            return query.ToList();
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 不,它不是性能损失,因为它使用延迟执行只查询一次. (2认同)

Gur*_*tia 7

我创建了一个应该帮助你的通用存储库.它支持统一的API来查询和排序已知和动态字段:

       //Filter on known fields
       var keyboard = Query<Product>.Create(p=>p.Category=="Keyboard");
       var keyboards = repository.Get(keyboard);

       //Or filter on dynamic fields
       var filter = Query<Product>.Create("Rating", OperationType.GreaterThan, 4)
       var filteredKeyboards = repository.Get(filter);

       //You can also combine two queries togather
       var filterdKeyboards2 = repository.Get(keyboard.And(filter))

       //Order it on known fields
       var orderedKeyboard = keyboard.OrderBy(o=>o.Asc(p=>p.Name));
       var orderedKeyboards = repository.Get(orderedKeyboard);

       //Or order by on dynamic fields
       var userOrdering = keyboard.OrderBy(o=>o.Asc("Name"));
       var orderedKeyboards2 = repository.Get(userOrdering);
Run Code Online (Sandbox Code Playgroud)

我不知道您正在获取的搜索对象/ DTO,但您可以轻松创建通用搜索对象/ DTO,并可以在几行代码中将其映射到Query对象.我过去在WCF服务中使用它,它对我来说非常好用.