【问题标题】:Which is the best practice to add a related objects in Entity Framework?在实体框架中添加相关对象的最佳实践是什么?
【发布时间】:2020-08-16 03:29:19
【问题描述】:

我最近在 .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; }
}

正如您在本示例中所见,我指的是 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; }

}

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

在业务层中,我正在传递数据,抛出一个 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();
    }

【问题讨论】:

  • 您要问的是如何解决问题的症状。相反,您应该问,如何解决问题的原因。正确的方法是从数据库中检索“重复”实体,更新任何已更改的属性,然后保存更改。
  • 我认为这个问题与您的课程无关,而是您在上下文中访问实体的方式。您能否在访问导致问题的上下文的位置添加代码。如上所述,您应该在上下文中引用现有实体,然后将其分配给同一上下文中的新实体。然后,当您保存更改时,EF 知道您引用的是现有实体而不是尝试添加新实体。
  • @Selthien 这是服务层的代码: public async Task AddCondominium(int AgencyId,CondominiumDTO newCondominium) { var condominium = _mapper.Map(newCondominium); condominium.ConsortiumAdministrationAgency = new ConsortiumAdministrationAgency() { Id = AgencyId }; _unitOfWork.Addresses.Add(condominium.Address); _unitOfWork.Condominiums.Add(condominium);返回等待 _unitOfWork.CompleteAsync(); }
  • 对于新条目,您的唯一 (id) 应该是自动生成的(不是您自己设置的)。要更新条目,您应该通过 id 获取它并修改其他道具并保存。此外,这可能是您的课程的问题。提供更多信息以寻求帮助。

标签: c# asp.net-core entity-framework-core code-first


【解决方案1】:

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

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

 Address address = _context.Addresses.Single(it => it.Id == someId);

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

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

【讨论】:

  • 它使用single 工作,但我担心效率。在此示例中,此模型有 3 个不同的实体,这意味着在数据库中执行至少 4 个查询以进行简单的添加操作。所以我实现了attach 方法,它在性能方面更好,但现在我必须手动设置是否要添加新实体
  • @OmarChahdi 检查 ID。如果有,那么您知道它必须事先存在,您可以使用Attach()
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-05
  • 1970-01-01
  • 2022-10-15
  • 2015-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多