Проблема с транзакциями
От: bolikdimon  
Дата: 10.01.08 09:20
Оценка:
Добрый день.
У меня следующая проблема.
Есть DAL класс, наследуемый от DataAccessor, в нем объявлен абстрактный метод:

[SprocName("Projects_Insert")]
public abstract override int Insert(Project project);

Из класса бизнес логики вызываю этот метод, все работает нормально. Но как только пытаюсь поместить его в пределы транзакции он перестает работать.

Делаю следующее — в DAL классе переопределяю метод GetDbManager():

private static DbManager db = new DbManager();
public override DbManager GetDbManager()
{
return db;
}

т.е. теперь он гарантированно возвращает один и тот же экземпляр DbManager.
В классе бизнес логики получаю ссылку на db и заворачиваю все в транзакцию:

DbManager db = DAL.GetDbManager();
db.BeginTransaction();
projectId = DAL.Insert(project);
db.CommitTransaction();

Так вот почему то этот код не работает, т.е. данные не вставляются. При этом в методе Insert используется тот же DbManager что и при открытии и коммите транзакции, т.к. если смотреть выполнение под дебагером, то перед вызовом Insert вызывается переопределенный GetDbManager(). Кроме того если б для Insert использовался другой DbManager, запись вставлялась бы по любому, т.к. вставка была бы не внутри транзакции. Такое чувство возникает, будто абстрактная реализация метода что-то делает с объектом DbManager и транзакция открывается нормально но вот не коммитится.
Если же метод в DAL классе сделать не абстрактным и то все работает.
В чем может быть проблема?

Спасибо.

P.S. Транзакция мне нужна для того чтобы потом добавить еще несколько обращений к БД, т.е. один метод внутри транзакции — это пока для теста.
Re: Проблема с транзакциями
От: Sashko Россия http://www.dc.baika.ru/
Дата: 10.01.08 09:59
Оценка:
Здравствуйте, bolikdimon, Вы писали:

B>Если же метод в DAL классе сделать не абстрактным и то все работает.

B>В чем может быть проблема?

у тебя твой DbManager диспозится в конце вызова Insert. Ты попробуй ещё раз дернуть Insert и увидешь что он сфалит. А так как транзакция не была покоммичена, то в диспозе она откатывается.

Посмотри пропертю

public virtual bool  DisposeDbManager


и метод

protected internal void SetDbManager(DbManager dbManager, bool dispose)


у DataAccessBase

Да, а генерёные методы акцессора оканчиваются примерно так

    finally
    {
        if ((dbManager != null) && this.get_DisposeDbManager())
        {
            dbManager.Dispose();
        }
    }
Re: Проблема с транзакциями
От: Sashko Россия http://www.dc.baika.ru/
Дата: 10.01.08 10:05
Оценка:
вдруг пригодится

DataAccessorEx — реализует 3ри способа создания DbManager'а, а так же временное кеширование созданного DbManager'а, как раз для реализации транзакции. Перед началом транзации вызывается CacheDbManager(), по окончанию ReleaseCachedDbManager(). Да BeginTransaction и CommitTransaction нужно вызывать явно. Хотя можно добавить к акцессору BeginTransaction() и [Commit/Rollback]Transaction() а внутри них кешировать созданный DbManager.

    public class DbManagerCreationException : DataException
    {
        public DbManagerCreationException() 
            : base("An BLToolkit Database Manager creation failure.")
        {
        }

        public DbManagerCreationException(String message) 
            : base(message) 
        {
        }

        public DbManagerCreationException(String message, Exception innerException) 
            : base(message, innerException) 
        {
        }

        public DbManagerCreationException(Exception innerException) 
            : base(innerException.Message, innerException) 
        {
        }

        protected DbManagerCreationException(SerializationInfo info, StreamingContext context) 
            : base(info, context) 
        {
        }
    }

    public delegate DbManager DbManagerCreator(Object argument);

    public abstract class DataAccessorEx : BLToolkit.DataAccess.DataAccessor
    {
        protected override DbManager CreateDbManager()
        {
            try
            {
                DbManager db =
                    (null != _dbManagerCreator
                        ? _dbManagerCreator(_dbManagerCreatorArgument)
                        : (!String.IsNullOrEmpty(_configurationString)
                            ? new DbManager(_configurationString)
                            : base.CreateDbManager()
                            )
                    );

                if (null != db)
                {
                    if (_refCount > 0)
                        SetDbManager(db, false);
                    return db;
                }
            }
            catch (DbManagerCreationException)
            {
                throw;
            }
            catch (Exception ex)
            {
                throw new DbManagerCreationException(ex);
            }
            throw new DbManagerCreationException();
        }

        public void CacheDbManager()
        {
            CacheDbManager(true);
        }

        public void CacheDbManager(Boolean immediateCreadeDbManager)
        {
            if (0 == _refCount)
            {
                DbManager db = (immediateCreadeDbManager ? CreateDbManager() : null);

                _saveDbManager = DbManager;
                _saveDisposeDbManager = DisposeDbManager;
                SetDbManager(db, false);
            }
            _refCount++;
        }

        public void ReleaseCachedDbManager()
        {
            if (_refCount > 0 && 0 == --_refCount)
            {
                if (null != DbManager)
                    DbManager.Dispose();

                SetDbManager(_saveDbManager, _saveDisposeDbManager);
                _saveDbManager = null;
                _saveDisposeDbManager = true;
            }
        }

        public static T CreateInstance<T>(String configurationString)
            where T : DataAccessorEx
        {
            T da = CreateInstance<T>();

            da._configurationString = configurationString;
            return da;
        }

        public static T CreateInstance<T>(DbManagerCreator dbManagerCreator, Object dbManagerCreatorArgument)
            where T : DataAccessorEx
        {
            T da = CreateInstance<T>();

            da._dbManagerCreator = dbManagerCreator;
            da._dbManagerCreatorArgument = dbManagerCreatorArgument;
            return da;
        }

        private String _configurationString;
        private DbManagerCreator _dbManagerCreator;
        private Object _dbManagerCreatorArgument;

        private UInt32 _refCount = 0;
        private DbManager _saveDbManager = null;
        private Boolean _saveDisposeDbManager = true;
    }
Re: Проблема с транзакциями
От: bolikdimon  
Дата: 10.01.08 10:39
Оценка:
Спасибо за помощь. Помог следующий вариант:
В классе бизнес логики создал новый DbManager и этот же экзампляр использовал и в конструкторе аксессора DAL класса, т.е.
DbManager db = new DbManager();
DAL dal = DAL.CreateInstance(db);
db.BeginTransaction();
dal.Insert(...);
db.CommitTransaction();
Re: Проблема с транзакциями
От: IT Россия linq2db.com
Дата: 10.01.08 14:46
Оценка:
Здравствуйте, bolikdimon, Вы писали:

B>Добрый день.

B>У меня следующая проблема.
B>Есть DAL класс, наследуемый от DataAccessor, в нем объявлен абстрактный метод:

B>[SprocName("Projects_Insert")]

B>public abstract override int Insert(Project project);

B>Из класса бизнес логики вызываю этот метод, все работает нормально. Но как только пытаюсь поместить его в пределы транзакции он перестает работать.


Как вариант. Для использования в транзакциях я создаю методы с DbManager параметром:

public abstract int Insert(DbManager db, Project project);

Далее в другом методе DAL или BLL:

void DoSome(Project project)
{
    MyAccessor a = GetAccessor();
  
    using (DbManager db = a.GetDbManager())
    {
        db.BeginTransaction();
        
        a.Insert(db, project);
        
        db.CommitTransaction();
    }
}
... << RSDN@Home 1.2.0 alpha rev. 771>>
Если нам не помогут, то мы тоже никого не пощадим.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.