我有使用 Entity Framework 5 持久化的 POCO 域实体。它们是使用存储库模式从 DbContext 获得的,并通过 UoW 模式暴露给 RESTful MVC WebApi 应用程序。POCO 实体是代理并且是延迟加载的。
在将实体发送给客户之前,我将它们转换为 DTO。我正在使用 Automapper 来执行此操作,并且 Automapper 将代理 POCO 映射到 DTO 似乎可以正常工作,从而保持导航属性不变。我为此使用以下映射:
Mapper.CreateMap<Client, ClientDto>();
域/DTO 对象示例:
[Serializable]
public class Client : IEntity
{
public int Id { get; set; }
[Required, MaxLength(100)]
public virtual string Name { get; set; }
public virtual ICollection<ClientLocation> ClientLocations { get; set; }
public virtual ICollection<ComplianceRequirement> DefaultComplianceRequirements { get; set; }
public virtual ICollection<Note> Notes { get; set; }
}
public class ClientDto : DtoBase
{
public int Id { get; set; }
[Required, MaxLength(100)]
public string Name { get; set; }
public ICollection<ClientLocation> ClientLocations { get; set; }
public ICollection<ComplianceRequirementDto> DefaultComplianceRequirements { get; set; }
public ICollection<Note> Notes { get; set; }
}
现在我正在尝试使用从线路发送回来的 DTO 更新我的上下文。我在让导航属性/相关实体正常工作方面遇到了具体问题。我正在使用的映射是:
Mapper.CreateMap<ClientDto, Client>()
.ConstructUsing((Func<ClientDto, Client>)(c => clientUow.Get(c.Id)));
上面,clientUow.Get() 引用 DbContext.Set.Find() 以便我从 EF 获取跟踪的代理 POCO 对象(它包含所有相关实体也作为代理)。
在我的控制器方法中,我正在执行以下操作:
var client = Mapper.Map<ClientDto, Client>(clientDto);
uow.Update(client);
客户端成功映射为代理 POCO 对象,但是它的相关实体/导航属性被替换为具有从 DTO 复制的属性值的新(非代理)POCO 实体。
上面, uow.Update() 基本上是指一个执行持久逻辑的函数,我有:
_context.Entry<T>(entity).State = System.Data.EntityState.Modified;
_context.SaveChanges();
上述内容甚至不会持久存在实体,更不用说相关实体了。我已经尝试了映射的变体和使用分离/状态进行持久化的不同方法,但总是得到“ObjectStateManager 中已经存在具有相同键的对象”异常。
我已经查看了无数其他线程,但无法完全使用 Automapper。我可以从上下文中获取代理对象并手动通过从 DTO 更新它们的属性,但是我使用 Automapper 映射域 - > DTO,使用它来做相反的事情会更优雅,因为我的 DTO在很大程度上类似于我的域对象。
是否有教科书式的方法来处理带有 EF 的 Automapper,域对象/DTO 具有也需要同时更新的导航属性?
更新:
var originalEntity = _entities.Find(entity.Id);
_context.Entry<T>(originalEntity).State = System.Data.EntityState.Detached;
_context.Entry<T>(entity).State = System.Data.EntityState.Modified;
上述持久性逻辑更新上下文中的“根”EF 代理对象,但不会更新任何相关实体。我猜这是因为它们没有被映射到 EF 代理对象,而是被映射到普通域对象。帮助将不胜感激!
更新: 使用当前版本的 EF(5) 似乎我想要实现的目标实际上是不可能的,这是 EF 的核心限制,与 Automapper 无关:
我想它又回到了手动操作。希望这可以帮助其他想知道的人。