2013-08-21 3 views
0

У меня есть следующий код, который создает новую закладку и добавляет к ней один или несколько тегов. Если тег еще не существует, он создается и добавляется в закладку.NHibernate Сохранить и зафиксировать в одной транзакции

Bookmark bookmark = new Bookmark(); 
bookmark.Title = request.Title; 
bookmark.Link = request.Link; 
bookmark.DateCreated = request.DateCreated; 
bookmark.DateModified = request.DateCreated; 
bookmark.User = _userRepository.GetUserByUsername(request.Username); 

IList<Tag> myTags = _tagRepository.GetTags(request.Username); 
IList<string> myTagsToString = myTags.Select(x => x.Title).ToList<string>(); 

foreach (var tag in request.Tags) 
{ 
    if (myTagsToString.Contains(tag)) 
    { 
     Tag oldTag = myTags.SingleOrDefault(x => x.Title == tag); 
     bookmark.Tags.Add(oldTag); 
    } 
    else 
    { 
     Tag newTag = new Tag(); 
     newTag.Title = tag; 
     newTag.User = _userRepository.GetUserByUsername(request.Username); 
     newTag.DateCreated = request.DateCreated; 
     newTag.DateModified = request.DateCreated; 
     bookmark.Tags.Add(newTag); 
    } 
} 

_bookmarkRepository.Add(bookmark); 
_uow.Commit(); 

Я реализовал единицу работы, но не уверен, правильно ли я сделал это. Я использую метод сохранения, за которым следует фиксация. Метод сохранения вставляет закладку и теги в базу данных, а метод фиксации выполняет вставку в таблицу соединений (закладки имеют много тегов и тегов, имеющих много закладок).

Итак, все вставлено правильно. Но если я удалю метод фиксации, закладка и теги по-прежнему будут вставлены. Но их нет вставки в таблицу соединений. Означает ли это, что эти вставки не находятся в одной транзакции, поскольку фиксация не требуется для сохранения закладки и тегов в базе данных? Конец необходим только для сохранения связи между тегами и закладками.

РЕДАКТИРОВАТЬ:

Repository

public abstract class Repository<T, TEntityKey> where T : IAggregateRoot 
{ 
    private IUnitOfWork _uow; 

    public Repository(IUnitOfWork uow) 
    { 
     _uow = uow; 
    } 

    public void Save(T entity) 
    { 
     SessionFactory.GetCurrentSession().SaveOrUpdate(entity); 
    } 

    public void Add(T entity) 
    { 
     SessionFactory.GetCurrentSession().Save(entity); 
    } 

    public void Remove(T entity) 
    { 
     SessionFactory.GetCurrentSession().Delete(entity); 
    } 

    public IEnumerable<T> FindAll() 
    { 
     ICriteria criteriaQuery = SessionFactory.GetCurrentSession().CreateCriteria(typeof(T)); 

     return (List<T>)criteriaQuery.List<T>(); 
    } 
} 

UnitOfWork

public class NHUnitOfWork : IUnitOfWork 
{ 
    public void RegisterAmended(IAggregateRoot entity) 
    { 
     SessionFactory.GetCurrentSession().SaveOrUpdate(entity); 
    } 

    public void RegisterNew(IAggregateRoot entity) 
    { 
     SessionFactory.GetCurrentSession().Save(entity); 
    } 

    public void RegisterRemoved(IAggregateRoot entity) 
    { 
     SessionFactory.GetCurrentSession().Delete(entity); 
    } 

    public void Commit() 
    { 
     using (ITransaction transaction = SessionFactory.GetCurrentSession().BeginTransaction()) 
     { 
      try 
      { 
       transaction.Commit(); 
      } 
      catch (Exception ex) 
      { 
       transaction.Rollback(); 
       throw; 
      } 
     } 
    } 
} 

BookmarkRepository

public class BookmarkRepository : Repository<Bookmark, int>, IBookmarkRepository 
{ 
    public BookmarkRepository(IUnitOfWork uow) 
     : base(uow) 
    { 
    } 
} 

ОБНОВЛЕНИЕ: Я изменил NHUnitOfWork к этому:

public class NHUnitOfWork : IUnitOfWork 
{ 
    private ITransaction _transaction; 

    public void RegisterAmended(IAggregateRoot entity) 
    { 
     SessionFactory.GetCurrentSession().SaveOrUpdate(entity); 
    } 

    public void RegisterNew(IAggregateRoot entity) 
    { 
     SessionFactory.GetCurrentSession().Save(entity); 
    } 

    public void RegisterRemoved(IAggregateRoot entity) 
    { 
     SessionFactory.GetCurrentSession().Delete(entity); 
    } 

    public void BeginTransaction() 
    { 
     _transaction = SessionFactory.GetCurrentSession().BeginTransaction(); 
    } 

    public void Commit() 
    { 
     using (_transaction) 
     { 
      try 
      { 
       _transaction.Commit(); 
      } 
      catch (Exception ex) 
      { 
       _transaction.Rollback(); 
       throw; 
      } 
     } 
    } 
} 

Так что я могу использовать его как это:

_uow.BeginTransaction(); 

Bookmark bookmark = new Bookmark(); 
bookmark.Title = request.Title; 
bookmark.Link = request.Link; 
bookmark.DateCreated = request.DateCreated; 
bookmark.DateModified = request.DateCreated; 
bookmark.User = _userRepository.GetUserByUsername(request.Username); 

IList<Tag> myTags = _tagRepository.GetTags(request.Username); 
IList<string> myTagsToString = myTags.Select(x => x.Title).ToList<string>(); 

foreach (var tag in request.Tags) 
{ 
    if (myTagsToString.Contains(tag)) 
    { 
     Tag oldTag = myTags.SingleOrDefault(x => x.Title == tag); 
     bookmark.Tags.Add(oldTag); 
    } 
    else 
    { 
     Tag newTag = new Tag(); 
     newTag.Title = tag; 
     newTag.User = _userRepository.GetUserByUsername(request.Username); 
     newTag.DateCreated = request.DateCreated; 
     newTag.DateModified = request.DateCreated; 
     bookmark.Tags.Add(newTag); 
    } 
} 

_bookmarkRepository.Add(bookmark); 
_uow.Commit(); 

Я добавил начать сделку по реализации NHUnitOfWork. Это означает, что мне нужно вызвать _uow.BeginTransaction() перед любым выбором или вставкой и в конце вызова _uow.Commit(). Кажется, это работает, если я смотрю на NHibernate Profiler. Если это не так, пожалуйста, скажите мне :)

ответ

0

Ваши Save методы не выполняются внутри транзакции, потому что вы закрываете и открытый сделки в методе Commit.

Правильная реализация будет заключаться в том, чтобы начать транзакцию до, вызвав Save.

+1

Чтобы уточнить, правильная реализация заключалась бы в том, чтобы начать транзакцию ПЕРЕД ДЕЙСТВИТЕЛЬНЫМИ ИЗМЕНЕНИЯМИ ВСЕХ (включая Save(), а также, например, Get() + модификацию свойства, поскольку NHibernate может (с настройками по умолчанию) принять решение выполнить изменение базы данных в любое время. –

+0

@Oskar: У вас есть пример этого? Я знаю последовательности в Oracle, которые используются для идентификатора, к которому обращаются до фиксации, но я не знаю о каком-либо другом таком случае. –

+0

Фактически , из NHibernate это на самом деле не «в любое время» - но с точки зрения сложного приложения его может быть очень сложно контролировать, когда точно передаются изменения. Дело в том, что Commit() - это всего лишь один из возможных способов запуска Flush(). См. Ссылку, если Flush() может возникать автоматически: http://nhforge.org/doc/nh/en/index.html#manipulatingdata-flushing –