Je voudrais savoir quelle est la meilleure façon de créer des requêtes dynamiques avec framework d'entité et linq.
Je veux créer un service qui possède de nombreux paramètres de tri et de filtrage (plus de 50). Je recevrai un objet de gui où ceux-ci seront remplis ... et la requête sera exécutée à partir d'une seule méthode de service.
J'ai regardé autour de moi et j'ai vu que je pouvais créer dynamiquement une chaîne qui peut être exécutée à la fin de ma méthode. Je n'aime pas beaucoup ça. Y a-t-il une meilleure manière de faire cela? Tapez de préférence sûr avec vérification de la compilation?
Vous pouvez composer un IQueryable<T>
pas à pas. En supposant que vous avez une classe FilterDefinition
qui décrit comment l'utilisateur veut filtrer ...
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; }
}
... alors vous pouvez créer une requête comme ceci:
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;
}
La seule autre façon que je connaisse serait de construire un IQueryable basé sur vos filtres vaues.
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();
}
}
J'ai créé un référentiel générique qui devrait vous aider. Il prend en charge une API uniforme pour interroger et trier sur les champs connus et dynamiques:
//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);
Je ne connais pas l'objet de recherche/DTO que vous obtenez, mais vous pouvez facilement créer un objet de recherche/DTO générique et le mapper à un objet Query en quelques lignes de code. Je l'ai utilisé dans le passé autour d'un service WCF et cela a très bien fonctionné pour moi.
Vous pouvez examiner la création du service à l'aide de WCF Data Services et créer dynamiquement l'URI pour interroger votre modèle d'entité.