Архитектура приложения - транзакции с RavenDB - PullRequest
4 голосов
/ 10 октября 2011

Я внедряю RavenDB в проект, и после нескольких дней работы с базой данных я сейчас структурирую это приложение, но у меня возник вопрос.

Я пишу бизнес-уровни для каждой сущности (почти), и у меня есть уникальный класс хранилища, который обрабатывает запросы и DocumentStore. Я запутался в том, как я должен делиться DocumentStore по слоям сервисов и обрабатывать транзакции.

Я показываю пример, где я пытаюсь сохранить и прочитать документ в одной транзакции.

Пример хранилища:

public class RavenRepository
{
    private static DocumentStore _store;
    private IDocumentSession _session;

    public RavenRepository(DocumentStore store)
    {
        _store = (_store==null) ? new DocumentStore() { Url = "http://wsk-gcardoso:8081" } : store;           
    }
    public T SingleOrDefault<T>(Func<T, bool> predicate) where T : BaseModel
    {
        using (var session = _store.OpenSession())
        {
            return session.Query<T>().SingleOrDefault(predicate);
        }
    }
    public T Add<T>(T item) where T : BaseModel
    {            
        using (var session = _store.OpenSession())
        {
            session.Advanced.AllowNonAuthoritiveInformation = this.AllowNonAuthoritiveInformation;
            session.Store(item);
            session.SaveChanges();
        }
        return item;
    }
    public void Initialize() {
        _store.Initialize();
    }
    public void Dispose() {
        _store.Dispose();
    }
}

Бизнес-уровень будет выглядеть так:

public class NewsletterBusiness
{
    private RavenRepository repository;
    public NewsletterBusiness(RavenRepository ravenRepository)
    {       
        repository = (ravenRepository == null) ? RavenRepository(null) : ravenRepository;
    }

    public Newsletter Add(Newsletter newsletter)
    {
        Newsletter news = repository.Add(newsletter);
        return news;
    }
    public Newsletter GetById(long Id)
    {
        Newsletter news = repository.SingleOrDefault<Newsletter>(x => x.Id == Id);
        return news;
    }
}

Теперь я пытаюсь сохранить и прочитать объект (информационные бюллетени) в одной и той же транзакции. Из того, что я прочитал, я должен установить для AllowNonAuthoritativeInformation documentStore значение false, чтобы дождаться завершения транзакции. Но из того, как я работаю со слоями и хранилищем, я храню и запрашиваю БД в одной транзакции?

Если честно, я думаю, что запутался в методе хранения OpenSession . Я думаю, что я путаю сессию с транзакцией.

Например, этот код:

var repository = new RavenRepository(null);
newsletterBusiness = new NewsletterBusiness(repository);
repository.Initialize();
using (var tx = new TransactionScope())
{
    Newsletter new = newsletterBusiness.Add(new Newsletter { Title = "Created by Tests", Content = "Created By Tests" });

    Newsletter objectCreated = newsletterBusiness.GetById(new.Id);
    repository.Dispose();
    tx.Complete();
}

Если я создам второй бизнес-уровень (например, для изображений) и задаю picturesBusiness.repository = repository (тот же самый объект RavenRepository, выделенный для businessLayer), я буду работать в том же сеансе newsletterBusiness.repository ?

picturesBusiness = new PicturesBusiness(repository);
Picture pic = picturesBusiness.GetById(20);

Я был бы очень признателен за помощь по этому вопросу, Приветствия из Португалии!

Ответы [ 2 ]

13 голосов
/ 10 октября 2011

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

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

Если вы хотите иметь транзакционную запись, охватывающую типы, учитывая вашу архитектуру, вы быиспользовать DTC, потому что каждый отдельный сеанс - это другое соединение с базой данных.Если бы вы использовали модель Session per Request, у вас был бы только один сеанс, и вы бы имели транзакционную семантику, просто вызвав SaveChanges () один раз.

2 голосов
/ 26 декабря 2011

Вы пытаетесь абстрагировать сессию ворона (которая по сути является UnitOfWork) с помощью шаблона репозитория.

Я бы предложил вам следующий подход - создать абстракцию UnitOfWork, которая будет инкапсулировать сеанс ravenDB и создавать из него репозитории. Вот несколько псевдокодов:

public class RavenUnitOfWork {
    private IDocumentSession m_session;

    public UnitOfWork() {
        // initialize m_session here
    }

    public Repository<T> GetRepository() {
        return new Repository<T>(m_session);
    }

    public void Commit() {
        m_session.SaveChanges();
    }
}

public class RavenRepository<T> {
    public Repository(IDocumentSession session) {
        // Store the session
    }
    public T Load(string id) {...}
    public void Store(T entity) {...}
    public void Delete(T entity) {...}
    public IQueryable<T> Query() {...}
}

Здесь вы явно реализуете эти шаблоны.

П.С .: Конечно, вы можете объявить IUnitOfWork и IRepository на свой вкус ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...