如何告诉 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)?
代码很简单。
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
class:
public async Task<IActionResult> Index()
{
tagRepository.Insert(new Tag
{
Name = "name",
Description = "description"
});
await UnitOfWork.SaveChangesAsync(); // calls dbContext.SaveChangesAsync()
return View();
}
TagRepository.cs
class:
// Context it's a usual DBContext injected via Repository's constructor
public virtual void Insert(TEntity item)
=> Context.Entry(item).State = EntityState.Added;
Tag
table 由 运行ning 创建:
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
值发送到数据库,但我的数据库中已经有一条包含 id=0
的记录,这就是它抛出 [=22] 的原因=]错误。
到目前为止我没有找到任何答案,我的问题是:我怎样才能摆脱这个错误并告诉 Entity Framework 我的 id
列是自动递增的并且没有需要更新吗?
你必须在这里使用"ValueGenerationOnAdd()"。由于您遇到的问题已在 GitHub 上报告。请找到下面的 link.
https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/73
您可以从以下 link.
中找到有关生成值模式的更多信息
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;}
}
}
来源:- https://www.learnentityframeworkcore.com/configuration/fluent-api/valuegeneratedonadd-method
希望这会有所帮助
根据the Postgre SQL docs,这里有一个示例,说明如何实现预期结果:
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().Property(b => b.Id).UseIdentityAlwaysColumn();
经过大量浪费时间研究后,我完全出乎意料地解决了这个问题。实际上,我的问题的解决方案就在表面上,因为问题不在 EF 中,也不在它的东西中。在我的例子中是 SEQUENCE
。我的意思是,涉及的 table 有序列列,相关序列只是被一些副作用改变了。换句话说 - 序列从 1 重新开始,同时 table 已经具有 1、2、3 ...等的值。这就是为什么 postgres 抛出 'duplicate key'错误。所以,解决方案是:
ALTER SEQUENCE "your_table_seq" RESTART WITH your_value;
代码很简单。
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
class:
public async Task<IActionResult> Index()
{
tagRepository.Insert(new Tag
{
Name = "name",
Description = "description"
});
await UnitOfWork.SaveChangesAsync(); // calls dbContext.SaveChangesAsync()
return View();
}
TagRepository.cs
class:
// Context it's a usual DBContext injected via Repository's constructor
public virtual void Insert(TEntity item)
=> Context.Entry(item).State = EntityState.Added;
Tag
table 由 运行ning 创建:
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
值发送到数据库,但我的数据库中已经有一条包含 id=0
的记录,这就是它抛出 [=22] 的原因=]错误。
到目前为止我没有找到任何答案,我的问题是:我怎样才能摆脱这个错误并告诉 Entity Framework 我的 id
列是自动递增的并且没有需要更新吗?
你必须在这里使用"ValueGenerationOnAdd()"。由于您遇到的问题已在 GitHub 上报告。请找到下面的 link.
https://github.com/npgsql/Npgsql.EntityFrameworkCore.PostgreSQL/issues/73
您可以从以下 link.
中找到有关生成值模式的更多信息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;}
}
}
来源:- https://www.learnentityframeworkcore.com/configuration/fluent-api/valuegeneratedonadd-method
希望这会有所帮助
根据the Postgre SQL docs,这里有一个示例,说明如何实现预期结果:
protected override void OnModelCreating(ModelBuilder modelBuilder)
=> modelBuilder.Entity<Blog>().Property(b => b.Id).UseIdentityAlwaysColumn();
经过大量浪费时间研究后,我完全出乎意料地解决了这个问题。实际上,我的问题的解决方案就在表面上,因为问题不在 EF 中,也不在它的东西中。在我的例子中是 SEQUENCE
。我的意思是,涉及的 table 有序列列,相关序列只是被一些副作用改变了。换句话说 - 序列从 1 重新开始,同时 table 已经具有 1、2、3 ...等的值。这就是为什么 postgres 抛出 'duplicate key'错误。所以,解决方案是:
ALTER SEQUENCE "your_table_seq" RESTART WITH your_value;