如何在 EF Core 中的自动递增 table 上显式设置 ID 属性
How to explicitly set the ID property on an autoincrementing table in EFCore
我有一个模型,默认情况下它有一个自动递增的 ID 字段,这是正常的。但是,我希望用初始数据播种数据库,因为有外键,我希望明确设置播种数据的 ID。
我的模型
public class EntAttribute
{
public int ID { get; set; }
public string Title { get; set; }
}
我的播种代码:
public class Seeder
{
private class AllAttributes
{
public List<EntAttribute> Attributes { get; set; }
}
public bool SeedData()
{
AllAttributes seedAttributes;
string strSource;
JsonSerializer JsonSer = new JsonSerializer();
strSource = System.IO.File.ReadAllText(@"Data/SeedData/Attributes.json");
seedAttributes = JsonConvert.DeserializeObject<AllAttributes>(strSource);
_context.AddRange(seedAttributes.Attributes);
_context.SaveChanges();
return true;
}
}
请注意,我对 EFCore 和 C# 都很陌生。以上是我设法拼凑的内容,在我保存更改之前它似乎一直有效。此时我得到:
SqlException:当 IDENTITY_INSERT 设置为 OFF 时,无法在 table 'Attribute' 中为标识列插入显式值。
现在我足够聪明,知道这是因为我无法在 EntAttribute table 中显式设置 ID 字段,因为它想通过自动递增分配自己的 ID 字段。但是我不够聪明,不知道该怎么办。
感谢任何帮助。
编辑:根据下面接受的答案添加解决方案,因为实际代码可能会帮助其他人...
所以我在上下文 class 中添加了以下内容:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("EntAttributeNumbering")
.StartsAt(10);
modelBuilder.Entity<EntAttribute>()
.Property(i => i.ID)
.HasDefaultValueSql("NEXT VALUE FOR EntAttributeNumbering");
}
这首先确保创建了一个序列(名称是任意的),然后将其设置为用于相关的 table 而不是自动递增。完成此操作后,我就可以使用我的种子数据了。记录少于 10 条,所以我只需要将序列的起始值设置为 10。更多通常是有意义的,但我知道永远不会更多。
我还不得不对我的迁移进行闪电战,因为它们以某种方式搞得一团糟,但这可能无关紧要。
使用 EF Core,您可以创建并使用 Sequence 对象来分配 ID,并且您可以通过选择序列开始的位置来保留一系列 ID 以供手动分配。使用序列,您可以自己分配 ID,或让数据库为您完成。
仅供使用 EF Core 3 的人参考,如果您使用 int 作为您的密钥,您可以设置开始序列值,以防您有种子数据。我发现在我只有一个种子记录的用例中解决这个问题要干净得多。
例如
modelBuilder.Entity<TableA>()
.Property(p => p.TableAId)
.HasIdentityOptions(startValue: 2);
modelBuilder.Entity<TableA>()
.HasData(
new TableA
{
TableAId = 1,
Data = "something"
});
https://github.com/npgsql/efcore.pg/issues/367#issuecomment-602111259
我有一个模型,默认情况下它有一个自动递增的 ID 字段,这是正常的。但是,我希望用初始数据播种数据库,因为有外键,我希望明确设置播种数据的 ID。
我的模型
public class EntAttribute
{
public int ID { get; set; }
public string Title { get; set; }
}
我的播种代码:
public class Seeder
{
private class AllAttributes
{
public List<EntAttribute> Attributes { get; set; }
}
public bool SeedData()
{
AllAttributes seedAttributes;
string strSource;
JsonSerializer JsonSer = new JsonSerializer();
strSource = System.IO.File.ReadAllText(@"Data/SeedData/Attributes.json");
seedAttributes = JsonConvert.DeserializeObject<AllAttributes>(strSource);
_context.AddRange(seedAttributes.Attributes);
_context.SaveChanges();
return true;
}
}
请注意,我对 EFCore 和 C# 都很陌生。以上是我设法拼凑的内容,在我保存更改之前它似乎一直有效。此时我得到:
SqlException:当 IDENTITY_INSERT 设置为 OFF 时,无法在 table 'Attribute' 中为标识列插入显式值。
现在我足够聪明,知道这是因为我无法在 EntAttribute table 中显式设置 ID 字段,因为它想通过自动递增分配自己的 ID 字段。但是我不够聪明,不知道该怎么办。
感谢任何帮助。
编辑:根据下面接受的答案添加解决方案,因为实际代码可能会帮助其他人...
所以我在上下文 class 中添加了以下内容:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasSequence<int>("EntAttributeNumbering")
.StartsAt(10);
modelBuilder.Entity<EntAttribute>()
.Property(i => i.ID)
.HasDefaultValueSql("NEXT VALUE FOR EntAttributeNumbering");
}
这首先确保创建了一个序列(名称是任意的),然后将其设置为用于相关的 table 而不是自动递增。完成此操作后,我就可以使用我的种子数据了。记录少于 10 条,所以我只需要将序列的起始值设置为 10。更多通常是有意义的,但我知道永远不会更多。
我还不得不对我的迁移进行闪电战,因为它们以某种方式搞得一团糟,但这可能无关紧要。
使用 EF Core,您可以创建并使用 Sequence 对象来分配 ID,并且您可以通过选择序列开始的位置来保留一系列 ID 以供手动分配。使用序列,您可以自己分配 ID,或让数据库为您完成。
仅供使用 EF Core 3 的人参考,如果您使用 int 作为您的密钥,您可以设置开始序列值,以防您有种子数据。我发现在我只有一个种子记录的用例中解决这个问题要干净得多。
例如
modelBuilder.Entity<TableA>()
.Property(p => p.TableAId)
.HasIdentityOptions(startValue: 2);
modelBuilder.Entity<TableA>()
.HasData(
new TableA
{
TableAId = 1,
Data = "something"
});
https://github.com/npgsql/efcore.pg/issues/367#issuecomment-602111259