Pull to refresh

Comments 17

Эммм… Транзакции?

(В сторону: ну и гадость же этот ваш EF)
не совсем транзакции. но согласен, слегка похоже!
Вы вопрос не поняли.
Как уже отметили, вы не поняли вопроса. Где и как у вас организуются транзакции?
И unitRepository и cityRepository имеют внутри себя каждый свой экземпляр DBContainer. При вызове BaseRepository.SaveChanges() каждого из них, по порядку, будет: открыто свое соединение -> начата транзакция -> выполнены CRUD команды SQL -> комит/ролбек -> закрытие соединения.
В итоге: получаем отдельные «транзакции» отдельно для каждого объекта типа BaseRepository, или так: в результате можем иметь сохраненные изменения unitRepository и «обломавшийся» cityRepository.SaveChanges().
Не уверен, поможет ли выполнение обоих SaveChanges() внутри using (TransactionScope ts = new TransactionScope()) {...}.
Или я неправильно понял вопрос.
Да, правильно поняли. Что неправильно — так это подобное поведение. А использование TransactionScope вполне себе может эскалировать транзакцию до распределенной.

How to run two Entity Framework Contexts inside TransactionScope without MSDTC?
Что неправильно — так это подобное поведение. — Мне кажется что все дискусии решаютя бизнес-задачами. Если именно_такое нужно для конткретного_проекта и требований — велком! Ну и да, нужно понимать какие ограничения возможны в применении данного подхода.
А чем именно неправильно подобное поведение? Эскалацию до распределенной можно побороть через ручное управление Enlistment-ом. Будет гарантированно одно соединение в пределах TransactionScope (и одна SqlTransaction), расшаренное для всех контекстов.
Потому что вообще говоря транзакции — дело клиентского по отношению к DAL/репозиторию/следующему-баззвордному-паттерну кода.
Эммм… Транзакции?
вообще говоря транзакции — дело клиентского по отношению к DAL/репозиторию/следующему-баззвордному-паттерну кода.

Я тоже не понял вопроса. И вашего же ответа.

DAL должен поддерживать транзакции, а не организовывать их. Репозиторий [в дописанном до совместимости с TransactionScope варианте, гарантированно не делающий эскалацию внутри] будет поддерживать и Explicit и Implicit транзакции. Если автор решил не реализовать поддержку транзакций в рамках статью — это его выбор. Это же статья, а не дамп кода живого проекта с комментариями.
Производительность на нескольких процессорах с ГГц-ами — конечно не главное, но… Рефлексия на каждый чих достаточно жестокая вещь.

А потом я не понял особой разницы между new BaseRepository().AllItems и new DBContainer().UnitSet. Конструкции по моему равнозначные (без полиморфизма же). По длине и по сложности очень похожие.
Да, производительность возможно несколько пострадает. Но по моему скромному мнение удобство повышается…
Разницы особой и нету. Только BaseRepository не требует явного задания названия контейнера, вот и всё.
Производительность — однозначна спорная вещь, я на ней не настаиваю. К тому же при выполнении sql-запросов. Просто замечание. Факт просадки может определить только профайлер.

А вот с интерфейсами — выигрыш по моему спорен. У вас упоминание о типе объектов просто переехало в другое место.
Рефлексию можно заменить на компилируемые лямбды. Работать будет… быстрее. И выглядеть — намного круче.
1. Посмотрите еще на один очень интересный проект расширения возможностей Entity Framework 1.0/4.0:
ADO.NET Entity Framework Extensions. Лично я уже даже не представляю себе проект на EF без использования функционала этих «расширений».
2. А для получения сущности по ключу я использую метод-расширение в классе DBContainer:

public T GetObjectByKey(object id) where T : EntityObject
{
string entitySetName = this.MetadataWorkspace.GetEntityContainer(this.DefaultContainerName, DataSpace.CSpace)
.BaseEntitySets.Where(bes => bes.ElementType.Name == typeof(T).Name)
.FirstOrDefault().Name;
string entitySetKeyName = string.Format("{0}.{1}", this.DefaultContainerName, entitySetName);
EntityKey key = new EntityKey(entitySetKeyName, "ID", id);
return (T)this.GetObjectByKey(key);
}

3. Получается, что у Вас unitRepository и cityRepository каждый имеет СВОИ/РАЗЛИЧНЫЕ экземпляры DBContainer(). Это, конечно, вариант и все зависит от требований конкретной задачи, но я бы еще добавил бы в конструктор BaseRepository параметра типа DBContainer: вдруг понадобится работать с уже ранее созданным экземпляром DBContainer. Имхо.
Хорошая попытка, но попробуите почитать на эту тему побольше. Если нет проблем с англииским, то можете начать с этои статьи: huyrua.wordpress.com/2010/07/13/entity-framework-4-poco-repository-and-specification-pattern/ где подробно изложена схема создания репозитория. Там используется замечательныи метод ObjectContext.CreateObjectSet<TEntity>() вместо рефлексии.
С английским проблем никаких нет:) Спасибо! Очень занимательная статья! Я правда сейчас работаю с Code-First, хочу посмотреть на что он способен.
Sign up to leave a comment.

Articles