.net 如何使用EF在数据库中插入三角关系

zi8p0yeb  于 2023-04-22  发布在  .NET
关注(0)|答案(1)|浏览(100)

你好,我有一个数据库与3表设计在一个三角形像下面:

File  has many Page 
Page  has many Segment
File  has many Segment

当我尝试插入类型为File的实体时,我得到以下错误:

  • InnerException {“MERGE语句与FOREIGN KEY约束“FK_Segment_File_FileId”冲突。冲突发生在数据库“mydatabase”、表“dbo.File”的列“Id”中。\r\n语句已终止。"} System.Exception {Microsoft.Data.SqlClient.SqlException}
    型号
public class File
{
  public int Id{get;set;}
  public ICollection<Segment> Segments{get;set;}
  public ICollection<Pages> Pages{get;set;}
}
public class Page
{
  public int Id{get;set;}
  public ICollection<Segment> Segments{get;set;}
}
public class Segment
{
  public int Id{get;set;}

  public Page Page{get;set;}
  public int PageId{get;set;}  //foreign key from page

  public File File{get;set;}
  public int FileId{get;set;} //foreign key from file
}

上下文

public class MyContext: DbContext {
        public DbSet<Segment> Segments { get; set; }
        public DbSet<Page> Pages { get; set; }
        public DbSet<File> Files { get; set; }
        public SXSContext(DbContextOptions<MyContext> options):base(options) {

        }
        protected override void OnModelCreating(ModelBuilder modelBuilder) {

            modelBuilder.Entity<File>(ent => {
                ent.ToTable("File");
                ent.HasKey(x => x.Id);
                ent.Property(x => x.Id).IsRequired();
            });
            modelBuilder.Entity<Page>(ent => {
                ent.ToTable("Page");
                ent.HasKey(x => x.Id);

                ent.Property(x => x.Id).IsRequired();
                ent.Property(x => x.FileId).IsRequired();
                ent.HasOne(y => y.File).WithMany(t => t.Pages).HasForeignKey(g => g.FileId).OnDelete(DeleteBehavior.NoAction);
            });
            modelBuilder.Entity<Segment>(ent => {
                ent.ToTable("Segment");
                ent.HasKey(x => x.Id);
                ent.Property(x => x.Id).IsRequired();
                ent.Property(x => x.PageId).IsRequired();
                ent.Property(x => x.FileId).IsRequired();
                ent.HasOne(y => y.Page).WithMany(t => t.Segments).HasForeignKey(g => g.PageId).OnDelete(DeleteBehavior.Cascade);
                ent.HasOne(y => y.File).WithMany(t => t.Segments).HasForeignKey(g => g.FileId).OnDelete(DeleteBehavior.Cascade);
            });
        }
    }

用法

static async Task Main(string[] args) {
            await Task.Delay(1);

            DbContextOptionsBuilder<MyContext> optionsBuilder = new DbContextOptionsBuilder<MyContext>();
            optionsBuilder.UseSqlServer(connectionString);
            SXSContext context = new SXSContext(optionsBuilder.Options);
            context.Database.EnsureCreated();
            List<Page> pages = new List<Page>{
                new Page{
                Segments = new List<Segment> {
                    new Segment{  },
                    new Segment{  },
                    new Segment{ }}
                },
                new Page{
                Segments = new List<Segment> {
                    new Segment{  },
                    new Segment{  }}
                }
            };
            File file = new File {  Pages = pages };
            context.Files.Add(file);

            context.SaveChanges();
            int val = await context.SaveChangesAsync();

        }

我有Segment的外键作为required,它们可能会被插入到它们的父FilePage之前,这会是一个问题吗?
应该如何插入这样的模式?我从File开始,我有PagesSegments,它们在插入之前不拥有id
它们可以在一次操作中插入吗?或者它们必须从根开始插入,在我的例子中是File

mv1qrgav

mv1qrgav1#

我有类似的问题,这是我遵循的解决方法:
首先,您应该插入非依赖实体并触发SaveChanges / SaveChangesAsync,以便您的实体将获得id-s(更多信息请查看另一个线程的the answer),在您的情况下,首先您必须添加File并调用SaveChanges / SaveChangesAsync,然后您应该对Page执行相同的操作,在每一步之后,然后你可以使用第三个insert(在你的例子中是Segment)而不会得到任何错误,因为你可以把所有引用的id-s都放好。

相关问题