You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core MVC Code-First带枚举与索引的复杂关系配置问题

解决方案

前置实体调整

先删除InputFile类中int Id属性上的[Key]特性,避免单主键和后续配置的联合主键冲突;如果你不需要单独的自增Id字段,也可以直接移除该属性。

OnModelCreating 完整配置

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    // 1. 配置InputFile联合主键
    modelBuilder.Entity<InputFile>()
        .HasKey(i => new { i.InputFileType, i.ScraperUploadClassId });
    
    // 可选:如果保留原Id字段,配置为自增非主键字段
    // modelBuilder.Entity<InputFile>()
    //     .Property(i => i.Id)
    //     .ValueGeneratedOnAdd();

    // 2. 配置一对多关联
    // ConfirmationFiles 对应 ConfirmationFile 类型的InputFile
    modelBuilder.Entity<ScraperUploadClass>()
        .HasMany(s => s.ConfirmationFiles)
        .WithOne(i => i.ScraperUploadClass)
        .HasForeignKey(i => i.ScraperUploadClassId)
        .HasFilter($"{nameof(InputFile.InputFileType)} = {(int)InputFileTypes.ConfirmationFile}")
        .OnDelete(DeleteBehavior.Restrict);

    // PrestationFiles 对应 PrestationFile 类型的InputFile
    modelBuilder.Entity<ScraperUploadClass>()
        .HasMany(s => s.PrestationFiles)
        .WithOne(i => i.ScraperUploadClass)
        .HasForeignKey(i => i.ScraperUploadClassId)
        .HasFilter($"{nameof(InputFile.InputFileType)} = {(int)InputFileTypes.PrestationFile}")
        .OnDelete(DeleteBehavior.Restrict);

    // 3. 配置一对一关联
    // EocChoiceFile 对应 EOCChoiceFile 类型
    modelBuilder.Entity<ScraperUploadClass>()
        .HasOne(s => s.EocChoiceFile)
        .WithOne()
        .HasPrincipalKey<InputFile>(i => i.ScraperUploadClassId)
        .HasForeignKey<ScraperUploadClass>(s => s.ID)
        .HasFilter($"{nameof(InputFile.InputFileType)} = {(int)InputFileTypes.EOCChoiceFile}")
        .OnDelete(DeleteBehavior.Restrict);

    // EocReplaceFile 对应 EOCReplaceFile 类型
    modelBuilder.Entity<ScraperUploadClass>()
        .HasOne(s => s.EocReplaceFile)
        .WithOne()
        .HasPrincipalKey<InputFile>(i => i.ScraperUploadClassId)
        .HasForeignKey<ScraperUploadClass>(s => s.ID)
        .HasFilter($"{nameof(InputFile.InputFileType)} = {(int)InputFileTypes.EOCReplaceFile}")
        .OnDelete(DeleteBehavior.Restrict);

    // CareStaffFile 对应 CareStaffFile 类型
    modelBuilder.Entity<ScraperUploadClass>()
        .HasOne(s => s.CareStaffFile)
        .WithOne()
        .HasPrincipalKey<InputFile>(i => i.ScraperUploadClassId)
        .HasForeignKey<ScraperUploadClass>(s => s.ID)
        .HasFilter($"{nameof(InputFile.InputFileType)} = {(int)InputFileTypes.CareStaffFile}")
        .OnDelete(DeleteBehavior.Restrict);

    // JobCreationFile 对应 JobCreationFile 类型
    modelBuilder.Entity<ScraperUploadClass>()
        .HasOne(s => s.JobCreationFile)
        .WithOne()
        .HasPrincipalKey<InputFile>(i => i.ScraperUploadClassId)
        .HasForeignKey<ScraperUploadClass>(s => s.ID)
        .HasFilter($"{nameof(InputFile.InputFileType)} = {(int)InputFileTypes.JobCreationFile}")
        .OnDelete(DeleteBehavior.Restrict);

    // NurseTitlesFile 对应 NurseTitleFile 类型
    modelBuilder.Entity<ScraperUploadClass>()
        .HasOne(s => s.NurseTitlesFile)
        .WithOne()
        .HasPrincipalKey<InputFile>(i => i.ScraperUploadClassId)
        .HasForeignKey<ScraperUploadClass>(s => s.ID)
        .HasFilter($"{nameof(InputFile.InputFileType)} = {(int)InputFileTypes.NurseTitleFile}")
        .OnDelete(DeleteBehavior.Restrict);
}

注意事项

  • 所有关联都设置了DeleteBehavior.Restrict,避免循环级联删除导致迁移报错
  • 过滤条件的语法适配SQL Server,如果你使用MySQL等其他数据库,需要将字段名的包裹符从方括号改为反引号
  • 如果之前已经生成过迁移文件,需要删除旧的迁移文件和数据库快照,重新执行Add-Migration命令生成新的迁移,避免历史配置冲突

内容的提问来源于stack exchange,提问作者Luc Van den Borre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 23:39:05