2

私の問題を説明するために、書籍のコレクションを持つデータ モデルがあり、それぞれに 1 つ以上のドラフトと「現在の」ドラフトがあるとします。モデルを次のようにしたいと思います。

class Book
{
    public int Id { get; set; }

    public string Title { get; set; }

    public virtual ICollection<Draft> Drafts { get; set; }

    public virtual Draft CurrentDraft { get; set; }
}

class Draft
{
    public int Id { get; set; }

    public virtual int BookId { get; set; }
    public virtual Book Book { get; set; }

    public string Description { get; set; }
}

次のような DbContext があります。

class TestDbContext : DbContext
{
    public DbSet<Book> Books { get; set; }
    public DbSet<Draft> Drafts { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();

        base.OnModelCreating(modelBuilder);
    }
}

...そして、次のような単純なプログラム:

static void Main(string[] args)
{
    Database.SetInitializer<TestDbContext>(new DropCreateDatabaseAlways<TestDbContext>());

    using (var db = new TestDbContext())
    {
        var book = new Book() { Title = "War and Peace", Drafts = new List<Draft>() };


        var draft1 = new Draft() { Book = book, Description = "First Draft" };

        book.Drafts.Add(draft1);


        var draft2 = new Draft() { Book = book, Description = "Second Draft" };

        book.Drafts.Add(draft2);


        book.CurrentDraft = draft2;


        db.Books.Add(book);

        db.SaveChanges();


        foreach (var b in db.Books)
        {
            Console.WriteLine("Book {0}: {1}", b.Id, b.Title);

            foreach (var d in book.Drafts)
                Console.WriteLine("\tDraft ID {0}: {1} from Book ID {2}", d.Id, d.Description, d.BookId);

            Console.WriteLine("Current draft has ID {0}", b.CurrentDraft.Id);
        }

        Console.ReadKey();
    }
}

DB が EF によって作成されると、次のようになります。

データベース スキーマ

[私は追加の Book_Id 列に熱狂的ではありませんが、それが機能するなら我慢できます。]

悲しいことに、テスト プログラムを実行すると、SaveChanges呼び出しで失敗し、例外が発生します。

リレーションシップの外部キー プロパティを公開しないエンティティの保存中にエラーが発生しました。1 つのエンティティを例外のソースとして識別できないため、EntityEntries プロパティは null を返します。保存中の例外の処理は、エンティティ タイプで外部キー プロパティを公開することで簡単に行うことができます。詳細については、InnerException を参照してください。

OnModelCreating で流暢な API をいじってみましたが、そのように構成しようとすると、Books と Drafts の間に 2 つの FK 関係があるという事実によって混乱します。私は流暢なもの (または一般的には EF) に精通していないため、適切に行う方法を知ることができません。

これは最初にEFコードでも可能ですか?

4

2 に答える 2

1

私があなただったら、もう 1 つのプロパティをドラフトに追加しますbool IsCurrent{get;set;}。と

public Draft CurrentDraft { get{return Drafts.SingleOrDefault(c=>c.IsCurrent)} }

この場合、ブックとドラフトの間に 1 つの外部キーが存在します。

于 2012-10-09T17:59:44.357 に答える
1

あなたの内部例外は、EFが何かをデータベースに保存して何かを適切に作成する順序を理解できないことです。複数の場所で save changes を呼び出して順序を強制すると、テスト アプリは次のように動作します。

            var book = new Book() { Title = "War and Peace", Drafts = new List<Draft>() };
            db.Books.Add(book);
            db.SaveChanges();
            var draft1 = new Draft() { Book = book, Description = "First Draft" };
            book.Drafts.Add(draft1);
            var draft2 = new Draft() { Book = book, Description = "Second Draft" };
            book.Drafts.Add(draft2);
            book.CurrentDraft = draft2;
            db.SaveChanges();

2 番目の book_id については、次のように流暢に使用できます。

        modelBuilder.Entity<Book>()
            .HasMany(b => b.Drafts)
            .WithRequired(d => d.Book)
            .HasForeignKey(d => d.BookId);

        modelBuilder.Entity<Book>()
            .HasOptional(b => b.CurrentDraft)
            .WithOptionalDependent()
            .Map(m => m.MapKey("CurrentDraftId"));

このデータベースを生成します:

ここに画像の説明を入力

于 2012-10-09T18:15:17.730 に答える