在实体框架中添加相关对象的最佳实践是什么?

Oma*_*hdi 0 c# code-first entity-framework-core asp.net-core

我最近在 .NET Core 3.1 中创建了一个 Web API 项目,并使用代码优先方法实现了 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; }
}
Run Code Online (Sandbox Code Playgroud)

正如你在这个例子中看到的,我指的是 Address 和 CondominiumType 而不使用引用 Id。迁移数据库时,Entity Framework 将创建相应的外键。

当我必须添加带有新地址的新公寓时,这非常有效,但是当我想添加现有地址或公寓类型时遇到问题。

当我将一个对象传递给具有已添加到数据库中的 ID 的上下文时,程序会抛出异常,因为我违反了表的 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; }

}
Run Code Online (Sandbox Code Playgroud)

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

在业务层,我传递数据抛出一个 UnitOfWork Patter:

 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();
    }
Run Code Online (Sandbox Code Playgroud)

Pro*_*man 5

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

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

 Address address = _context.Addresses.Single(it => it.Id == someId);
Run Code Online (Sandbox Code Playgroud)

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

另一种方法是使用Attach()方法而不是Add()上下文来附加地址。这样,EntityFramework 的上下文将对象置于“跟踪”或“附加”状态,并且在您运行时不会尝试将其添加为新行,SaveChanges()并假设它是数据库中的实体,而无需从数据库中运行SELECT查询。