在 Entity Framework 中添加相关对象的最佳做法是什么?

Which is the best practice to add a related objects in Entity Framework?

我最近在 .NET Core 3.1 中创建了一个 Web API 项目,并使用 code first 方法实现了 Entity Framework Core。我的每个模型都是这样引用其他模型的:

public class Condominium
{
    public int Id { get; set; }
    public Address Address { get; set; }
    public int Levels { get; set; }
    public string Description { get; set; }
    public CondominiumType CondominiumType { get; set; }
}

如您在此示例中所见,我指的是地址和 CondominiumType,但未使用引用 ID。 Entity Framework 将在数据库迁移时创建相应的外键。

当我必须添加具有新地址的新公寓时,这工作得很好,但当我想添加现有地址或公寓类型时,我遇到了问题。

当我将对象传递给上下文时,其 Id 已添加到数据库中,程序会抛出异常,因为我违反了 table 的 UNIQUE 约束。我知道我可以通过添加参考键来解决这个问题,这样写

    public class Condominium
{
    public int Id { get; set; }
    public int AddressId { get; set; }
    public Address Address { get; set; }
    public int Levels { get; set; }
    public string Description { get; set; }
    public int CondominiumTypeId { get; set; }
    public CondominiumType CondominiumType { get; set; }

}

但我想知道哪种方法是解决此类案例的正确方法。 ¿是否可以在不重写我的 类 的情况下添加现有对象?

在业务层中,我正在传递数据并抛出一个 UnitOfWork 模式:

 public async Task<bool> AddCondominium(int AgencyId,CondominiumDTO newCondominium)
    {
        var condominium = _mapper.Map<Condominium>(newCondominium);
        condominium.ConsortiumAdministrationAgency = new ConsortiumAdministrationAgency() { Id = AgencyId };
        _unitOfWork.Addresses.Add(condominium.Address);
        _unitOfWork.Condominiums.Add(condominium);
        return await _unitOfWork.CompleteAsync();
    }

EntityFramework 必须知道您添加到上下文中的对象应该是数据库中的新实体还是表示已经存在的实体(带有 Id)。当您使用 Add() 方法时,您是在说该对象用于新的 row/entity。但这意味着它会尝试使用对象中的值添加新实体。当它具有 Id 属性 集(这是主键)时,它会尝试添加具有该 ID 的新行,这将因重复键约束违规而失败。

有几种解决方法。您可以从正在使用的上下文中获取要引用的对象。当你使用像

这样的东西时
 Address address = _context.Addresses.Single(it => it.Id == someId);

您可以在其他实体的任何地方使用 address 引用 类 来引用数据库中的现有实体。这样,address中的对象就处于“跟踪”或“附加”到EntityFramework上下文的状态。 EntityFramework 不会在您 运行 SaveChanges() 时尝试将其添加为新行,而是在您更改值(如果有)时发送 UPDATE 查询。

另一种方法是使用 Attach() 方法而不是 Add() 将地址附加到上下文。这样 EntityFramework 的上下文将对象置于“跟踪”或“附加”状态,并且当您 运行 SaveChanges() 并假设它是来自数据库的实体,没有 运行ning 来自数据库的 SELECT 查询。