11

J'ai le followed the pattern on this site pour connecter ninject et nhibernate à mon site asp.net-mvc3.Comment utiliser le modèle UnitofWork sur mon site asp.net-mvc (en utilisant nhibernate et ninject)

Voici le code dans mes global.aspx.cs:

internal class ServiceModule : NinjectModule 
{ 
    public override void Load() 
    { 
     var helper = new NHibernateHelper(connectionString); 
     Bind<ISessionFactory>().ToConstant(helper.SessionFactory) 
      .InSingletonScope(); 

     Bind<IUnitOfWork>().To<UnitOfWork>() 
      .InRequestScope(); 
     Bind<ISession>().ToProvider(new SessionProvider()) 
      .InRequestScope(); 
     Bind<IIntKeyedRepository<FAQ>>().To<Repository<FAQ>>() 
      .InRequestScope(); 
     } 

la question est que je dois maintenant faire de mise à jour() et Add() dans mes contrôleurs;

Je possède ce que mon code de contrôleur:

public FAQController(IIntKeyedRepository<FAQ> faqRepository, IUnitOfWork unitOfWork) 
    { 
     _faqRepository = faqRepository; 
     _unitOfWork = unitOfWork; 
    } 


    [Authorize] 
    [AcceptVerbs(HttpVerbs.Post)] 
    [ValidateInput(false)] 
    public ActionResult AddFAQ(FAQ contact) 
    { 
     var c = new FAQ {Question = contact.Question, Answer = contact.Answer}; 
     _faqRepository.Add(c); 
     _unitOfWork.Commit(); 
     return RedirectToAction("Index"); 
    } 

ma question principale est qu'il se sent mal à passer Iunitofwork dans le constructeur que de nombreuses autres actions ne ont pas besoin. Je n'en ai vraiment besoin que pour les actions où je fais des mises à jour et des insertions dans mon db. Puisque j'utilise le CIO de ninject sur le lien ci-dessus, il semble dire de passer cet objet unitofwork à travers IOC. Donc, y a-t-il une meilleure façon d'optimiser l'utilisation du pattern UnitOfWork avec IOC dans asp.net-mvc qui appelle beingtransaction pour chaque méthode de mon controller.

+0

Jetez un oeil à [ce] (http://blog.xelibrion.com/journal/2011/4/16/nhibernate-session-management-in-aspnet-mvc -application.html) article de blog. – xelibrion

Répondre

12

Une autre façon de gérer les transactions consiste à utiliser un IActionFilter Ouvrez la transaction dans OnActionExecuting et engager sur OnActionExecuted

public class TransactionFilter : IActionFilter 
{ 
    private readonly ISession session; 
    private ITransaction transaction; 

    public TransactionFilter(ISession session) 
    { 
     this.session = session; 
    } 

    public void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     this.transaction = this.session.BeginTransaction(); 
    } 

    public void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     try 
     { 
      if (this.transaction.IsActive) 
      { 
       if (filterContext.Exception == null) 
       { 
        this.transaction.Commit(); 
       } 
       else 
       { 
        this.transaction.Rollback(); 
       } 
      } 
     } 
     finally 
     { 
      this.transaction.Dispose(); 
     } 
    } 
} 

Définir un attribut pour marquer les actions qui utilisent une transaction:

[AttributeUsage(AttributeTargets.Method)] 
public class TransactionAttribute : Attribute 
{ 
} 

changer votre configuration Ninject:

internal class ServiceModule : NinjectModule 
{ 
    public override void Load() 
    { 
     var helper = new NHibernateHelper(connectionString); 
     Bind<ISessionFactory>().ToConstant(helper.SessionFactory) 
      .InSingletonScope(); 

     Bind<ISession>().ToProvider<SessionProvider>().InRequestScope(); 
     Bind(typeof(IRepository<>)).To(typeof(Repository<>)); 
     Bind(typeof(IIntKeyedRepository<>)).To(typeof(Repository<>)); 
     BindFilter<TransactionFilter>(FilterScope.Action, null) 
      .WhenActionMethodHas<TransactionAttribute>(); 
    } 
} 

enfin changer votre contrôleur:

public FAQController(IIntKeyedRepository<FAQ> faqRepository) 
{ 
    _faqRepository = faqRepository; 
} 


[Transaction] 
[Authorize] 
[AcceptVerbs(HttpVerbs.Post)] 
[ValidateInput(false)] 
public ActionResult AddFAQ(FAQ contact) 
{ 
    var c = new FAQ {Question = contact.Question, Answer = contact.Answer}; 
    _faqRepository.Add(c); 
    return RedirectToAction("Index"); 
} 
+0

C'est exactement ce que je cherchais. Ayende proposé presque la même solution: http://ayende.com/blog/4809/refactoring-toward-frictionless-odorless-code-what-about-transactions Mais je préfère injecter la session sur la demande du contrôleur. – Tim

0

En général, j'essaie de cacher mon implémentation IRepository générique dans IUnitOfWork (voir ci-dessous).

Mon autre recommandation est de passer un UnitOfWorkProvider ou un UnitOfWorkFactory au constructeur. De cette façon, vous pouvez enregistrer la portée de la transaction localement. Cela a l'avantage supplémentaire de pouvoir résoudre IRepository ou ISession comme bon vous semble, via une injection de dépendance ou manuellement.

using(var uow = this.UnitOfWorkProvider.New()) 
{ 
    uow.Save<Faq>(myFaq); 
} 

vous aussi que dans votre IUnitOfWork.Dispose() vous nettoyer la transaction et des objets de session de données/informations que vous pourriez avoir.

0

Je préfère injecter mon unité de travail dans des classes qui les utilisent réellement. Dans la plupart des cas, les classes de persistance (référentiel dans mon cas) sont les seules qui nécessitent l'unité de travail. Vous voulez vous assurer de maintenir une séparation nette des préoccupations. Le contrôleur n'a pas besoin de connaître l'unité de travail et ne doit pas non plus être couplé à celui-ci.

public class FaqRepository { 
    public FaqRepository(IUnitOfWork unitofWork) { ... } 

    public void CreateQuestion(Faq faq) { 
    unitOfWork.Save(faq); 
    unitOfWork.Commit(); 
    } 
} 

Si vous appeler votre dépôt de votre contrôleur, injecter le dépôt dans votre contrôleur comme suit:

public class FaqController { 
    public FaqController(IFaqRepository faqRepository) {...} 
} 

Est-ce que sens?

+0

Le problème que je vois avec ceci est que votre Repository est maintenant responsable de l'UoW. Si vous deviez apporter des modifications nécessitant deux référentiels, vous allez rencontrer des problèmes. – Phill

+0

@Phil - pouvez-vous élaborer? – csano

+0

Si votre UOW tombe sur deux objets, par exemple, UserLogin et UserProfile étant stockés séparément, aucune cascade, il est sur deux référentiels, et que vous voulez exécuter à la fois dans la transaction. Votre référentiel valide actuellement la transaction, vous devez donc exécuter deux unités de travail distinctes. – Phill

Questions connexes