c# - 在实体框架中添加相关对象的最佳实践是什么?
问题描述
我最近在 .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 上下文的状态。EntityFramework 不会在您运行时尝试将其添加为新行,SaveChanges()
而是UPDATE
在您更改值(如果有)时发送查询。
另一种方法是将地址附加到Attach()
方法而不是Add()
上下文中。这样,EntityFramework 的上下文将对象置于“已跟踪”或“附加”状态,并且在您运行时不会尝试将其添加为新行,SaveChanges()
并假定它是数据库中的实体而不运行数据库中的SELECT
查询。
推荐阅读
- postgresql - 如何在 psql 查询中将文本数字转换为整数类型
- html - 如何从发布请求中获取数据?
- android - 将覆盖设置为假后,锚定覆盖不隐藏?扑
- linux - bash 错误 \r\r': 没有这样的文件或目录
- node.js - 我如何使用 puppeteer 截取网站并将其发送到消息 Discord.js?
- r - 如何在 geom_plot() 中正确添加平均值、标准差和抖动?ggplot2
- javascript - 在javascript中将双引号字符串拆分为数组
- flutter - 如何设置主页异步和条件?
- regex - 如何使用 Unicode 正则表达式验证字符串的一部分
- sql - 为 IP 地址创建 SQL Server UDDT?