Criar consultas dinâmicas com a estrutura de entidades

Eu gostaria de saber qual é a melhor maneira de criar consultas dinâmicas com o entity framework e linq.

quero criar um serviço que tenha muitos parâmetros para ordenação e filtragem (mais de 50). Vou receber um objecto da gui, onde estes serão preenchidos... e a consulta será executada a partir de um único método de serviço.

Olhei em volta e vi que podia criar dinamicamente uma corda que pode ser executada no final do meu método. Não gosto muito disto. Há uma maneira melhor de fazer isto? De preferência digite seguro com verificação de compilação?

Author: Gabe Moothart, 2011-04-04

4 answers

Podias compor um IQueryable<T> passo a passo. Assumindo que você tem uma classe FilterDefinition que descreve como o usuário deseja filtrar ...

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

... então você poderia construir uma consulta assim:

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;
}
 51
Author: Slauma, 2011-04-04 16:41:54
A única outra forma que conheço seria construir um IQueryable baseado nos teus filtros.
    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();
        }
    }
 31
Author: BrandonZeider, 2011-04-04 16:33:01

Criei um repositório Genérico que deverá ajudá-lo. Ele suporta API uniforme para consulta e ordenação em ambos os campos conhecidos e dinâmicos:

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

Não sei sobre o objecto de pesquisa / DTO que está a receber, mas pode facilmente criar um objecto de pesquisa Genérico/DTO e pode mapeá-lo para um objecto de pesquisa em poucas linhas de código. Usei - o no passado em torno de um serviço WCF e funcionou muito bem para mim.

 6
Author: Gurmit Teotia, 2018-06-20 12:00:18

Você poderia olhar para a criação do serviço usando os Serviços de dados WCF e dinamicamente criar o URI para consultar o seu modelo de entidade.

 1
Author: Thomas Li, 2011-04-04 16:20:24