Question

Essayer de faire un dépôt très simple et modèle couche de service ici. (.NET 4, C #, LINQ, bien que cette question est en partie la langue agnostique). Note:. Ce n'est que R & D

Mon but est de réduire la quantité de définitions de méthode dans ma couche de service.

Voici mon dépôt contrat:

interface IFooRepository
{
   IEnumerable<Foo> Find();
   void Insert(Foo foo);
   void Update(Foo foo);
   void Delete(Foo foo);
}

Rien de nouveau.

Maintenant, voici ce que im (essayer) d'avoir dans mon contrat de service:

interface IFooDataService
{
   public IEnumerable<Foo> Find(FooSearchArgs searchArgs);
}

Pour l'essentiel, tout « Foo » particulier possède de nombreuses propriétés (id, nom, etc.), que je voudrais être en mesure de rechercher sur.

Alors, je ne veux pas avoir 1x Trouver méthode pour chaque propriété différente, je veux juste un -. De cette façon quand je crée des propriétés supplémentaires je ne dois modifier les contrats

Les "FooSearchArgs" est un simple POCO avec toutes les différentes propriétés "Foo" il.

Alors, c'est ce que Im essayant de faire, voici mes questions:

  • Est-ce une mauvaise conception? Si oui, quelles sont les alternatives?
  • Comment puis-je mettre en œuvre ce filtrage dans la couche de service? Est-ce que je dois vérifier quelles sont les propriétés de « FooSearchArgs » sont définies, puis continuer à filtrer vers le bas? (Si cela, alors query.where, si cela, query.where, etc.) quelqu'un a une idée d'une méthode intelligente d'extension LINQ IEnumerable pour le faire? (C.-à-repository.WhereMeetsSearchCriteria(fooSearchArgs))

Appréciez l'aide.

Était-ce utile?

La solution

Nous utilisons quelque chose de très similaire. Une chose que vous devez décider est si vous allez exposer à l'extérieur IQueryable du dépôt. Votre méthode de recherche retourne IEnumerable qui pourrait être le retour de IQueryable votre clause WHEN.

L'avantage de retourner le IQueryable est que vous pouvez affiner vos critères à l'extérieur de votre couche dépôt.

repository.Find(predicate).Where(x => x.SomeValue == 1);

L'expression ne sera compilé quand vous venez d'utiliser les données renvoyées et ici dans le mensonge l'inconvénient. Parce que vous ne frappez la base de données quand vous venez d'utiliser effectivement les résultats que vous pourriez finir par essayer d'appeler la base de données après votre session (NHibernate) ou les connexions ont été fermées.

Ma préférence personnelle est d'utiliser le modèle de spécification où vous passez votre méthode de trouver un objet ISpecification est utilisé pour faire la requête.

public interface ISpecification<TCandidate>
{
    IQueryable<TCandidate> GetSatisfyingElements(IQueryable<TCandidate> source);
}

public class TestSpecification : ISpecification<TestEntity>
{
    public IQueryable<TestEntity> GetSatisfyingElements(IQueryable<TestEntity> source)
    {
        return source.Where(x => x.SomeValue == 2);
    }
}

public class ActiveRecordFooRepository: IFooRepository
{
    ...

    public IEnumerable<TEntity> Find<TEntity>(ISpecification<TEntity> specification) where TEntity : class 
    {
        ...

        return specification.GetSatisfyingElements(ActiveRecordLinq.AsQueryable<TEntity>()).ToArray();

        ...
    }

    public TEntity FindFirst<TEntity>(ISpecification<TEntity> specification) where TEntity : class 
    {
        return specification.GetSatisfyingElements(ActiveRecordLinq.AsQueryable<TEntity>()).First();
    }
}

Une fois la requête est exécuté, les appels du référentiel toArray ou ToList sur le résultat IQueryable retour de la spécification de telle sorte que la requête est évaluée puis il. Bien que cela semble moins flexible que l'exposition IQueryable il est livré avec plusieurs avantages.

  1. Les requêtes sont exécutées immédiatement et empêche un appel à la base de données faite après les séances ont fermé.
  2. Parce que vos requêtes sont maintenant intégrées dans les spécifications qu'ils sont testable.
  3. Les spécifications sont réutilisables sens vous n'avez pas la duplication de code lorsque vous essayez d'exécuter des requêtes similaires et des bugs dans les requêtes ne doivent être fixées dans un seul endroit.
  4. Avec le bon type de mise en œuvre, vous pouvez également enchaîner vos spécifications ensemble.

repository.Find(
    firstSpecification
        .And(secondSpecification)
        .Or(thirdSpecification)
        .OrderBy(orderBySpecification));

Autres conseils

passe comme paramètre Func à votre couche de service Trouvez la méthode, au lieu des FooSearchArgs, une option? Enumerables ont une méthode Where (LINQ) qui prend un Func comme paramètre, vous pouvez l'utiliser pour filtrer les résultats.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top