Entity Framework和仓储模式

4
我希望使用实体框架来持久化领域实体。我的项目设置如下:
- UI: MVC(使用Automapper在领域实体和视图模型之间进行映射) - Domain: 实体、服务、存储库接口 - Repository: 实体框架(实现来自领域层的接口)。使用Automapper在领域实体和实体框架对象之间进行映射。
这很好用,除非在我的服务中,如果我执行像检查存储库一样验证项,然后执行更新操作,这将失败,因为实体框架的标识映射已经看到了该项,然后我尝试再次附加它。
我可以使用以下代码解决此问题(这将变得更加通用)。
        public void Update(Domain.Entities.Book entity)
    {
        Book newBook = _mapper.Map<Domain.Entities.Book, Book>(entity);
        ObjectStateEntry cacheEntry;
        if (_dataContext.ObjectStateManager.TryGetObjectStateEntry(_dataContext.CreateEntityKey("Books",newBook), out cacheEntry))
        {
            _dataContext.Books.ApplyCurrentValues(newBook);
        }
        else
        {
            _dataContext.Books.Attach(newBook);
            _dataContext.ObjectStateManager.ChangeObjectState(newBook, EntityState.Modified);
        }
        _dataContext.SaveChanges();
    }

问题是我发现自己不得不写相同类型的代码来进行删除。
        public void Delete(Domain.Entities.Book entity)
    {
        Book newBook = _mapper.Map<Domain.Entities.Book, Book>(entity);
        ObjectStateEntry cacheEntry;
        if (_dataContext.ObjectStateManager.TryGetObjectStateEntry(_dataContext.CreateEntityKey("Books", newBook), out cacheEntry))
        {
            _dataContext.ObjectStateManager.ChangeObjectState(cacheEntry.Entity, EntityState.Deleted);

        }
        else
        {
            _dataContext.Books.Attach(newBook);
            _dataContext.ObjectStateManager.ChangeObjectState(newBook, EntityState.Deleted);
        }
        _dataContext.SaveChanges();
    }

我确信一定有更好的方法来实现我想要做的事情,但我却无论如何也想不出来!希望能得到关于上述方法的其他一般性评论,因为我将在一个大型项目中使用它!谢谢,Ross。

1
我想知道你是如何陷入一种不知道实体是否已经被连接的情况。在像更新实体这样基本的用例中使用类似TryGetObjectStateEntry这样的高级方法,在我看来是代码异味。请注意,你的更新依赖于cacheEntry.Entity代表了数据库中的原始状态的假设,否则ApplyCurrentValues和更改跟踪将无法标记正确的属性为修改,以执行正确的DB UPDATE。你知道即使你不知道实体是否已经被连接也总是会发生吗? - Slauma
创建存储库对象并获取项目会导致项目被加载到EF中,然后转换为域项。然后可以编辑此域项,然后将其传递给存储库的更新方法。使用AutoMap将此域对象转换为分离的EF对象。将其附加到EF会导致异常,因为键已经保存。我很惊讶这对人们来说不是更大的问题? - Ross Dargan
你不使用POCO作为实体吗?它们与EF没有任何关系,您可以在支持POCO的另一个ORM中使用相同的实体。 - Slauma
我可能有些困惑。我在我的领域层中使用POCO对象,并使用automapper将它们映射到EF对象。我不认为EF对象是POCO。但我可能是错的! - Ross Dargan
1
如果你的EF实体是从EntityObject类派生的,那么你是正确的,它们不是POCO,并且直接依赖于EF。但是你可以使用POCO与EF,即不从任何EF特定内容派生的实体类(只需谷歌“Entity Framework POCO”或类似内容)。EF团队不鼓励使用EntityObject,并建议使用POCO。你知道DbContext和你正在使用的ObjectContext相比吗?我建议你熟悉一下它,因为它简化了EF在许多方面的使用。 - Slauma
显示剩余6条评论
2个回答

1

我只有一个上下文。在我的测试UI应用程序中,我创建了一个存储库,并将其传递给服务。不幸的是,这不是问题所在。 - Ross Dargan

0

除非我完全误读了你的问题,否则我认为你的问题是多个DatabaseContext对象的实例。如果您从一个上下文实例获取对象,然后尝试在不同的上下文实例中使用它,您将会得到很多异常:第二个上下文实例将看到该对象已经附加,但它无法使用它,因为它已经附加到不同的上下文实例。

如果您只有一个管理附加对象的上下文实例,它将看到对象已经附加并将直接使用它。您就不需要使用AutoMapper(顺便说一句,这是一种很好的成员逐一克隆技术!)将对象克隆到新实例中,也不需要进行任何其他可怕的“TryingToAttachObject”操作。

我曾经遇到过很多类似的多个上下文实例的问题,直到我发现了依赖注入及其魔力:它将创建一个DBContext实例,并将用于处理所有请求和EF管理。


嗨,正如我刚刚回复BigDaddy的那样,上下文只有一个实例,恐怕这并不能解决问题。 - Ross Dargan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接