postgresql - 如何使用实体框架播种迁移重新启动 postgres 序列?
问题描述
我有以下数据库播种机:
public partial class Seed_Languages : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.InsertData(
table: "Languages",
columns: new[] { "LanguageId", "LangCode", "LangName", "Sort" },
values: new object[,]
{
{ 1, "AU", "Австралия", 0 },
{ 159, "CX", "Остров Рождества", 0 },
{ 160, "PN", "Острова Питкэрн", 0 },
{ 161, "SH", "Острова Святой Елены, Вознесения и Тристан-да-Кунья", 0 },
{ 162, "PK", "Пакистан", 0 },
{ 163, "PW", "Палау", 0 },
.... and so on ...
如您所见,我将填充一些表格,其中包含语言名称(在俄语上,用于在 UI 上显示)、语言代码、一些附加字段Sort
(此处不重要)和主键。很简单,对吧?这是表格:
然后我在我的内部创建它OnModelCreating
:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// many fluent api calls
LanguagesSeeder.SeedLanguages(modelBuilder);
}
然后我运行$ dotnet ef database update
并且播种工作正常!但问题很快就开始了。
当我尝试插入新的一种语言时,.NET 给了我:
异常数据:严重性:错误SqlState:23505 MessageText:重复键值违反唯一约束“PK_Languages”详细信息:键(“LanguageId”)=(1)已存在。架构名称:公共表名称:语言约束名称:PK_Languages 文件:nbtinsert.c 行:434
“嗯,让我们再试一次” - 我想。和:
异常数据:严重性:错误SqlState:23505 MessageText:重复键值违反唯一约束“PK_Languages”详细信息:键(“LanguageId”)=(2)已存在。架构名称:公共表名称:语言约束名称:PK_Languages 文件:nbtinsert.c 行:434 例程:_bt_check_unique
你看到了吗?同样的错误,但有另一个主键投诉!第一个是:Key ("LanguageId")=(1) already exists.
第二个Key ("LanguageId")=(2) already exists.
!
那么该怎么办?我知道这样:
ALTER SEQUENCE <name of sequence> RESTART WITH <your number is here>;
但是在播种后在控制台中运行这个 SQL 是很不舒服的。我错过了什么吗?也许,有一个标准的方法,我的意思是使用一些 EF API?
更新
我将向您展示我的Language
模型:
namespace Domains
{
public class Language
{
public int LanguageId { get; set; }
public int Sort { get; set; }
public List<Customer> Customers { get; set; }
public List<PushMessageLang> PushMessageLangs { get; set; }
[NotMapped]
public IEnumerable<PushMessage> PushMessages
{
get => PushMessageLangs?.Select(r => r.PushMessage);
set => PushMessageLangs = value.Select(v => new PushMessageLang()
{
PushMessageId = v.PushMessageId
}).ToList();
}
public string LangName { get; set; }
public string LangCode { get; set; }
}
}
我通过我的存储库抽象进行插入:
基础存储库:
public class BaseRepository<T, C> : IRepository<T>
where T : class
where C : DbContext
{
protected C DataContext;
private readonly DbSet<T> _dbset;
public BaseRepository(C context)
{
DataContext = context;
_dbset = context.Set<T>();
}
public virtual IQueryable<T> All => _dbset;
public virtual async Task SaveAsync(T entity)
{
await _dbset.AddAsync(entity);
await DataContext.SaveChangesAsync();
}
public async Task SaveAsync(List<T> entity)
{
await _dbset.AddRangeAsync(entity);
await DataContext.SaveChangesAsync();
}
public virtual async Task UpdateAsync(T entity)
{
_dbset.Attach(entity).State = EntityState.Modified;
_dbset.Update(entity);
await DataContext.SaveChangesAsync();
}
public virtual async Task DeleteAsync(int id)
{
var dbEntity = await _dbset.FindAsync(id);
if (dbEntity != null)
{
_dbset.Remove(dbEntity);
await DataContext.SaveChangesAsync();
}
}
}
在控制器中:
public async Task<IActionResult> Create([FromForm] LanguageViewModel viewModel)
{
if (!ModelState.IsValid)
{
return View(viewModel);
}
var newLanguage = new Language()
{
Sort = viewModel.Sort,
LangCode = viewModel.Code,
LangName = viewModel.Name
};
await _languageRepository.SaveAsync(newLanguage);
return RedirectToAction("Index");
}
更新 2
正如评论中所问的,我将在这里为Language
模型添加所有流利的 api:
// many to many with `Message` entity
modelBuilder.Entity<PushMessageLang>()
.HasKey(bc => new { bc.PushLangId, bc.PushMessageId });
modelBuilder.Entity<PushMessageLang>()
.HasOne(bc => bc.Language)
.WithMany(b => b.PushMessageLangs)
.HasForeignKey(bc => bc.PushLangId)
.OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<PushMessageLang>()
.HasOne(bc => bc.PushMessage)
.WithMany(c => c.PushMessageLangs)
.HasForeignKey(bc => bc.PushMessageId)
.OnDelete(DeleteBehavior.Cascade);
// has unique language code
modelBuilder.Entity<Language>()
.HasIndex(x => x.LangCode).IsUnique();
更新 3
正如@Roman Marusyk 所问,我在这里使用SQL 脚本来创建Languages
表。
-- auto-generated definition
create table "Languages"
(
"LanguageId" integer generated by default as identity
constraint "PK_Languages"
primary key,
"LangName" text,
"LangCode" text,
"Sort" integer default 0 not null
);
alter table "Languages"
owner to makeapp_pushes;
create unique index "IX_Languages_LangCode"
on "Languages" ("LangCode");
嗯,现在我看到没有关于自动增量的任何内容。但我的 SQL 客户端显示了我的:
解决方案
添加HasKey
到模型配置
modelBuilder.Entity<Language>()
.HasKey(x => x.LanguageId)
.HasIndex(x => x.LangCode).IsUnique();
正如@IvanStoev 提到的,按照惯例,该属性LanguageId
已经是主键
尝试指定
modelBuilder.Entity<Language>()
.Property(p => p.LanguageId)
.ValueGeneratedOnAdd();
推荐阅读
- typescript - Rxjs forkJoin 不适用于多个主题
- java - 链表面试题
- javascript - 当我使用“await”为函数创建变量时,此函数会立即运行还是仅在我调用此变量时运行?
- amazon-web-services - S3/Athena 查询结果位置和“无效的 S3 文件夹位置”
- python - 带有 Sklearn 的 MNIST 数据集
- reactjs - 在 React 中的其他组件中渲染组件
- algorithm - 为什么我在构建 LL(1) 表时从 Dragon Book 得到不同的结果?
- android - 为什么扩展工厂不起作用?有任何想法吗?
- swift - SwiftUI 创建以点为指标的图像滑块
- python - 当字符串索引是整数时,“字符串索引必须是整数错误”