如何使用实体框架种子迁移来重新启动postgres序列?

问题描述 投票:1回答:2

我有以下数据库播种器:

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(此处不重要)和主键。简单吧?这是表格:

enter image description here

然后我在OnModelCreating中创建它:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder); 

   // many fluent api calls 
   LanguagesSeeder.SeedLanguages(modelBuilder);
}

然后我运行$ dotnet ef database update,播种正常!但是问题很快就开始了。

[当我尝试插入一种新语言时,.NET给了我:

异常数据:严重性:ERRORSqlState:23505MessageText:重复的键值违反了唯一约束“ PK_Languages”详细信息:键(“ LanguageId”)=(1)已存在。SchemaName:公共TableName:语言ConstraintName:PK_Languages档案:nbtinsert.c线:434

““嗯,让我们再试一次”-我想。和:

异常数据:严重性:ERRORSqlState:23505MessageText:重复的键值违反了唯一约束“ PK_Languages”详细信息:键(“ LanguageId”)=(2)已存在。SchemaName:公共TableName:语言ConstraintName: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的要求,我在这里介绍了用于创建Languages表的SQL脚本。

-- 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客户端显示了我的:

enter image description here

postgresql .net-core entity-framework-core seeding .net-core-3.1
2个回答
1
投票

HasKey添加到模型配置

HasKey

正如@IvanStoev所述,按照惯例,属性modelBuilder.Entity<Language>() .HasKey(x => x.LanguageId) .HasIndex(x => x.LangCode).IsUnique(); 已经是主键

尝试指定

LanguageId

0
投票

在迁移中,我已手动添加此字符串:

  modelBuilder.Entity<Language>()
        .Property(p => p.LanguageId)
        .ValueGeneratedOnAdd();

其中migrationBuilder.RestartSequence("Languages_LanguageId_seq", 251, "public"); -序列名称,Languages_LanguageId_seq-序列的起始编号(PK值),251-方案名称。

这里是public。现在,我可以插入而没有任何错误。

© www.soinside.com 2019 - 2024. All rights reserved.