2

Я использую AutoFac для ввода конкретного контекста данных в своем веб-приложении. Я хочу выполнить метод SaveChanges() контекста базы данных в конце запроса, если на странице не было исключений. В противном случае я просто хочу избавиться от контекста как обычно.Сохранить изменения DbContext с помощью AutoFac OnRelease?

Я заметил, что AutoFac имеет метод OnRelease. Intellisense для метода заявляет:

Выполнение прилагаемого действия вместо удаления экземпляров, когда они больше не требуются.

Таким образом, я думал сделать что-то вроде этого:

builder.RegisterType<MyContext>().As<IDbContext>().InstancePerHttpRequest() 
    .OnRelease(x => { 
     if (HttpContext.Current != null && HttpContext.Current.Error == null) 
      x.SaveChanges(); 
     if (x != null) 
     { 
      x.Dispose(); 
      x = null; 
     } 
    }); 

Является ли это подходящее место для фиксации изменений для контекста данных? Гарантируется ли выполнение каждого запроса, даже если возникает исключение?

ответ

2

В общем, мне не нравится подход, когда вы сохраняете изменения по запросу, потому что здесь вы теряете гибкость. Хорошей практикой является сохранение изменений в конце бизнес-транзакции. Представьте себе, этот пример кода:

public ActionResult CreateAccount(CreateAccountModel createAccountModel) 
{ 
    // Your business transaction start here from validating and processing input data 
    var account = CreateAccountFrom(createAccountModel); 
    _yourContext.Add(account); 
    // Your business transaction ends here 
    // This is the good place to commit your transaction 
    _yourContext.SaveChanges(); 

    // You can have another business transaction here 

    // the following is not important code to log the event 
    // which could break the business transaction if it would be within one 
    // you can wrap it in try-catch for example 
    _yourContext.Add(new Event(){ Type = AccountCreated }); 
    _yourContext.SaveChanges(); 

    // code to retrieve date for the view 
    var viewModel = GetViewModel(); 
    return View(viewModel); 
} 


Теперь относительно кода, короче говоря, это плохое место, чтобы сохранить изменения. Прежде всего, вы нарушаете принцип единой ответственности, OnRelease должен очищать ресурсы на классах без IDisposable, но не выполнять дополнительную логику. Плохо поставить бизнес-логику там только потому, что вы можете это сделать. Во-вторых, если вы получаете исключение в x.SaveChanges(), ваш контекст не будет удален. Лучше не смешивать логику бизнес-логики и логику жизни объекта.

+0

Александр, спасибо за ваш ответ. У меня есть возможность называть 'SaveChanges()' в моем коде, когда это необходимо. Кроме того, не удалось ли я обернуть 'SaveChanges()' в блок try/catch/finally так же, как в остальной части моего кода, чтобы справиться с вашими заботами об удалении? – Sam

+1

@Sam «У меня есть возможность вызывать SaveChanges() в моем коде, когда это необходимо». Почему вы хотите объединить эти два подхода? Это приводит к ошибкам. «Я не могу обернуть SaveChanges() в блок try/catch/finally« Да, он будет работать, но ... :) –

Смежные вопросы