问题描述
我最近在.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; }
}
如您在本示例中看到的,我引用的是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();
}
解决方法
EntityFramework必须知道您添加到上下文中的对象应该是数据库中的新实体还是代表已经存在的实体(带有ID)。当您使用Add()
方法时,是说该对象是用于新行/实体的。但这意味着它试图在对象中添加带有值的新实体。当它设置了Id
属性(这是主键)时,它将尝试添加具有该ID的新行,该行将因重复的键约束冲突而失败。
有几种解决方案。您可以从正在使用的上下文中获取要引用的对象。当您使用类似
的东西时 Address address = _context.Addresses.Single(it => it.Id == someId);
您可以在其他实体类中的任何地方使用address
引用来引用数据库中的现有实体。这样,address
中的对象处于EntityFramework上下文的“已跟踪”或“已附加”状态。在运行SaveChanges()
时,EntityFramework不会尝试将其添加为新行,而是在您更改值(如果有)时发送UPDATE
查询。
另一种方法是使用Attach()
方法而不是Add()
将地址附加到上下文。这样,EntityFramework的上下文会将对象置于“已跟踪”或“已附加”状态,并且在您运行SaveChanges()
并假定它是数据库中的实体而不运行时不会尝试将其添加为新行。 SELECT
从数据库中查询。