使用手动分配的Id插入带有EF Core的新实体

时间:2017-11-20 12:09:27

标签: c# mysql entity-framework-core asp.net-core-2.0

我需要在数据库中插入一个enitity,它有一个约束它的id,所以我想手动设置它。

注意:下面的模型是了解我正在做什么的最小例子。整个过程都在使用EF Core和Pomelo MySql提供程序的ASP.NET Core 2上运行。

我试图在我已经存在的数据库(MySQL)中创建一个如下定义的实体:

CREATE TABLE Users (
    id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
    email VARCHAR(128) NOT NULL);

CREATE TABLE UserData (
    id INTEGER PRIMARY KEY,
    name VARCHAR(32) NOT NULL,
    FOREIGN KEY(id) REFERENCES Users(id));

因此Users表中的每条记录都在UserData表中有记录。 现在在我的代码中我想使用像

这样的东西
Context.Users.Add(user);
Context.SaveChanges();
data.Id = user.Id;
Context.UserData.Add(data);
Context.SaveChanges();

User应该由数据库生成Id,然后使用UserData创建Id。但是,EF执行的语句会导致错误:

Failed executing DbCommand (6ms) [Parameters=[@p0='?', @p1='?' (Size = 32)], CommandType='Text', CommandTimeout='30']
  INSERT INTO `UserData` (`id`, `name`)
  VALUES (@p0, @p1);

MySql.Data.MySqlClient.MySqlException: Cannot add or update a child row:
  a foreign key constraint fails (`Main`.`UserData`, CONSTRAINT `UserData_ibfk_1`
  FOREIGN KEY (`id`) REFERENCES `Users` (`id`))

这意味着无论Id传递给MySQL,它都不是User的那个。

我甚至尝试按Entering keys manually with Entity Framework中的建议向[DatabaseGenerated(DatabaseGeneratedOption.None)]添加UserData.Id,但我认为更多关于CodeFirst方法而不是已经在运行数据库中。

从这个问题开始:EF Core Add function returns negative id我了解到Context.Add()修改了Id,但在Add之后分配我的值并没有改变任何内容。

如果它很重要,请参阅我的DbContext配置

modelBuilder.Entity<UserData>(entity =>
{
    entity.Property(e => e.Id)
        .HasColumnName("id")
        .HasColumnType("int(11)")
        .ValueGeneratedNever();

    entity.Property(e => e.Name)
        .IsRequired()
        .HasColumnName("name")
        .HasMaxLength(32);

    entity.HasOne(d => d.User)
        .WithOne(p => p.UserData)
        .HasForeignKey<UserData>(d => d.Id)
        .OnDelete(DeleteBehavior.ClientSetNull)
        .HasConstraintName("UserData_ibfk_1");
}
modelBuilder.Entity<User>(entity =>
{
    entity.Property(e => e.Id)
        .HasColumnName("id")
        .HasColumnType("int(11)")
        .ValueGeneratedNever();

    entity.Property(e => e.Email)
        .IsRequired()
        .HasColumnName("email")
        .HasMaxLength(128);
}

2 个答案:

答案 0 :(得分:1)

  

User应该获得数据库生成的Id

不符合您的流利配置:

modelBuilder.Entity<User>(entity =>
{
    entity.Property(e => e.Id)
        .HasColumnName("id")
        .HasColumnType("int(11)")
        .ValueGeneratedNever(); // <-- the problem
}

ValueGeneratedNever()替换为ValueGeneratedOnAdd(),问题将得到解决。

作为旁注,由于您似乎在UserUserData中都有导航属性,因此您可以使用它们而不是FK属性,因此无需中间SaveChanges只需获取生成的Id。例如,而不是:

Context.Users.Add(user);
Context.SaveChanges();
data.Id = user.Id;
Context.UserData.Add(data);
Context.SaveChanges();

你可以简单地使用:

user.UserData = data;
Context.Users.Add(user); // <-- will also add `UserData`
Context.SaveChanges();

EF将以正确的顺序插入两个记录(首先User,然后UserData,并使用上一个插入内容生成的Id

答案 1 :(得分:0)

事实证明,在添加新实体并执行

之后
VANETZA_DIR

新添加的对象未更新。从数据库中完成新的拉动后

Context.SaveChanges()

返回的实体具有正确的ID,分配给我的Context.Users.First(u => u.Email == user.Email); 已允许正确添加到表格中。