Npgsql - 使用 "GENERATED ALWAYS AS IDENTITY"
Npgsql - Using "GENERATED ALWAYS AS IDENTITY"
我目前正在尝试使用 Npgsql(版本 3.1.3)将记录插入 table,并使用官方文档 (Npgsql.org) 生成身份。但我总是得到错误:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> Npgsql.PostgresException (0x80004005): 428C9: cannot insert into column "mitteilung_id"
我已经找到了几个关于这个主题的问题,但它们要么已经过时(版本 2 或更低),要么不起作用。
我的项目结构如下。 table 定义如下所示:
CREATE TABLE mitteilung
(
mitteilung_id INTEGER GENERATED ALWAYS AS IDENTITY
CONSTRAINT mitteilung_pk
PRIMARY KEY,
betreff TEXT
CONSTRAINT mitteilung_nn_betreff
CHECK (betreff IS NOT NULL)
CONSTRAINT mitteilung_ck_length_betreff
CHECK (length(betreff) <= 100),
nachricht TEXT
CONSTRAINT mitteilung_ck_length_nachricht
CHECK (length(nachricht) <= 500)
CONSTRAINT mitteilung_nn_nachricht
CHECK (nachricht IS NOT NULL),
erfasst_am TIMESTAMP WITH TIME ZONE
CONSTRAINT mitteilung_nn_erfasst_am
CHECK (erfasst_am IS NOT NULL)
);
我定义的实体如下:
public class Mitteilung : ISlongooEntity
{
public int MitteilungId { get; set; }
...
我也试过给ID添加以下属性属性:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
在数据库上下文中,我测试了以下设置来解决问题。
modelBuilder.Entity<Mitteilung>()
.Property(b => b.MitteilungId)
.UseIdentityAlwaysColumn();
modelBuilder.Entity<Mitteilung>()
.Property(b => b.MitteilungId)
.Metadata.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.IdentityAlwaysColumn);
modelBuilder.Entity<Mitteilung>()
.Property(b => b.MitteilungId)
.Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
但无论我使用哪种组合设置,在尝试保存实体时都会收到上述错误消息。我也不太明白为什么在进行更新时会尝试更新 ID。我做错了什么?
public Mitteilung Save(Mitteilung obj)
{
var addedObj = Context.Mitteilungen.Add(obj);
// Context.Entry(obj).Property(x => x.MitteilungId).IsModified = false;
Context.SaveChanges();
return addedObj.Entity;
}
下面的代码可以正常工作。
请注意,EF Core 会自动检测到 MitteilungId
是 Mitteilung
的主键,并且由于它是一个 int,因此会将其设置为 GENERATED BY DEFAULT AS IDENTITY
。换句话说,您不需要任何流畅的 API 调用 - 或者 [Key]
或 [DatabaseGenerated]
注释 - EF Core 将按照约定正确设置。
如果出于某种原因,您需要 GENERATED ALWAYS AS IDENTITY
(而不是 BY DEFAULT
),则可以使用下面的流畅 API 调用。
如果问题仍然存在,能否更改下面的代码示例以产生错误?
class Program
{
static async Task Main(string[] args)
{
await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();
ctx.Blogs.Add(new Mitteilung { Name = "foo" });
await ctx.SaveChangesAsync();
}
}
public class BlogContext : DbContext
{
public DbSet<Mitteilung> Blogs { get; set; }
static ILoggerFactory ContextLoggerFactory
=> LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql("...")
.EnableSensitiveDataLogging()
.UseLoggerFactory(ContextLoggerFactory);
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Mitteilung>()
.Property(b => b.MitteilungId)
.UseIdentityAlwaysColumn();
}
}
public class Mitteilung
{
public int MitteilungId { get; set; }
public string Name { get; set; }
}
我目前正在尝试使用 Npgsql(版本 3.1.3)将记录插入 table,并使用官方文档 (Npgsql.org) 生成身份。但我总是得到错误:
Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details.
---> Npgsql.PostgresException (0x80004005): 428C9: cannot insert into column "mitteilung_id"
我已经找到了几个关于这个主题的问题,但它们要么已经过时(版本 2 或更低),要么不起作用。
我的项目结构如下。 table 定义如下所示:
CREATE TABLE mitteilung
(
mitteilung_id INTEGER GENERATED ALWAYS AS IDENTITY
CONSTRAINT mitteilung_pk
PRIMARY KEY,
betreff TEXT
CONSTRAINT mitteilung_nn_betreff
CHECK (betreff IS NOT NULL)
CONSTRAINT mitteilung_ck_length_betreff
CHECK (length(betreff) <= 100),
nachricht TEXT
CONSTRAINT mitteilung_ck_length_nachricht
CHECK (length(nachricht) <= 500)
CONSTRAINT mitteilung_nn_nachricht
CHECK (nachricht IS NOT NULL),
erfasst_am TIMESTAMP WITH TIME ZONE
CONSTRAINT mitteilung_nn_erfasst_am
CHECK (erfasst_am IS NOT NULL)
);
我定义的实体如下:
public class Mitteilung : ISlongooEntity
{
public int MitteilungId { get; set; }
...
我也试过给ID添加以下属性属性:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
在数据库上下文中,我测试了以下设置来解决问题。
modelBuilder.Entity<Mitteilung>()
.Property(b => b.MitteilungId)
.UseIdentityAlwaysColumn();
modelBuilder.Entity<Mitteilung>()
.Property(b => b.MitteilungId)
.Metadata.SetValueGenerationStrategy(NpgsqlValueGenerationStrategy.IdentityAlwaysColumn);
modelBuilder.Entity<Mitteilung>()
.Property(b => b.MitteilungId)
.Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore);
但无论我使用哪种组合设置,在尝试保存实体时都会收到上述错误消息。我也不太明白为什么在进行更新时会尝试更新 ID。我做错了什么?
public Mitteilung Save(Mitteilung obj)
{
var addedObj = Context.Mitteilungen.Add(obj);
// Context.Entry(obj).Property(x => x.MitteilungId).IsModified = false;
Context.SaveChanges();
return addedObj.Entity;
}
下面的代码可以正常工作。
请注意,EF Core 会自动检测到 MitteilungId
是 Mitteilung
的主键,并且由于它是一个 int,因此会将其设置为 GENERATED BY DEFAULT AS IDENTITY
。换句话说,您不需要任何流畅的 API 调用 - 或者 [Key]
或 [DatabaseGenerated]
注释 - EF Core 将按照约定正确设置。
如果出于某种原因,您需要 GENERATED ALWAYS AS IDENTITY
(而不是 BY DEFAULT
),则可以使用下面的流畅 API 调用。
如果问题仍然存在,能否更改下面的代码示例以产生错误?
class Program
{
static async Task Main(string[] args)
{
await using var ctx = new BlogContext();
await ctx.Database.EnsureDeletedAsync();
await ctx.Database.EnsureCreatedAsync();
ctx.Blogs.Add(new Mitteilung { Name = "foo" });
await ctx.SaveChangesAsync();
}
}
public class BlogContext : DbContext
{
public DbSet<Mitteilung> Blogs { get; set; }
static ILoggerFactory ContextLoggerFactory
=> LoggerFactory.Create(b => b.AddConsole().AddFilter("", LogLevel.Information));
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
=> optionsBuilder
.UseNpgsql("...")
.EnableSensitiveDataLogging()
.UseLoggerFactory(ContextLoggerFactory);
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Mitteilung>()
.Property(b => b.MitteilungId)
.UseIdentityAlwaysColumn();
}
}
public class Mitteilung
{
public int MitteilungId { get; set; }
public string Name { get; set; }
}