使用 Entity Framework Core 自动增加部分主键
Posted
技术标签:
【中文标题】使用 Entity Framework Core 自动增加部分主键【英文标题】:Auto-increment on partial primary key with Entity Framework Core 【发布时间】:2016-07-09 09:38:16 【问题描述】:我已经使用 EF Core fluent API 声明了以下模型:
modelBuilder.Entity<Foo>()
.HasKey(p => new p.Name, p.Id );
当我在 PostgreSQL 中创建数据库时,这两个字段都标记为主键,但 Id 字段没有标记为自动增量。我也试过添加
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
到 Foo 下的 Id 字段,而不会对迁移代码产生任何影响。有没有办法制作 Id AI 虽然它是 PPK?
【问题讨论】:
你的Id
属性是什么类型的?
Id 是 int,Name 是字符串
如果Id
是自动生成的数字,为什么还需要将Name
作为主键的一部分?
【参考方案1】:
好吧,那些数据注释应该可以解决问题,也许与 PostgreSQL 提供程序有关。
来自EF Core documentation:
根据所使用的数据库提供程序,可能会生成值 EF 或数据库中的客户端。如果该值是由 数据库,那么 EF 可能会在您添加实体时分配一个临时值 到上下文。然后这个临时值将被替换为
SaveChanges
期间数据库生成的值。
你也可以试试这个 Fluent Api 配置:
modelBuilder.Entity<Foo>()
.Property(f => f.Id)
.ValueGeneratedOnAdd();
但正如我之前所说,我认为这与数据库提供者有关。尝试向您的数据库添加新行,稍后检查是否为 Id
列生成了值。
【讨论】:
我已将此标记为答案,尽管我的代码尚未完全正常工作。这会在启动时引发异常,说“不支持为 int4 创建 IsIdentity”,所以我猜你是对的,这取决于数据库提供程序,到目前为止,他们似乎还没有实现对它的支持。 只是跟进,使用 PostgreSQL,您无法修改现有字段以成为 AI。这导致了我之前遇到的异常,所以我必须扔掉我的数据库,创建一个新的并放入所有数据。【参考方案2】:首先,您不应该将 Fluent Api 与数据注释合并,因此我建议您使用以下之一:
确保您已正确设置密钥
modelBuilder.Entity<Foo>()
.HasKey(p => new p.Name, p.Id );
modelBuilder.Entity<Foo>().Property(p => p.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
或者您也可以使用数据注释来实现它
public class Foo
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key, Column(Order = 0)]
public int Id get; set;
[Key, Column(Order = 1)]
public string Name get; set;
【讨论】:
不是他在fluent api中定义的时候,顺序是匿名对象中属性的顺序 HasDatabaseGeneratedOption 在我使用的版本(7.0.0-rc1-final)中似乎不存在,还是我缺少扩展或什么? 我认为这不能解决 OP 的问题。他正在将 Fluent Api(他在其中建立 Ids 顺序)与 Data Annotations(他指定Id
属性为 Identity)合并。我个人不喜欢合并这两个功能,但他的配置应该可以工作。我认为正在发生的事情更多地取决于数据库提供者。
@MassimilianoPeluso 但这不是问题,那部分首先在 OP 的代码中
我试图坚持使用流畅的 API,但据我所知,HasDatabaseGeneratedOption 仅存在于 EF6 而不是 EF7。还是我需要使用扩展程序才能访问该功能?【参考方案3】:
致所有遇到此问题的人,他们使用 SQL Server 数据库,即使在 int 主键上添加以下注释后仍然抛出异常
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id get; set;
请检查您的 SQL,确保您的主键旁边有 'IDENTITY(startValue, increment)',
CREATE TABLE [dbo].[User]
(
[Id] INT IDENTITY(1,1) NOT NULL PRIMARY KEY
)
这将使数据库在每次添加新行时增加id,起始值为1,增量为1。
我不小心忽略了在我的 SQL 中花费了我一个小时的生命, 所以希望这对某人有帮助!!!
【讨论】:
我仍然面临错误“当 IDENTITY_INSERT 设置为 OFF 时,无法在表 'User' 中插入标识列的显式值。” 我遇到同样的错误,我有 Id 和 Version 的主键,在更新时我想通过增加我的版本但保留 Id 来添加新条目,还没有找到一个好的解决方案。【参考方案4】:像下面这样注释属性
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID get; set;
要为新模型上的所有值生成属性使用标识列,只需将以下内容放在上下文的 OnModelCreating() 中:
builder.ForNpgsqlUseIdentityColumns();
这将使所有具有 .ValueGeneratedOnAdd() 的键和其他属性默认具有标识。您可以使用 ForNpgsqlUseIdentityAlwaysColumns() 来始终拥有 Identity,还可以使用 UseNpgsqlIdentityColumn() 和 UseNpgsqlIdentityAlwaysColumn() 逐个属性地指定身份。
postgres efcore value generation
【讨论】:
.netcore EF最新版本下,不推荐使用ForNpgsqlUseIdentityColumns,使用下面一行builder.UseIdentityColumns【参考方案5】:指定列类型为serial以便PostgreSQL生成id。
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Column(Order=1, TypeName="serial")]
public int ID get; set;
https://www.postgresql.org/docs/current/static/datatype-numeric.html#DATATYPE-SERIAL
【讨论】:
以上是关于使用 Entity Framework Core 自动增加部分主键的主要内容,如果未能解决你的问题,请参考以下文章
在 Entity Framework Core 中使用 [ComplexType]
在 Entity Framework Core 中使用 SQL 视图
使用 Entity Framework Core 更新相关数据