Criar consultas dinâmicas com a estrutura de entidades
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?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;
}
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();
}
}
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.
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.