Сообщение Re[3]: Правильный Unit of work от 21.02.2020 12:14
Изменено 21.02.2020 15:24 Danchik
Re[3]: Правильный Unit of work
Здравствуйте, varenikAA, Вы писали:
AA>Здравствуйте, Danchik, Вы писали:
D>>Я вижу бредовый неполный кусок кода, нужен ли он? Без малейшего понятия.
D>>Не придумывайте себе на голову свои фреймворки, атипатерны — вижу generic repository уже освоен.
AA>Спасибо, за ответ, ну в асп-нете же жизненным циклом объектов управляет Microsoft.Extensions.DependencyInjection,
AA> юнит создается на скоуп, как только скоуп покинули, коннекш закрывается автоматом(в диспозе).
AA>И как иначе, если параллельные транзакции в большинстве субд запрещены?
Тоисть на каждый вызов метода контроллера будем стартовать транзакцию или как-то по другому использовать?
Неявный старт транзакции вам потом боком вылезет.
Как вам такой вариант?
Если Commit не вызывался, значит было исключение. В таком случае на Dispose делаем Rollback, иначе ничего не делаем.
Если все правильно написать можно, например сделать TransactionManager, пускай считает вложенность чтобы методы его использовали по DI
Думал приблизительно напишу, но вроде как рабочее решение
AA>Здравствуйте, Danchik, Вы писали:
D>>Я вижу бредовый неполный кусок кода, нужен ли он? Без малейшего понятия.
D>>Не придумывайте себе на голову свои фреймворки, атипатерны — вижу generic repository уже освоен.
AA>Спасибо, за ответ, ну в асп-нете же жизненным циклом объектов управляет Microsoft.Extensions.DependencyInjection,
AA> юнит создается на скоуп, как только скоуп покинули, коннекш закрывается автоматом(в диспозе).
AA>И как иначе, если параллельные транзакции в большинстве субд запрещены?
Тоисть на каждый вызов метода контроллера будем стартовать транзакцию или как-то по другому использовать?
Неявный старт транзакции вам потом боком вылезет.
Как вам такой вариант?
using (var tran = GetTransactionScope(db))
{
/// bla, bla
tran.Commit();
}
Если Commit не вызывался, значит было исключение. В таком случае на Dispose делаем Rollback, иначе ничего не делаем.
Если все правильно написать можно, например сделать TransactionManager, пускай считает вложенность чтобы методы его использовали по DI
public class TransactionManager : IDisposable
{
private readonly DbContext _db;
private int _nesting;
private IDbContextTransaction _transaction;
public TransactionManager(DbContext db)
{
_db = db;
}
public void Dispose()
{
_transaction?.Dispose();
}
public TransactionScope BeginTransaction()
{
if (_nesting == 0)
_transaction = _db.Database.BeginTransaction();
var scope = new TransactionScope(this);
++_nesting;
return scope;
}
private void RollbackInternal()
{
if (_transaction != null)
{
_transaction.Rollback();
_transaction.Dispose();
_transaction = null;
}
}
private void LeaveInternal()
{
if (--_nesting < 0)
throw new Exception("Invalid nesting.");
}
private void CommitInternal()
{
if (_transaction == null)
throw new Exception("Transaction not stared.");
if (_nesting == 1)
_transaction.Commit();
}
public class TransactionScope : IDisposable
{
private readonly TransactionManager _tm;
private bool _committed;
internal TransactionScope(TransactionManager tm)
{
_tm = tm;
}
public void Dispose()
{
if (!_committed)
{
// rollback ASAP
_tm.RollbackInternal();
}
_tm.LeaveInternal();
}
public void Commit()
{
_tm.CommitInternal();
_committed = true;
}
}
}
....
using (var tran1 = tm.BeginTransaction())
{
using (var tran2 = tm.BeginTransaction())
{
using (var tran3 = tm.BeginTransaction())
{
throw new Exception("Something happened.");
tran3.Commit();
}
tran2.Commit();
}
tran1.Commit();
}
Думал приблизительно напишу, но вроде как рабочее решение
Re[3]: Правильный Unit of work
Здравствуйте, varenikAA, Вы писали:
AA>Здравствуйте, Danchik, Вы писали:
D>>Я вижу бредовый неполный кусок кода, нужен ли он? Без малейшего понятия.
D>>Не придумывайте себе на голову свои фреймворки, атипатерны — вижу generic repository уже освоен.
AA>Спасибо, за ответ, ну в асп-нете же жизненным циклом объектов управляет Microsoft.Extensions.DependencyInjection,
AA> юнит создается на скоуп, как только скоуп покинули, коннекш закрывается автоматом(в диспозе).
AA>И как иначе, если параллельные транзакции в большинстве субд запрещены?
Тоисть на каждый вызов метода контроллера будем стартовать транзакцию или как-то по другому использовать?
Неявный старт транзакции вам потом боком вылезет.
Как вам такой вариант?
Если Commit не вызывался, значит было исключение. В таком случае на Dispose делаем Rollback, иначе ничего не делаем.
Если все правильно написать можно, например сделать TransactionManager, пускай считает вложенность чтобы методы его использовали по DI
Думал приблизительно напишу, но вроде как рабочее решение
AA>Здравствуйте, Danchik, Вы писали:
D>>Я вижу бредовый неполный кусок кода, нужен ли он? Без малейшего понятия.
D>>Не придумывайте себе на голову свои фреймворки, атипатерны — вижу generic repository уже освоен.
AA>Спасибо, за ответ, ну в асп-нете же жизненным циклом объектов управляет Microsoft.Extensions.DependencyInjection,
AA> юнит создается на скоуп, как только скоуп покинули, коннекш закрывается автоматом(в диспозе).
AA>И как иначе, если параллельные транзакции в большинстве субд запрещены?
Тоисть на каждый вызов метода контроллера будем стартовать транзакцию или как-то по другому использовать?
Неявный старт транзакции вам потом боком вылезет.
Как вам такой вариант?
using (var tran = GetTransactionScope(db))
{
/// bla, bla
tran.Commit();
}
Если Commit не вызывался, значит было исключение. В таком случае на Dispose делаем Rollback, иначе ничего не делаем.
Если все правильно написать можно, например сделать TransactionManager, пускай считает вложенность чтобы методы его использовали по DI
public class TransactionManager : IDisposable
{
private readonly DbContext _db;
private int _nesting;
private IDbContextTransaction _transaction;
public TransactionManager(DbContext db)
{
_db = db;
}
public void Dispose()
{
_transaction?.Dispose();
}
public TransactionScope BeginTransaction()
{
if (_nesting == 0)
_transaction = _db.Database.BeginTransaction();
var scope = new TransactionScope(this);
++_nesting;
return scope;
}
private void RollbackInternal()
{
if (_transaction != null)
{
_transaction.Rollback();
_transaction.Dispose();
_transaction = null;
}
}
private void LeaveInternal()
{
if (--_nesting < 0)
throw new Exception("Invalid nesting.");
}
private void CommitInternal()
{
if (_transaction == null)
throw new Exception("Transaction not stared. Possible you have forgot to call Commit() in nested scope.");
if (_nesting == 1)
_transaction.Commit();
}
public class TransactionScope : IDisposable
{
private readonly TransactionManager _tm;
private bool _committed;
internal TransactionScope(TransactionManager tm)
{
_tm = tm;
}
public void Dispose()
{
if (!_committed)
{
// rollback ASAP
_tm.RollbackInternal();
}
_tm.LeaveInternal();
}
public void Commit()
{
_tm.CommitInternal();
_committed = true;
}
}
}
....
using (var tran1 = tm.BeginTransaction())
{
using (var tran2 = tm.BeginTransaction())
{
using (var tran3 = tm.BeginTransaction())
{
throw new Exception("Something happened.");
tran3.Commit();
}
tran2.Commit();
}
tran1.Commit();
}
Думал приблизительно напишу, но вроде как рабочее решение