【问题标题】:Entity Framework detached virtual object after using AutoMapper使用 AutoMapper 后实体框架分离的虚拟对象
【发布时间】:2020-01-30 02:05:30
【问题描述】:

我已经设置了一个 MVC 环境,我在其中获取一个 Entity Framework 实体,将其映射到 DTO 以供用户修改,然后将 DTO 映射回 EF 实体。

我的 EF 课程如下:

public class Person
{
    [Key]
    public int Id { get; set; }
    public string Name { get; set; }
    public int AddressId { get; set; }
    public virtual StreetAddress Address { get; set; }
    /*More stuff here*/
}
//For the purpose of this example lets assume that addresses cannot be changed, they are read-only
public class StreetAddress
{
    [Key]
    public int Id { get; set; }
    public string StreetName { get; set; }
    /*More stuff here*/
}

我的 DTO 是:

public class PersonDTO
{
    public int Id { get; set; }
    public string Name { get; set; }
    public int AddressId { get; set; }
    public StreetAddress Address { get; set; }
    /*More stuff here*/
}

从这里我将 Person 映射到 PersonDTO 并再次返回:

Person person = /*retrieve from database*/;
PersonDTO dto = Mapper.Map<PersonDTO>(person);

// send dto to user, user updates name, user sends dto back
// the address object is the same, but it might have been converted to JSON or something like that during transport

Person person = Mapper.Map<Person>(dto);

所以我现在有一个准备保存到数据库的人。 StreetAddress 对象仍然具有相同的信息,但是现在 EF 将 Address 视为分离的。我不能使用context.Attach(Address),因为上下文已经有一个 StreetAddress 附加了相同的 Key,并且尝试这样做会导致抛出异常。

如果我选择忽略分离的地址并将这个新人添加到我的数据库中,EF 将地址视为一个全新的对象并将其插入到数据库中,导致数据库中的地址行重复,同样的细节,新身份证。

我目前的解决方案是将地址对象替换为已经附加到上下文的对象:

var tracked = context.ChangeTracker.Entries<Address>();
person.Address = tracked.Where(x => x.Entity.Id == person.AddressId).Select(e => e.Entity).FirstOrDefault();

有没有更好的方法来做到这一点?也许是一种告诉 EF 如果有一个地址 ID 已经在数据库中的人,则不需要插入它?

【问题讨论】:

    标签: c# entity-framework automapper


    【解决方案1】:

    一种方法是在 Person 和 PersonDTO 中 expose your FK AddressId

    另一种是将实体状态设置为修改:context.Entry(person.Address).State = EntityState.Modified; 如图here

    【讨论】:

    • 我实际上已经暴露了外键,这就是 /*addressId*/ 评论的来源,我已经编辑了问题以使其更清楚。我怎样才能在这里使用暴露的外键来帮助我?
    • 我也尝试过更改 person.Address 的状态,但失败了,出现异常Attaching an entity of type '.....StreetAddress' failed because another entity of the same type already has the same primary key value
    • 这是 MVC 吗?你的保存逻辑是什么?我个人觉得最简单的方法是在 GET 中填充我的 ViewModel 并将其发送到视图,然后在 POST 上取回对象并将更改的视图模型字段映射回,然后再保存。
    • 是的,它是 MVC,至于保存逻辑,我对 EF 很陌生,但对于这种特定情况,我只是使用context.Set&lt;Person&gt;().Add(person);context.SaveChanges();,因为我的代码的精简版本目前只插入新的人。
    • 尝试清空地址导航属性(或在将 DTO 映射到实体时忽略它),但确保设置了 AddressID。
    猜你喜欢
    • 2012-03-27
    • 1970-01-01
    • 2010-09-28
    • 2016-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 2013-01-24
    相关资源
    最近更新 更多