2010-09-28 7 views
4

Je développe une application Web dans ASP.NET MVC avec NHibernate.Comment créer un référentiel générique

Basé sur des articles et des tutoriels que j'ai trouvés sur Google, j'utilise Repository pour mes cours.

J'ai 10 classes et 10 dépôts. Aujourd'hui, j'ai compris que 90% des dépôts miniers sont exactement égaux, sauf pour la classe. Ceci est un exemple:

public class PromocaoRepository:IPromocaoRepository { 
    private ISession Session; 

    public PromocaoRepository() { 
     this.Session = NHibernateSessionFactory.OpenSession(); 
    } 

    public void Add(Promocao promocao) { 
     using(ITransaction transaction = this.Session.BeginTransaction()) { 
      this.Session.Save(promocao); 
      transaction.Commit(); 
     } 
    } 

    public void Edit(Promocao promocao) { 
     using(ITransaction transaction = this.Session.BeginTransaction()) { 
      this.Session.Update(promocao); 
      transaction.Commit(); 
     } 
    } 

    public void Remove(Promocao promocao) { 
     using(ITransaction transaction = this.Session.BeginTransaction()) { 
      this.Session.Delete(promocao); 
      transaction.Commit(); 
     } 
    } 

    public Promocao GetById(int id) { 
     return this.Session.Get<Promocao>(id); 
    } 

} 

Il y a une façon de faire une sorte de sorcière de référentiel générique je peux utiliser dans tous mes cours?

Si c'est possible, que dois-je faire au cas où je devrais créer une méthode particulière pour une classe spécifique?

+0

duplication possible de [Utilisation d'un modèle de référentiel générique avec nHibernate fluide] (http://stackoverflow.com/questions/2587965/using-a-generic-repository-pattern-with-fluent-nhibernate) - comme vous pouvez le voir 75% des réponses sont liées à une réponse existante – jfar

Répondre

4

Vous devez créer un référentiel générique, que vous pouvez utiliser dans le cas général, et si des méthodes supplémentaires sont nécessaires pour une classe particulière, ajoutez-le en utilisant l'héritage. En utilisant votre exemple:

public class GenericRepository<TEntity> :IGenericRepository<TEntity> { 
    private ISession Session; 

    public GenericRepository() { 
     this.Session = NHibernateSessionFactory.OpenSession(); 
    } 

    public void Add(TEntity instance) { 
     using(ITransaction transaction = this.Session.BeginTransaction()) { 
      this.Session.Save(instance); 
      transaction.Commit(); 
     } 
    } 

    /* other methods */ 
} 

public class SpecificRepository : GenericRepository<SpecificEntity>, ISpecificRepository 
{ 
    public void SpecialQuery() { /* added method implementation */ } 
} 
+0

Merci! Je devais juste définir ma session ISession comme protégée/publique pour les dépôts d'enfants. – MCardinale

6

De another thread:

public interface IRepository<T> : IQueryable<T> 
{ 
    void Add(T entity); 
    T Get(Guid id); 
    void Remove(T entity); 
} 

public class Repository<T> : IQueryable<T> 
{ 
    private readonly ISession session; 

    public Repository(ISession session) 
    { 
    session = session; 
    } 

    public Type ElementType 
    { 
    get { return session.Query<T>().ElementType; } 
    } 

    public Expression Expression 
    { 
    get { return session.Query<T>().Expression; } 
    } 

    public IQueryProvider Provider 
    { 
    get { return session.Query<T>().Provider; } 
    } 

    public void Add(T entity) 
    { 
    session.Save(entity); 
    } 

    public T Get(Guid id) 
    { 
    return session.Get<T>(id); 
    } 

    IEnumerator IEnumerable.GetEnumerator() 
    { 
    return this.GetEnumerator(); 
    } 

    public IEnumerator<T> GetEnumerator() 
    { 
    return session.Query<T>().GetEnumerator(); 
    } 

    public void Remove(T entity) 
    { 
    session.Delete(entity); 
    } 
} 
+0

Jamais pensé à faire hériter le référentiel IQueryable . Des mises en garde à cela? – mxmissile

+0

Il n'hérite pas mais implémente, IQueryable est une interface. Et ce qu'il fait est simplement de transférer des appels à la session. Query qui a déjà intégré l'implémentation LINQ IQueryable. –

+0

C'est presque le code exact que j'utilise et je l'aime. – Ryan

2

Jetez un oeil à ma réponse à la question "Asp.net MVC 2 Entity Framework Generic Repository Method. how to Update a specific Collumn" - cela devrait vous donner une bonne idée de ce qu'il faut faire.

HTHS, Charles

PAR EXEMPLE

Modèle de base:

public interface IDbTable 
{ 
    int Id { get; set; } 
    DateTime DateCreated { get; set; } 
    DateTime DateUpdated { get; set; } 
} 

public class DbTable 
{ 
    public int Id { get; set; } 
    public DateTime DateCreated { get; set; } 
    public DateTime DateUpdated { get; set; } 
} 

Votre modèle

public class Category : DbTable 
{ 
    public string Name { get; set; } 
} 

Votre dépôt

public interface IBaseRepository<T> where T : class, IDbTable 
{ 
    void Add<T>(T entity); 
    void Edit<T>(T entity); 
    void Remove<T>(T entity); 
    T GetById(int id); 
} 

public class BaseRepository<T> : IBaseRepository<T> 
{ 
    private ISession Session; 

    public BaseRepository() 
    { 
     this.Session = NHibernateSessionFactory.OpenSession(); 
    } 

    public void Add(T entity) 
    { 
     entity.DateCreated = DateTime.UtcNow; 
     entity.DateUpdated = DateTime.UtcNow; 

     using(ITransaction transaction = this.Session.BeginTransaction()) 
     { 
      this.Session.Save(entity); 
      transaction.Commit(); 
     } 
    } 

    public void Edit(T entity) 
    { 
     entity.DateUpdated = DateTime.UtcNow; 

     using(ITransaction transaction = this.Session.BeginTransaction()) 
     { 
      this.Session.Update(entity); 
      transaction.Commit(); 
     } 
    } 

    public void Remove(T entity) 
    { 
     using(ITransaction transaction = this.Session.BeginTransaction()) 
     { 
      this.Session.Delete(entity); 
      transaction.Commit(); 
     } 
    } 

    public T GetById(int id) 
    { 
     return this.Session.Get<T>(id); 
    } 
} 

Oh, et permet de ne pas oublier la mise en œuvre concrète

public interface ICategoryRepository : IBaseRepository<Category> 
{ 
    Category GetCategoryByName(string categoryName); 
} 

public CategoryRepository : BaseRepository<Category> 
{ 
    public Category GetCategoryByName(string categoryName) 
    { 
     //blah 
    } 
} 
3

Voici ma réponse à une question similaire (28 votes À partir de maintenant):

Advantage of creating a generic repository vs. specific repository for each object?

L'idée est de genericize la mise en œuvre, et non pas l'interface. Au lieu d'une interface de référentiel générique orientée vers l'extérieur, créez une classe de base de référentiel générique orientée vers l'intérieur, que vous utilisez pour implémenter facilement des interfaces spécifiques aux entités.

Edit: Je tiens à souligner que les dépôts génériques servent une fonction très différente que des référentiels spécifiques. Les référentiels sont destinés à encapsuler les mécanismes d'accès aux données derrière les requêtes de l'entité, y compris toute la logique de requête. Un référentiel générique encapsule la possibilité de créer des requêtes, mais il n'encapsule aucune requête spécifique concernant une entité.

Le but est de ne pas rendre les utilisateurs du référentiel responsables de l'écriture de leurs propres requêtes. Un référentiel générique vit au même niveau d'abstraction qu'un ORM; un dépôt spécifique vit à un niveau supérieur à celui-ci.

Questions connexes