entity-framework - EFCore - 为什么我必须使子对象为空才能阻止它们插入?一对多
问题描述
少量上下文,几年来我一直在使用 NHibernate 代码映射,最近几个月我开始使用 Entity Framework Core。
我试图理解为什么我必须使子对象为空以阻止它们插入新记录。我不确定这是否是我的理解问题,或者这是否是实体框架的工作方式。
我有两个类,Command 和 CommandCategory。Command 有一个 CommandCategory,而 CommandCategory 可以有许多命令。例如,“设置超时”命令将位于“配置”类别下。同样,“设置 URL”命令也将位于“配置”类别下。
class Command
{
public Guid Id { get; set; }
public string Name { get; set; }
public string CommandString { get; set; }
public Guid CommandCategoryId { get; set; }
public CommandCategory CommandCategory { get; set; }
}
class CommandCategory
{
public CommandCategory(string id, string name)
{
Id = Guid.Parse(id);
Name = name;
Commands = new List<Command>();
}
public Guid Id { get; set; }
public string Name { get; set; }
public ICollection<Command> Commands { get; set; }
}
我的 DbContext 设置如下:
class EfContext : DbContext
{
private const string DefaultConnection = "XXXXX";
public virtual DbSet<Command> Command { get; set; }
public virtual DbSet<CommandCategory> CommandCategory { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(DefaultConnection);
optionsBuilder.EnableSensitiveDataLogging();
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Command>()
.HasOne(x => x.CommandCategory)
.WithMany(x => x.Commands);
}
}
然后这里是实际运行它的代码。首先我调用 Add()。Add 创建一个新命令并将其添加到数据库中。它还会创建一个名为“Configuration”的 CommandCategory 并正确插入两者。
接下来我调用 AddWithExisting()。这将创建一个新命令,但使用现有的 CommandCategory。当它尝试添加到数据库时,它首先插入命令,然后尝试插入命令类别。因为 CommandCategory.Id 已经存在,并且它被设置为主键,所以这会失败,因为它是重复键。为了解决这个问题,我必须确保 Command 对象上的 CommandCategory 属性设置为 null。然后,这只会将 Command 插入数据库,而不是 CommandCategory 对象。
我知道通常您不会创建新的 CommandCategory 对象,但在这种情况下,我正在模拟通过 ApiController 从客户端发出的对象。我的应用程序通过 WebApi 来回发送数据,因此该对象基本上是在发出请求时创建的。
取消属性似乎是一件奇怪的事情,我认为对象关系映射的重点是不必像这样处理单个属性。
这是它应该如何运作还是我做错了什么?
class Program
{
static void Main(string[] args)
{
var dbContext = new EfContext();
Add(dbContext);
AddWithExisting(dbContext);
Console.WriteLine("Hello World!");
}
private static void Add(EfContext dbContext)
{
var newCommand = new Command();
newCommand.Id = Guid.NewGuid();
newCommand.Name = "set timeout";
newCommand.CommandString = "timeout:500;";
var newCommandCategory = new CommandCategory("8C0D0E31-950E-4062-B783-6817404417D4", "Configuration");
newCommandCategory.Commands.Add(newCommand);
newCommand.CommandCategory = newCommandCategory;
dbContext.Command.Add(newCommand);
dbContext.SaveChanges();
}
private static void AddWithExisting(EfContext dbContext)
{
var newCommand = new Command();
newCommand.Id = Guid.NewGuid();
newCommand.Name = "set URL";
newCommand.CommandString = "url:www.stackoverflow.com";
// this uses the same Id and Name as the existing command, this is to simulate a rest call coming up with all the data.
var newCommandCategory = new CommandCategory("8C0D0E31-950E-4062-B783-6817404417D4", "Configuration");
newCommandCategory.Commands.Add(newCommand);
// If i don't null the below line, it will insert to the database a second time
newCommand.CommandCategory = newCommandCategory;
newCommand.CommandCategoryId = newCommandCategory.Id;
dbContext.Command.Add(newCommand);
dbContext.SaveChanges();
}
解决方案
这是设计使然,您可以在这里做两件事:
您可以从数据库中查找现有命令类别并将其设置为属性(因为此对象“附加”到数据库上下文,它不会创建新的)。
只需在命令上设置命令类别的 ID。
例如
newCommand.CommandCategory = dbContext.CommandCategories.Find("8C0D0E31-950E-4062-B783-6817404417D4");
或者
newCommand.CommandCategoryId = new Guid("8C0D0E31-950E-4062-B783-6817404417D4");
目前,它看到了一个新的命令类别(未附加),因此正在尝试创建它。
推荐阅读
- javascript - 无法使用 Mongoose / UpdateOne 从数组中删除项目
- c - 动态增加 C 字符串的大小
- animation - error bad argument #1 to draw (drawable expected, got table),试图为主角制作一个精灵动画
- c# - 如何更快地更新或显示我的标签?(使用 Timer tick,间隔 1 ms 太慢了)
- javascript - 如何在 iframe 中的光标位置获取元素?
- reactjs - React 应用文件夹的节点模块占用 40gb
- java - 修复 'java.lang.NoClassDefFoundError: org/apache/curator/RetryPolicy' Maven
- java - 表未在 Spring Boot H2 中创建
- node.js - 文件中的字节大小值与文件中实际的字节数不同
- python - 嵌套列表理解中的嵌套条件