如何告诉Entity Framework我的ID列是自动递增的(AspNet Core 2.0 + PostgreSQL)?

And*_*tov 11 auto-increment npgsql entity-framework-core asp.net-core

代码很简单. Tag.cs实体:

public partial class Tag
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

HomeController.cs 类:

public async Task<IActionResult> Index()
{
   tagRepository.Insert(new Tag 
               { 
                   Name = "name", 
                   Description = "description" 
               });
   await UnitOfWork.SaveChangesAsync();  // calls dbContext.SaveChangesAsync()

   return View();
}
Run Code Online (Sandbox Code Playgroud)

TagRepository.cs 类:

    // Context it's a usual DBContext injected via Repository's constructor
    public virtual void Insert(TEntity item)
                => Context.Entry(item).State = EntityState.Added;
Run Code Online (Sandbox Code Playgroud)

Tag 表是通过运行创建的:

CREATE TABLE Tag (
    ID SERIAL PRIMARY KEY,
    Name text NOT NULL,
    Description text NULL
);
Run Code Online (Sandbox Code Playgroud)

运行我的应用程序时出现错误:

fail: Microsoft.EntityFrameworkCore.Database.Command[20102]
      Failed executing DbCommand (28ms) [Parameters=[@p0='?', @p1='?', @p2='?'], CommandType='Text', CommandTimeout='30']
      INSERT INTO "tag" ("id", "description", "name")
      VALUES (@p0, @p1, @p2);
Npgsql.PostgresException (0x80004005): 23505: duplicate key value violates unique constraint "tag_pkey"
   at Npgsql.NpgsqlConnector.<DoReadMessage>d__157.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   at Npgsql.NpgsqlConnector.<ReadMessage>d__156.MoveNext()
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,Entity Framework尝试向id=0DB 发送值,但是id=0在我的数据库中已有记录,这就是它抛出duplicate key错误的原因.

到目前为止我没有找到任何答案,我的问题是:如何摆脱这个错误并告诉Entity Framework我的id列是自动递增的,而且不需要更新它?

Tri*_*mar 11

你必须在这里使用"ValueGenerationOnAdd()".因为您正在获得的问题已在GitHub上报告.请找到以下链接.

https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/73

您可以从以下链接中找到有关生成值模式的更多信息.

添加时生成的值

public classs SampleContext:DBContext{
public DbSet<Tag> Tag { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder){
    modelBuilder.Entity<Tag>()
        .Property(p => p.ID)
        .ValueGeneratedOnAdd();
 }
public class Tag{
  public int Id { get; set; }
  public string Name { get; set; }
  public string Description{get;set;}
  }
}
Run Code Online (Sandbox Code Playgroud)

资料来源: - https://www.learnentityframeworkcore.com/configuration/fluent-api/valuegeneratedonadd-method

希望这会有所帮助

  • 我已经从现有数据库生成了上下文(使用命令 `Scaffold-DbContext`),有趣的是,所有实体中的所有 `id` 属性都是使用 `.Property(p =&gt; p.Id).ValueGenerateNever()` 生成的。我猜这可能是一个错误。无论如何,我已将其替换为“.ValueGenerateOnAdd()”并且它有效。感谢您的链接和解释。 (2认同)

man*_*ore 5

根据Postgre SQL 文档,这里有一个示例,展示了如何实现所需的结果:

protected override void OnModelCreating(ModelBuilder modelBuilder)
   => modelBuilder.Entity<Blog>().Property(b => b.Id).UseIdentityAlwaysColumn();
Run Code Online (Sandbox Code Playgroud)