Является ли Entity Framework ObjectContext правильной реализацией шаблона единицы работы? - PullRequest
6 голосов
/ 25 июня 2010

Entity Framework 4 - STE - простая БД с одной таблицей Блоги, имеющие столбец 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 == null после последней строки)

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

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

Ответы [ 3 ]

4 голосов
/ 25 июня 2010

Вам нужно позвонить

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, объекты в состоянии «Добавлен» не имеют исходных значений в 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, я не вижу, почему нет. Он действительно поддерживает список объектов и отслеживает изменения и т. Д. И т. Д. Однако проблема, с которой вы столкнулись, связана с тем, что вы выбираете данные из базового провайдера, а не из списка объектов, в настоящее время прикрепленных к контекст.

1 голос
/ 05 июля 2010

Шаблон, который нарушен в вашем примере, - это не шаблон единицы работы, а сопоставление идентификаторов.

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

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

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

0 голосов
/ 26 июня 2010

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

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 без сохранения изменений в БД, если хотите.

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