10
votes

LINQ to SQL - Comment faire efficacement une et une recherche de critères multiples

J'ai un site ASP.NET MVC (qui utilise LINQ vers SQL pour l'ORM) et une situation dans laquelle un client souhaite une facilité de recherche sur une base de données sur mesure selon laquelle ils peuvent choisir de faire une "et" de la recherche (tous les critères correspondance) ou une recherche 'ou' ou une correspondance de critères). La requête est assez complexe et longue et je veux savoir s'il y a un moyen simple, je peux le faire faire à la fois sans avoir à créer et à conserver deux versions différentes de la requête.

Par exemple, la recherche actuelle "et" regarde quelque chose comme ça (mais c'est un beaucoup version simplifiée): xxx

je pourrais copier cela et remplacer le && avec || opérateurs pour obtenir la version 'ou' ', mais que vous sentez qu'il doit y avoir une meilleure façon de la réaliser. Quelqu'un a-t-il des suggestions comment cela peut être réalisé de manière efficace et flexible qui est facile à entretenir? Merci.


0 commentaires

7 Réponses :


1
votes

1 commentaires

J'avais regardé cela - mais j'espérais un moyen de maintenir les avantages d'une expression fortement dactylographiée.



2
votes

Vous pouvez créer une méthode d'extension le long des lignes de

bool isOr = true; //or false
var results = Data.BoolWhere(r => r.Id == criteria.SampleId, isOr)
  .BoolWhere(r => r.Status.SampleStatusId == criteria.SampleStatusId, isOr)
  .BoolWhere(r => r.Job.JobNumber.StartsWith(criteria.JobNumber), isOr)
  .BoolWhere(r => r.Description.Contains(criteria.Description), isOr)


0 commentaires

1
votes

Peut-être plus simple que l'idée de Jens à visualiser, si vous recherchez seulement combiné ou combiné et (et non un mélange), vous pouvez toujours exprimer votre égalité comme une liste de tests, puis appliquer le tout ou tous les opérateurs à cela. Par exemple:

var queries = new List<Func<Table,SampleListDto,bool>>{
      ((a,b) => a.Id == b.SampleId),
      ((a,b) => a.Status.SampleStatusId == b.SampleStatusId),
      ((a,b) => a.Job.JobNumber.StartsWith(b.JobNumber)),
      ((a,b) => a.Description.Contains(b.Description))
};

var results = Table.Where(t=> queries.All(q => q(t, criteria)); // returns the && case
// or:  var results = Table.Where(t=>queries.Any(q=>q(t,criteria));


0 commentaires

1
votes

Voici des informations sur PredicateBuilder

Ceci doit être compatible avec Linq à SQL. < P> Une nouvelle fonction pourrait être créée pour utiliser les fonctions du prédicatbuilder et ou ou: xxx

Les et les fonctions ressemblaient à: xxx < / pré>


0 commentaires

2
votes

Si vous avez ces méthodes d'extension: xxx

alors vous pouvez déclarer vos instructions sous forme de liste: xxx

et écrivez votre requête comme: xxx

ou pour le || version: xxx

et il suffit de maintenir les déclarations dans un endroit.


1 commentaires

C'est une autre idée intelligente et fonctionne très bien avec des objets. Malheureusement, encore une fois, il a besoin de travailler avec iquérissable et non itinérable de tenir une chance d'être convertie en SQL. J'ai essayé de changer les méthodes d'extension, mais je n'ai aucune joie. Merci de la suggestion, cependant.



1
votes

Vous pouvez utiliser un modèle T4 pour générer chaque méthode. De cette façon, vous aurez toujours des expressions fortement typées. Cliquez avec le bouton droit de la souris sur votre projet et sélectionnez Ajouter-> Nouvel élément-> Modèle de texte

Le modèle serait en boucle comme suit: P>

<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ output extension=".cs" #>

namespace YourNamespaceName
{
    public partial class YourClassName
    {
    <# Generate(true); #>
    <# Generate(false); #>
    }
}
<#+
    private void Generate(bool isOr)
    {
        string op = isOr ? "||" : "&&";
        string methodName = "GetSampleSearchQuery" + (isOr ? "Or" : "And");
#>
    private IQueryable<SampleListDto> <#= methodName #>(SamplesCriteria criteria)
    {
        var results = from r in Table where
                (r.Id == criteria.SampleId) <#= op #>
                (r.Status.SampleStatusId == criteria.SampleStatusId) <#= op #>
                (r.Job.JobNumber.StartsWith(criteria.JobNumber)) <#= op #>
                (r.Description.Contains(criteria.Description))
            select r;
        return results;
    }
<#+
    }
#>


1 commentaires

C'est une idée intelligente! Idéalement, je préfère le faire par programmation, mais cela semble la prochaine meilleure idée. Aussi une bonne illustration de ce que vous pouvez faire via des modèles T4.



1
votes

Vous pouvez utiliser la technique expliquée dans Cette réponse . La méthode compose peut être appelée ainsi: - first.compose (deuxième, expression.et); ou first.compose (deuxième, expression.or);

Le type d'opération devient donc un paramètre.

En l'appliquant à plusieurs reprises à toutes vos clauses, vous pouvez construire l'expression requise, et c'est tout le code d'expression parfaitement saisi et pure.


0 commentaires