繁体   English   中英

实体框架在使用 AutoMapper 后分离虚拟对象

[英]Entity Framework detached virtual object after using AutoMapper

我已经建立了一个 MVC 环境,我在其中使用实体框架实体,将其映射到 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);

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

如果我选择忽略分离的地址并将这个新人添加到我的数据库中,EF 会将地址视为一个全新的对象并将其插入数据库,从而导致数据库中的地址行重复,详细信息相同,新 ID。

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

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

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

一种方法是使您的FK AddressId在人与PersonDTO。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM