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

问题描述 投票:0回答:1

我已经建立了一个MVC环境,在该环境中,我将使用实体框架实体,将其映射到DTO以供用户修改,然后将DTO映射回EF实体。

我的EF类如下:

public class Person
{
    [Key]
    public int Id { get; set; }
    public string Name { 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 Address
{
    [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 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将地址视为已分离。我不能使用context.Attach(Address),因为上下文已经有一个附加了相同Key的StreetAddress,并且尝试这样做会引发异常。

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

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

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

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

c# entity-framework automapper
1个回答
0
投票

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

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

© www.soinside.com 2019 - 2024. All rights reserved.