Является платформой Объекта ObjectContext корректная реализация Шаблона Единицы работы?

Платформа объекта 4 - STE - простой DB с единственной таблицей Blogs, имеющей столбец BlogID PK...

var samplesDbEntities = new SamplesDBEntities();
var blogId = Guid.NewGuid();
samplesDbEntities.Blogs.AddObject(new Blog() { BlogID = blogId });
var objectSetResult = samplesDbEntities.Blogs
                                       .Where(p => p.BlogID == blogId)
                                       .SingleOrDefault();

(результат выполнения кода => objectSetResult == пустой указатель после последней строки)

AFAIK, ObjectContext является реализацией шаблона UoW, и, в этом случае я предполагаю, что должен вернуть результат из ObjectSet (Репозиторий), просто "отмеченный как переходный процесс", кто-то может объяснить меня, что я делаю неправильно и почему objectSetResult имеет нулевое значение здесь?

(Да, я знаю о ObjectStateManager, но мне это - больше патча для верхней упомянутой архитектурной проблемы),

6
задан skaffman 4 July 2010 в 21:05
поделиться

3 ответа

В вашем примере нарушен не шаблон Unit Of Work, а Identity Mapping.

Unit of Work отслеживает изменения, внесенные в объекты вашим кодом, вместо того, чтобы вы заботились об этом вручную.

Шаблон Identity Mapping использует контекст объекта, чтобы иметь один экземпляр сущности для одного значения первичного ключа.

Мне странно, но Entity Framework (как и LINQ 2 SQL) не отображает идентичность объектов в каждой ситуации, и описанная выше ситуация - один из таких случаев.

1
ответ дан 17 December 2019 в 04:41
поделиться

Вам необходимо позвонить по

samplesDbEntities.SaveChanges();

, прежде чем запрашивать объект.

var samplesDbEntities = new SamplesDBEntities(); 
var blogId = Guid.NewGuid(); 
samplesDbEntities.Blogs.AddObject(new Blog() { BlogID = blogId }); 

samplesDbEntities.SaveChanges();

var objectSetResult = samplesDbEntities.Blogs 
                                   .Where(p => p.BlogID == blogId) 
                                   .SingleOrDefault(); 

Обновление

Причина, по которой вы не получаете добавленного пользователя обратно в objectSetResult, заключается в том, что вызов метода SingleOrDefault объекта IQueryable приводит к запросу базы данных (фактическая строка запроса SQL создается в соответствии с условием «где» и т. д.), а поскольку объекта (пока) нет в базе данных, он не возвращается. Однако новый объект присоединен к контексту, и его EntityState имеет значение «Добавлен». Согласно MSDN, объекты в состоянии Added не имеют исходных значений в ObjectStateEntry. Состояние объектов внутри контекста объекта управляется ObjectStateManager. Поэтому, если вы хотите проверить, действительно ли объект прикреплен, вы можете получить его, вызвав GetObjectStateEntry:

var samplesDbEntities = new SamplesDBEntities();
Blog blog = new Blog() { BlogID = Guid.NewGuid() };
samplesDbEntities.Blogs.AddObject("Blogs", blog);

Blog addedBlog = (Blog)context.ObjectStateManager.GetObjectStateEntry(blog).Entity;

Также обратите внимание, что EntityState извлеченного объекта - «Добавлен».

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

4
ответ дан 17 December 2019 в 04:41
поделиться

Спасибо за разъяснение вашей точки зрения. Я добавляю это в качестве еще одного ответа, поскольку по этому вопросу можно сказать довольно много.

AFAIK, не существует строгого универсального определения UoW, так что тема, конечно, дискуссионная. Мои соображения таковы:

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

  2. Если вы добавляете сущности в контекст для того, чтобы потом по каким-то причинам достать их из него, прежде чем персистировать изменения в БД, вы используете EF не так, как он должен использоваться. Обычно для этого не следует использовать ObjectStateManager, но вы можете:

    Blog addedBlog = context.
     ObjectStateManager.
     GetObjectStateEntries(EntityState.Added).
     Where(ent => (ent.Entity is Blog) && ((Blog)ent.Entity).BlogID == blogID).
     Select(ent => ent.Entity as Blog).
     SingleOrDefault();
    
  3. Единицей работы является контекстный объект, который ведет списки бизнес-сущностей, отслеживает изменения их состояния в течение одной бизнес-транзакции. Делает ли EF ObjectContext это? Да. Обеспечивает ли он разумный синтаксис для получения объекта, находящегося в состоянии "Добавлено"? Нет, но это в любом случае не является требованием для "правильной" реализации UoW. Не забывайте - EF это ORM, и цель состоит в том, чтобы отслеживать изменения в вашей базе данных в коде, а не изменения между различными частями вашего кода (для этого у вас есть бизнес-логика).

И относительно: "в чем смысл UoW, если я должен сохранять каждую сущность отдельно, а не пакетно" - смысл в том, что вы можете добавить кучу объектов в контекст, а затем сохранить их все одним махом, вызвав SaveChanges. Как я уже говорил, контекст не предназначен для "переноски" ваших бизнес-объектов. Однако вы можете получить их из ObjectStateManager без сохранения изменений в БД, если хотите.

0
ответ дан 17 December 2019 в 04:41
поделиться
Другие вопросы по тегам:

Похожие вопросы: