entity-framework - 使用 Automapper,将 DTO 映射回 Entity Framework ,包括引用的实体

标签 entity-framework asp.net-web-api automapper dto navigation-properties

我有使用 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 对象(包含所有相关实体也作为代理)。

在我的 Controller 方法中,我正在执行以下操作:
    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 无关:

Link

Link

我想它又回到了手动操作。希望这可以帮助其他有同样疑问的人。

最佳答案

您已经确定了问题:

The above persistence logic updates the 'root' EF proxy object in the context, however any related entities are not updated



您仅在根节点上设置修改状态。您必须编写代码来遍历所有对象并将状态设置为已修改。

关于entity-framework - 使用 Automapper,将 DTO 映射回 Entity Framework ,包括引用的实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14145454/

相关文章:

asp.net-mvc - 将 Ninject 与 Asp.NET Web API Beta ApiController 结合使用

c# - 针对自托管 Web API (OWIN/Katana) 验证 MVC 客户端

C# 强制运算符?

c# - AutoMapper 不适用于容器类

entity-framework - EF Core Code First - 聚簇索引和标识列

c# - ProjectionTo 返回 ArgumentException : Argument types do not match

c# - 代码优先模型映射

c# - 使用 Entity Framework 提高效率

javascript - 来自后端的字节数组在前端转换为其他内容

c# - 使用 AutoMapper 映射类数组