Как вы должны использовать шаблон UnitofWork на моем сайте asp.net-mvc (используя nhibernate и ninject) - PullRequest
11 голосов
/ 06 августа 2011

У меня есть , следуя шаблону на этом сайте , чтобы подключить ninject и nhibernate к моему сайту asp.net-mvc3.

Вот код в моем 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();
       }

проблема в том, что мне теперь нужно выполнить Update () и Add () в моих контроллерах;

У меня есть это в качестве кода моего контроллера:

    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");
    }

Мой главный вопрос заключается в том, что неправильно вводить Iunitofwork в конструкторе, так как многим другим действиям это не нужно.Мне это действительно нужно только для действий, где я делаю обновления и вставки в мою базу данных.Так как я использую недействительный IOC по вышеуказанной ссылке, кажется, что он передает этот объект unitofwork через IOC.

Итак, есть ли более оптимизированный способ использования шаблона UnitOfWork с IOC в asp.net-mvcэто вызывает транзакцию для каждого метода в моем контроллере.

Ответы [ 3 ]

12 голосов
/ 10 августа 2011

Альтернативный способ обработки транзакций - использовать IActionFilter Открыть транзакцию в OnActionExecuting и зафиксировать 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();
        }
    }
}

Определите атрибут, чтобы отметить действия, которые используют транзакцию:

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

Измените конфигурацию 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>();
    }
}

Наконец, смените контроллер:

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 голосов
/ 07 августа 2011

Я предпочитаю вводить свою единицу работы только в те классы, которые действительно их используют.В большинстве случаев постоянные классы (репозиторий в моем случае) - единственные, которым нужна единица работы.Вы хотите убедиться, что вы поддерживаете четкое разделение проблем.Контроллер не должен знать о единице работы и не должен быть связан с ней.

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

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

Если вы вызываете свой репозиторий из вашего контроллера, вставьте репозиторий в свой контроллер следующим образом:

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

Имеет ли это смысл?

0 голосов
/ 07 августа 2011

Обычно я стараюсь скрыть свою общую реализацию IRepository внутри IUnitOfWork (см. Ниже).

Моя другая рекомендация - передать UnitOfWorkProvider или UnitOfWorkFactory в конструктор. Таким образом, вы можете зарегистрировать область транзакции локально. Это дает дополнительное преимущество, заключающееся в возможности разрешать IRepository или ISession по своему усмотрению, путем внедрения зависимости или вручную.

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

Также убедитесь, что вы в IUnitOfWork.Dispose () очищаете транзакцию и любые объекты / информацию сеанса данных, которые могут у вас быть.

...