Реализация UnitOfWork

Мне удалось реализовать небольшую крутую единицу работы для работы с Entity Framework.

я придумала..

public class UnitOfWork : IUnitOfWork
    {
        private Database _database;
        private IDatabaseFactory _databaseFactory;

        private DbTransaction transaction;

        public UnitOfWork(IDatabaseFactory databaseFactory)
        {
            _databaseFactory = databaseFactory;
            _database = Database;

            transaction = _database.Database.Connection.BeginTransaction();
        }

        public Database Database
        {
            get { return _database ?? (_database = _databaseFactory.Get()); }
        }

        public void Dispose()
        {
            try
            {
                _database.SaveChanges();
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
            }
        }
    }

Я почти уверен, что сейчас все завидуют этой единице работы. (Шутя)

Но у меня есть небольшая проблема с дизайном на этом сервисном уровне.

public class JournalService : IJournalService
    {
        IJournalRepository _journalRepository;

        public JournalService(IJournalRepository journalRepository)
        { 
            _journalRepository = journalRepository;
        }

        public void AjouterJournal(Journal j)
        {
           [B]using (IUnitOfWork uow = new UnitOfWork())[/B]
            {
                var journal = new Journal();
                journalRepository.AddJournal(journal);

            }
        }
    }

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

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

Я мог бы внедрить IDatabaseFactory в свой сервисный слой, но идея состоит в том, чтобы не использовать его там. На самом деле сервисный уровень не должен знать об этом.

Как насчет фабрики UnitOfWork?

Любые идеи или предложения о том, как я могу это исправить?

Спасибо.


person Rushino    schedule 05.02.2011    source источник
comment
Фабрика UnitOfWork вроде работает. Но тогда проблема заключается в том, как вы предоставляете IDatabaseFactory вашему UnitOfWorkFactory.   -  person yuxhuang    schedule 05.02.2011
comment
DI-инъекция в конструкторе?   -  person Rushino    schedule 05.02.2011


Ответы (1)


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

Другое дело, что эту реализацию можно использовать только для простых операций CRUD. В более сложных сервисах вы получите состав из нескольких операций (возможно, из нескольких сервисов), каждая из которых будет работать с UnitOfWork. Вызов нескольких SaveChanges (и транзакций) в одной бизнес-операции, вероятно, не то, что вам обычно нужно - в таком случае вы хотите вызывать SaveChanges только один раз из какой-либо службы верхнего уровня или из вызывающей службы. Типичный сценарий заключается в том, что одна бизнес-операция имеет одну единицу работы с одной транзакцией, но вы можете выполнять множество сервисных операций как часть этой бизнес-операции.

Другим следствием является создание ваших репозиториев. Вероятно, им нужен доступ к базе данных, не так ли? Так что вы, вероятно, уже внедрили UoW в конструктор репозитория. Если вы сделаете это, вы сможете вообще избежать связи между UoW и базовыми услугами.

person Ladislav Mrnka    schedule 06.02.2011
comment
Не могли бы вы немного подробнее объяснить вторую часть (о реализации можно использовать только для простого CRUD...) В настоящее время я внедряю UoW и репозитории на свой сервисный уровень. что-то не так с этим? обычно UoW начинается, когда начинается бизнес-операция, и заканчивается после завершения бизнес-операции в службе. Я мог бы в конечном итоге вызвать другие службы, но эти службы будут иметь отношение только к моей бизнес-операции, и эти службы не могут быть доступны через контроллер напрямую. Контроллер будет использовать только одну службу, которая, вероятно, является службой в реальном контексте. - person Rushino; 06.02.2011
comment
Идея второй части — композиция. Если вашей бизнес-операцией является AddJournal, вы можете включить UoW и SaveChanges в сервисную операцию. Но если ваша бизнес-операция DoSomethingBig состоит из нескольких вызовов AddJournal, вы не захотите вызывать SaveChanges и Commit в каждом вызове AddJournal. Вы захотите вызвать его только один раз после всех вызовов AddJournal. - person Ladislav Mrnka; 06.02.2011
comment
Хороший вопрос, чувак, я не знал об этом, на самом деле, вызывая журнал addjournal, вы действительно используете единицу работы, что не очень хорошая идея, но зачем вам вызывать addjournal из службы, если вместо этого вы можете вызвать репозиторий.addjournal? Я считаю, что класс обслуживания делает больше, чем грубые операции. Поправьте меня, если я ошибаюсь, разве репозиторий в основном не выполняет грубую работу? если мне когда-нибудь придется добавить журнал, я не буду использовать сервисный метод. В противном случае Где вы предлагаете поместить единицу реализации работы? Какой уровень ? - person Rushino; 06.02.2011
comment
Операция службы обычно выполняет больше работы, чем просто вызов метода в репозитории - может быть, например, некоторая бизнес-валидация, проверки безопасности, ведение журнала и т. д. Вот почему вы иногда хотите создавать вызовы операций службы (повторно использовать их) вместо вызова репозитория. методы. В таком случае вы можете сделать это грязным способом - извлечь UoW из сервисного слоя и вызвать его на слое с помощью ваших сервисов. Аккуратный способ — определить два уровня сервисных уровней — низкий уровень без вызовов UoW и уровень Facede (повторное использование низкоуровневых сервисов) с вызовами UoW. Но это также касается размера вашего проекта. - person Ladislav Mrnka; 06.02.2011