Question

J'installe actuellement un nouveau projet, et j'ai rencontré quelques petites choses, où je besoin d'un peu d'influence.

est ce que je considère:

  • Je voudrais un référentiel générique

  • Je ne veux pas retourner IQueryable de mon dépôt.

  • Je voudrais résumer mes questions dans les spécifications.

  • I ai mis en place le modèle de spécification

  • Il doit être facilement testable

Maintenant, c'est là que je suis un peu coincé et ma question est de quelle manière serait la façon la plus élégante d'appeler la méthode de recherche avec une ou plusieurs spécifications:

(courant): bannerRepository.Find().IsAvailableForFrontend().IsSmallMediaBanner()

ou exprimer des requêtes comme lambdas avec mes spécifications

(Lambda): bannerRepository.Find.Where(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner)

ou peut-être d'une manière tout à fait autre? La chose la plus importante est que le gars avant la mise en œuvre du MVC, devrait avoir une bonne expérience intuitive du référentiel.

Qu'est-ce que j'espère atteindre est de maintenir la flexibilité de som en matière de pouvoir combiner des spécifications, et donner l'expérience de « filtrage » avec les specfications, mais sans fuite IQueryable au contrôleur, mais plus comme un ISpecifiable, qui permet uniquement de modifier la requête avec les spécifications et non avec LINQ. Mais suis-je juste de retour à une fuite logique de requête au contrôleur de cette façon?

Était-ce utile?

La solution

Je l'ai vu quelques API Courant de qui utilise les propriétés des spécifications, donc ils ne pas ajouter le bruit de parenthèses aux clients.

bannerRepository.Find.IsAvailableForFrontend.IsSmallMediaBanner.Exec()

Exec Being () une méthode pour l'exécution des spécifications sur le repo.

mais même si vous n'utilisez pas les propriétés, je pencherais pour l'API couramment, car il a le bruit minimum.

Autres conseils

  

ou peut-être une autre façon tout à fait?

Eh bien, en fait je ne comprends pas exactement votre mise en œuvre du référentiel (par exemple ce sera la méthode .Find() retour?), Mais je choisirais une autre direction:

public class Foo 
{ 
    public Int32 Seed { get; set; }
}

public interface ISpecification<T> 
{
    bool IsSatisfiedBy(T item);
}

public interface IFooSpecification : ISpecification<Foo> 
{
    T Accept<T>(IFooSpecificationVisitor<T> visitor);
}

public class SeedGreaterThanSpecification : IFooSpecification
{
    public SeedGreaterThanSpecification(int threshold)
    {
        this.Threshold = threshold;
    }
    public Int32 Threshold { get; private set; }
    public bool IsSatisfiedBy(Foo item) 
    {
        return item.Seed > this.Threshold ;
    }
    public T Accept<T>(IFooSpecificationVisitor<T> visitor)
    {
        return visitor.Visit(this);
    }
}
public interface IFooSpecificationVisitor<T>
{
    T Visit(SeedGreaterThanSpecification acceptor);
    T Visit(SomeOtherKindOfSpecification acceptor);
    ...
}
public interface IFooRepository 
{
    IEnumerable<Foo> Select(IFooSpecification specification);
}
public interface ISqlFooSpecificationVisitor : IFooSpecificationVisitor<String> { }
public class SqlFooSpecificationVisitor : ISqlFooSpecificationVisitor
{
    public string Visit(SeedGreaterThanSpecification acceptor)
    {
        return "Seed > " + acceptor.Threshold.ToString();
    }
    ...
}
public class FooRepository
{   
    private ISqlFooSpecificationVisitor visitor;

    public FooRepository(ISqlFooSpecificationVisitor visitor)
    {
        this.visitor = visitor;
    }

    public IEnumerable<Foo> Select(IFooSpecification specification)
    {
        string sql = "SELECT * FROM Foo WHERE " + specification.Accept(this.visitor);
        return this.DoSelect(sql);
    }

    private IEnumerable<Foo> DoSelect(string sql)
    {
        //perform the actual selection;
    }
}

J'ai donc une entité, son interface de spécification et plusieurs implementors impliqués dans un schéma de visiteur, son interface référentiel acceptant une interface de spécification et la mise en œuvre du référentiel, en acceptant un visiteur capable de traduire les spécifications en clauses SQL (mais il est juste une question de ce cas, bien sûr). Enfin, je compose la spécification "en dehors" l'interface de référentiel (en utilisant interface fluide).

Peut-être que cela est juste une idée naïve, mais je trouve assez simple. Espérons que cela aide.

Personnellement, j'aller avec la manière lambda. Peut-être à cause de mon amour pour lambda, mais il fournit son lot d'espace pour une configuration de référentiel générique.

considérant ce qui suit:

bannerRepository.Find.Where(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner)

Je ne sais pas ce que votre modèle ressemble mais vous pouvez factoriser certaines choses ici:

Créer une interface générique appelée « IRepository » de type contenant toutes les méthodes d'accès aux données.

Il pourrait ressembler à ceci:

interface IRepository<T> where T : class
{
    IEnumerable<T> FindAll(Func<T, bool> exp);

    T FindSingle(Func<T, bool> exp);
}   

Créer une classe 'Repository' abstraite implémentant cette interface:

class Repository<T> : IRepository<T> where T : class
{
    TestDataContext _dataContext = TestDataContext();

    public IEnumerable<T> FindAll(Func<T, bool> exp)
    {
        _dataContext.GetTable<T>().Where<T>(exp);
    }

    public T FindSingle(Func<T, bool> exp)
    {
        _dataContext.GetTable<T>().Single(exp);
    }
}

Nous pouvons maintenant créer une interface pour la table bannières / objets qui met en œuvre notre « IRepository » et une classe concrète extension de la classe abstraite « référentiel » et la mise en œuvre du « IBannerInterface »:

interface IBannerRepository : IRepository<Banner>
{
}

Et le dépôt correspondant à la mettre en œuvre:

class BannerRepository : Repository<Banner>, IBannerRepository
{
}

Je suggère d'utiliser cette approche car il vous donne beaucoup de flexibilité, ainsi que suffisamment de puissance pour contrôler toutes les petites entités que vous avez.

L'appel à ces méthodes sera super facile de cette façon:

BannerRepository _repo = new BannerRepository();

_repo.FindSingle(banner => banner.IsFrontendCampaignBanner && banner.IsSmallMediaBanner);

Oui, cela signifie que vous avez à faire un peu de travail, mais il est l'enfer plus facile pour vous de changer la source de données plus tard.

it helps!

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