EntityFrameworkCoreで子コレクションが更新されない

.net c# entity-framework-core uwp win-universal-app

質問

ネストされた1対多の関係を持つ以下の単純化されたモデルを考えてみましょう。

public class Report
{
    public Guid ReportId { get; set; }
    public string Name { get; set; }
    public List<Schedule> Schedules { get; set; }
}

public class Schedule
{
    public Guid ScheduleId { get; set; }
    public string Title { get; set; }
    public List<Description> Descriptions { get; set;}

    // FK
    public Guid ReportId { get; set; }
    public Report Report { get; set; }
}

public class Description
{
    public Guid DescriptionId { get; set; }
    public string Content { get; set; }

    // FK
    public Guid ScheduleId { get; set; }
    public Schedule Schedule { get; set; }
}

public class DataContext : DbContext
{
    public DbSet<Report> Reports { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Filename=mydbname.db");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Report>()
            .HasMany(report => report.Schedules)
            .WithOne(schedule => schedule.Report);
        modelBuilder.Entity<Schedule>()
            .HasOne(schedule => schedule.Report)
            .WithMany(report => report.Schedules)
            .OnDelete(DeleteBehavior.Cascade);
        modelBuilder.Entity<Description>()
            .HasOne(description => description.Schedule)
            .WithMany(schedule => schedule.Descriptions)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

期待どおりに追加すると、各項目が各表に挿入されます。

Description description = new Description();
description.DescriptionId = Guid.NewGuid();
description.Content = "my content";

Schedule schedule = new Schedule();
schedule.ScheduleId = Guid.NewGuid();
schedule.Title = "my schedule";
schedule.Descriptions = new List<Description>();
schedule.Descriptions.Add(description);

Report report = new Report;
report.ReportId = Guid.NewGuid();
report.Name = "my report";
report.Schedules = new List<Schedule>();
report.Schedules.Add(schedule);

using(var db = new DataContext())
{
    db.Reports.Add(report);
    db.SaveChanges();
}

エンティティの削除も正常に機能し、すべての項目が各表で削除されます。

using(var db = new DataContext())
{
    db.Reports.Remove(report);
    db.SaveChanges();
}

ただし、アイテムを更新するのは、コレクションに新しいアイテムを追加するときではなく、既存のアイテムのコンテンツを変更する場合のみです。例えば:

// this works
report.Name = "updated report";
report.Schedules.ElementAt(0).Descriptions.ElementAt(0).Content = "updated content";
using(var db = new DataContext())
{
    db.Reports.Update(report);
    db.SaveChanges();
}

// this throws DbUpdateConcurrencyException because no rows are affected.
Description newDescription = new Description();
newDescription.DescriptionId = Guid.NewGuid();
newDescription.Content = "new content";

Schedule newSchedule = new Schedule();
newSchedule.ScheduleId = Guid.NewGuid();
newSchedule.Title = "new schedule";
newSchedule.Descriptions = new List<Description>();
newSchedule.Descriptions.Add(newDescription);

report.Schedules.Add(newSchedule);
using(var db = new DataContext())
{
    db.Reports.Update(report);
    db.SaveChanges();
}

アイテムをコレクションに正しく追加して後で更新するにはどうすればよいですか?私のテーブルデザインは理にかなっていますか?これは、Reportオブジェクトを取得する方法です。

List<Report> Reports;
using (var db = new DataContext())
    Reports = db.Reports
                    .Include(report => report.Schedules)
                        .ThenInclude(schedule => schedule.Descriptions)
                    .ToList()

EDIT

Sunteen - MSFTの投稿と同様に、自分のコードに間違いがないようです。私の場合、問題の原因を見つけました。これは、各エンティティの主キーID( Guid.NewGuid() )を故意に生成するはずです。判明したように、IDは自動的に生成され、問題は解決されます。 Sunteen - MSFTありがとうございます。

受け入れられた回答

私はあなたの問題を再現できません。私が書いた唯一のコードは、コードスニペットに表示されなかったreportオブジェクトを取得することです。更新しようとしているreportオブジェクトがテーブルに存在することを確認してください。私はちょうどReportテーブルから最初のレコードを取得し、次に、次のようにコードを更新し、

using (var db = new DataContext())
{
    List<Report> Reports;
    Reports = db.Reports.Include(report1 => report1.Schedules)
                        .ThenInclude(schedule => schedule.Descriptions)
                    .ToList();
    var report = Reports[0];

    Description newDescription = new Description();
    newDescription.DescriptionId = Guid.NewGuid();
    newDescription.Content = "new content";

    Schedule newSchedule = new Schedule();
    newSchedule.ScheduleId = Guid.NewGuid();
    newSchedule.Title = "new schedule";
    newSchedule.Descriptions = new List<Description>();
    newSchedule.Descriptions.Add(newDescription);
    report.Schedules.Add(newSchedule);
    db.Reports.Update(report);
    db.SaveChanges();
}

あなたのコードを使ってデモを作成し、うまくいきました。 デモをgithubにアップロードしました。テスト用にダウンロードして、プロジェクトと比較して違いを見つけることができます。比較の相違で解決できない場合は、このデモで問題を再現して解決し直すことができます。



Related

ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ