15

編集:これは、リポジトリを使用する大規模なプロジェクトでのみ発生します。CodeFirst アプローチで EF4 を使用し、リポジトリを使用している人はいますか? 教えてください。

やあ。現在、EF4 CodeFirst クラスを使用しています。テスト プロジェクトでは、Author と Book の 2 つのクラスを取得しました (著者は本を取得しました)。私がやろうとしているのは、Author クラスに AddBook があることですが、それをコレクションに追加できないように機能しないようです。ここに私のクラスと 2 つの異なる例外があります。

 public class Book
{
    public virtual int BookId { get; set; }
    public virtual string Title { get; set; }
    public virtual Author Author { get; set; }
}

public class Author
{
    public virtual int AuthorId { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<Book> Books { get; set; }

    public Author()
    {
        Books = new Collection<Book>();
    }

    public void AddBook(Book book)
    {
        book.Author = this;
        Books.Add(book);
    }
}

例外: コレクションが既に EntityCollection に設定されているため、タイプ 'Author_4CF5D4EE9​​54712D3502C5DCDDAA549C8E5BF02A0B2133E8826A1AC5A40A15D2A' のプロパティ 'Books' は設定できません。

Author クラスをこれに変更します

public class Author
{
    public virtual int AuthorId { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<Book> Books { get; set; }

    public void AddBook(Book book)
    {
        book.Author = this;
        Books.Add(book);
    }
}

例外: オブジェクト参照がオブジェクトのインスタンスに設定されていません。

コレクションが既に EntityCollection に設定されているため、設定できません。

コレクションが新しいものに設定されていないため、例外が発生するのは当然ですが、最初の例外が発生します。では、これは EF で最初にコードを使用してどのように行われるのでしょうか?

たぶん、私のDbSetと衝突する可能性があることを追加する必要がありますか?

public class EntityContext : DbContext, IUnitOfWork
{
    public DbSet<Author> Authors { get; set; }
    public DbSet<Book> Books { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.IncludeMetadataInDatabase = false;
    }

    public void Save()
    {
        SaveChanges();
    }
}
4

6 に答える 6

30

コレクション プロパティから "virtual" キーワードを削除すると、Entity Framework が変更追跡プロキシを作成できなくなり、問題を回避できます。ただし、これは多くの人にとって解決策ではありません。なぜなら、変更追跡プロキシは非常に便利であり、コード内の適切な場所で変更を検出するのを忘れた場合の問題を防ぐのに役立つからです。

コンストラクターではなく get アクセサーでコレクション プロパティをインスタンス化するように、POCO クラスを変更することをお勧めします。変更追跡プロキシの作成を許可するように変更された元の Author POCO クラスを次に示します。

public class Author
{
    public virtual int AuthorId { get; set; }
    public virtual string Name { get; set; }

    private ICollection<Book> _books;

    public virtual ICollection<Book> Books
    {
        get { return _books ?? (_books = new Collection<Book>()); }
        set { _books = value; }
    }

    public void AddBook(Book book)
    {
        book.Author = this;
        Books.Add(book);
    }
}

上記のコードでは、コレクション プロパティはもはや自動ではなく、バッキング フィールドがあります。セッターを保護したままにして、(プロキシ以外の) コードが後でこれらのプロパティを変更できないようにすることをお勧めします。コンストラクターが不要になり、削除されたことに気付くでしょう。

于 2012-03-28T17:37:07.490 に答える
7

コレクションを初期化するための「リスト」の使用に関するDejan.Sによる上記の問題は、EF5RTMおよびASP.NET4.5RTMでも引き続き発生します。

初期化の問題を一覧表示

ただし、主キーから仮想キーワード(たとえば、上記のスクリーンショットのUserId )を削除すると、機能します。したがって、主キーを除いて、すべてのプロパティを仮想化できるようです。

于 2012-08-26T22:40:55.110 に答える
6

virtualすべてのプロパティで私にとってここでの問題でした..プロジェクトにスケールアップしたときになぜそのような影響があるのか​​ わかりませんが、それがその方法でした..これが同じ問題を抱えている人に役立つことを願っています..

于 2010-10-05T21:26:11.887 に答える
4

私は最初にコードを動作させましたが、私のコードとの唯一の(主な)違いは、コレクションではなくリストとして初期化することです...したがって、私のコードは次のようになります。

public class Author
{
    public virtual int AuthorId { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<Book> Books { get; set; }

    public Author()
    {
        Books = new List<Book>();
    }
}

また、コレクションに直接追加するだけBooksです。エンティティフレームワークがそれを処理する必要があるため、本をコレクションに追加したり、著者を本に追加したりする必要はありません。

これがうまくいかない場合。お知らせ下さい。

HTH、
チャールズ

于 2010-10-04T22:01:47.397 に答える
2

この署名を使用してみてください。これがうまくいったことを願っています。

public class Author
{
    public virtual int AuthorId { get; set; }
    public virtual string Name { get; set; }

    private ICollection<Book> _books;

    public virtual ICollection<Book> Books
    {
        get { return _books ?? (_books = new HashSet<Book>()); } // Try HashSet<N>
        set { _books = value; }
    }

    public void AddBook(Book book)
    {
        book.Author = this;
        Books.Add(book);
    }
}
于 2013-01-20T17:38:37.340 に答える