Где должна быть граница транзакции в шаблоне репозитория? - PullRequest
1 голос
/ 12 января 2010

У меня есть хранилище примерно так:

public interface IRepository
{
    void Save<T>(T entity);
    void Create<T>(T entity);
    void Update<T>(T entity);
    void Delete<T>(T entity);
    IQueryable<T> GetAll<T>();
}

Мой вопрос: где должны быть границы моей транзакции? Должен ли я открыть новую транзакцию для каждого метода и зафиксировать ее перед возвратом? Или это должно быть вокруг всего хранилища, чтобы транзакция фиксировалась только тогда, когда хранилище было утилизировано / собрано мусор?

Ответы [ 3 ]

3 голосов
/ 12 января 2010

Транзакции не должны применяться к репозиториям, потому что, если в транзакции участвует более одного человека, это невозможно сказать.

Иметь отдельный уровень обслуживания, который использует репозитории и объекты моделей для удовлетворения сценариев использования. Методы обслуживания знают, где должны быть границы транзакции. Вот где они должны быть применены.

1 голос
/ 12 января 2010

Единица работы, безусловно, путь. Если вы используете SQL Server с локальной базой данных, TransactionScope сделает большую часть тяжелой работы за вас; до тех пор, пока вы разделяете сеансы между репозиториями (что вы делаете с помощью инъекции в конструктор, верно ...?), вы можете вкладывать их в свое удовольствие. По умолчанию он включается в «внешнюю» транзакцию, если она есть, и запускает новую, если ее нет, и это именно то поведение, которое требуется для единицы работы.

Так что ваши репозитории могут выглядеть так:

public class UserRepository : IUserRepository
{
    public UserRepository(ISession session)
    {
        this.Session = session;
    }

    public void Save(User user)
    {
        using (TransactionScope tsc = new TransactionScope())
        {
            Session.Save(user);
            tsc.Complete();
        }
    }

    protected ISession Session { get; set; }
}

public class OrderRepository : IOrderRepository
{
    public OrderRepository(ISession session)
    {
        this.Session = session;
    }

    public void Save(Order order)
    {
        using (TransactionScope tsc = new TransactionScope())
        {
            Session.Save(order);
            tsc.Complete();
        }
    }

    protected ISession Session { get; set; }
}

Тогда вы можете выполнить всю единицу работы следующим образом:

User currentUser = GetCurrentUser();
using (TransactionScope tsc = new TransactionScope())
{
    ISession session = SessionFactory.OpenSession();

    Order order = new Order(...);
    order.User = currentUser;
    IOrderRepository orderRepository = GetOrderRepository(session);
    orderRepository.Save(order);

    currentUser.LastOrderDate = DateTime.Now;
    IUserRepository userRepository = GetUserRepository(session);
    userRepository.Save(currentUser);

    tsc.Complete();
}

Если вам не нравится TransactionScope или ваша среда мешает вам эффективно его использовать, тогда вы всегда можете реализовать свое собственное UOW или использовать существующую реализацию. Или, если вы просто изящный архитектор, то вы можете сделать и то, и другое - использовать универсальный интерфейс единицы работы с одной из основных библиотек DI и реализовать конкретное UOW, используя TransactionScope.

0 голосов
/ 12 января 2010

Один из вариантов - это единица работы шаблона. Это уже объяснялось в нескольких предыдущих вопросах.

...