【发布时间】: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