Переполнение стека при добавлении сущности с несколькими взаимосвязями один к одному с одной и той же таблицей в Entity Framework Core - PullRequest
0 голосов
/ 09 марта 2020

У меня есть проблема при добавлении сущностей с несколькими взаимосвязями один к одному с одной и той же таблицей в Entity Framework Core. Исходя из этого вопроса у меня есть следующие вещи:

public class Article
{
    public int Id { get; set; }
    public int? PreviousId { get; set; }
    public Article Previous { get; set; }
    public int? NextId { get; set; }
    public Article Next { get; set; }
}

В OnModelCreating из DbContext, как у меня:

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

    modelBuilder.HasDefaultSchema("ab");
    modelBuilder.ApplyConfiguration(new ArticleEntityTypeConfiguration());
}

public class ArticleEntityTypeConfiguration : IEntityTypeConfiguration<Article>
{
    public void Configure(EntityTypeBuilder<Article> builder)
    {
        builder.ToTable("Articles");

        builder.HasKey(table => table.Id);
        builder.Property(table => table.Id).ValueGeneratedOnAdd();

        builder.HasOne(table => table.Previous).WithOne().HasForeignKey<Article>(table => table.PreviousId);
        builder.HasOne(table => table.Next).WithOne().HasForeignKey<Article>(table => table.NextId);
    }
}

И когда добавив новую статью, я получаю ошибку переполнения стека и приложение вылетает. Я добавляю статью со следующим кодом:

public Task AddNewArticleAsync(Article article)
{
    var newArticle = new Article();

    article.Next = newArticle;
    newArticle.Previous = article;

    await _dbContext.Programs.AddAsync(article);
}

Знаете ли вы, как избежать этой ошибки? Спасибо!

Ответы [ 2 ]

0 голосов
/ 10 марта 2020

Итак, я продолжаю исследовать это и нашел этот ответ, который помог мне решить проблему. Хитрость заключалась в том, чтобы изменить OnModelCreating из DbContext на:

public void Configure(EntityTypeBuilder<Article> builder)
{
    builder.ToTable("Articles");

    builder.HasKey(table => table.Id);
    builder.Property(table => table.Id).ValueGeneratedOnAdd();

    builder
        .HasOne(table => table.Previous)
        .WithOne() // <-- one of this must be empty
        .HasForeignKey<Article>(table => table.PreviousId)
        .OnDelete(DeleteBehavior.Restrict);

    builder
        .HasOne(table => table.Next)
        .WithOne(table => table.Previous)
        .HasForeignKey<Article>(table => table.NextId);
}
0 голосов
/ 10 марта 2020

если вы добавляете новую статью, PreviousId/NextId должен быть нулевым или существующим Article.Id. Если ваш Artice.Id увеличивается, предыдущий идентификатор является максимальным идентификатором существующих записей.

Ниже демо для сохранения новых статей:

[HttpPost]
public async Task<IActionResult> Create(Article article)
{
    if (ModelState.IsValid)
    {
        int minArticleId = _context.Articles.Max(a => a.Id);
        var previous = await _context.Articles.Where(s => s.Id == minArticleId).FirstOrDefaultAsync();
        article.PreviousId = minArticleId;
        _context.Add(article);
        await _context.SaveChangesAsync();

        previous.NextId = article.Id;          
        _context.Update(previous);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }

    return View(article);
}
...