【发布时间】:2020-01-07 06:04:43
【问题描述】:
少量上下文,我已经使用 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();
}
【问题讨论】:
标签: entity-framework entity-framework-core relationship one-to-many ef-core-2.2