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

Posted

技术标签:

【中文标题】如何告诉 Entity Framework 我的 ID 列是自动递增的(AspNet Core 2.0 + PostgreSQL)?【英文标题】:How to tell Entity Framework that my ID column is auto-incremented (AspNet Core 2.0 + PostgreSQL)? 【发布时间】:2018-10-16 13:59:16 【问题描述】:

代码很简单。 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; 

HomeController.cs类:

public async Task<IActionResult> Index()

   tagRepository.Insert(new Tag 
                
                   Name = "name", 
                   Description = "description" 
               );
   await UnitOfWork.SaveChangesAsync();  // calls dbContext.SaveChangesAsync()

   return View();

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;

Tag 表是通过运行创建的:

CREATE TABLE Tag (
    ID SERIAL PRIMARY KEY,
    Name text NOT NULL,
    Description text NULL
);

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

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()

如您所见,Entity Framework 尝试将 id=0 值发送到 DB,但我的 DB 中已经有一条带有 id=0 的记录,这就是它抛出 duplicate key 错误的原因。

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

【问题讨论】:

【参考方案1】:

在浪费了大量时间研究之后,我完全出乎意料地解决了这个问题。实际上,我的问题的解决方案就在表面上,因为问题不在 EF 中,也不在它的东西上。就我而言,它是SEQUENCE。我的意思是,涉及的表有序列列,相关的序列只是被一些副作用改变了。换句话说 - 序列从 1 重新启动,同时表已经具有 1、2、3 等值。这就是 postgres 抛出 'duplicate key' 错误的原因。所以,解决办法是:

ALTER SEQUENCE "your_table_seq" RESTART WITH your_value;

【讨论】:

【参考方案2】:

根据the Postgre SQL docs,这里有一个例子,它展示了如何达到预期的结果:

protected override void OnModelCreating(ModelBuilder modelBuilder)
   => modelBuilder.Entity<Blog>().Property(b => b.Id).UseIdentityAlwaysColumn();

【讨论】:

.UseIdentityAlwaysColumn() 无法解析。您使用的是什么 EF Core 版本? 顺便说一句,我试过 UseNpgsqlIdentityAlwaysColumn()UseNpgsqlSerialColumn() - 这些都不起作用 @anatol,嗨。 Microsoft.EntityFrameworkCore.Design - 3.1.3; Microsoft.EntityFrameworkCore.Tools - 3.1.3; Npgsql.EntityFrameworkCore.PostgreSQL - 3.1.3.【参考方案3】:

你必须在这里使用“ValueGenerationOnAdd()”。由于您遇到的问题已在 GitHub 上报告。请找到以下链接。

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

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

Value generated on add

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 Descriptionget;set;
  

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

希望这会有所帮助

【讨论】:

我已经从现有数据库生成了上下文(使用命令Scaffold-DbContext),有趣的是我在所有实体中的所有id 属性都是用.Property(p =&gt; p.Id).ValueGeneratedNever() 生成的。我猜这可能是一个错误。无论如何,我已经用.ValueGeneratedOnAdd() 替换了它并且它可以工作。感谢您的链接和解释。 我使用ValueGeneratedOnAdd() 自动创建id,但是不起作用。感谢您或@AndreyKotov 可以看看。见***.com/questions/59673778/… 仅供参考,如果您的属性被称为 Id 或 TagId,您不需要手动设置 ValueGeneratedOnAdd - 按照惯例,这是为您完成的(参见 docs.microsoft.com/en-us/ef/core/modeling/… 和 docs.microsoft.com/en-us/ef/core/modeling/…)。 答案中提到的来源与问题无关。问题是关于 Postgre SQL,而不是关于 SQL Server。所以,答案对我不起作用。

以上是关于如何告诉 Entity Framework 我的 ID 列是自动递增的(AspNet Core 2.0 + PostgreSQL)?的主要内容,如果未能解决你的问题,请参考以下文章

如何扩展 Entity Framework 6 模型

如何使用 Entity Framework Code First 让我的数据库播种?

如何在 Entity Framework 4.4 中实现 DBSet.AddOrUpdate?

如何将 Entity Framework 4.1 与 MVC 3 登录一起使用

如何让 Visual Studio 发布 Web 向导相信我的数据库是 Entity Framework CodeFirst?

Entity Framework 3.5 - 如何加载孩子