Код Первое добавление в коллекции? Как использовать Code First с репозиториями?

РЕДАКТИРОВАТЬ: Это происходит только в более масштабных проектах с репозиториями. Кто-нибудь использует EF4 с подходом CodeFirst и использует репозитории? Пожалуйста, посоветуй мне.

Привет. В настоящее время я работаю с EF4 CodeFirst Classes. В моем тестовом проекте я получил два класса, Автор и Книга (автор получил книги). То, что я пытаюсь сделать, это то, что у меня есть AddBook в моем классе Author, но это, похоже, не будет работать так, как будто я не могу добавить его в коллекцию... вот мои классы и два разных исключения.

 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);
    }
}

исключение: свойство 'Книги' для типа 'Author_4CF5D4EE954712D3502C5DCDDAA549C8E5BF02A0B2133E8826A1AC5A40A15D2A' не может быть установлено, так как для коллекции уже задано значение EntityCollection.

Я изменяю класс 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.

И вполне естественно, что я получаю это исключение, потому что для Collection не задано новое, но затем я получаю это первое исключение. так как это сделать с кодом сначала в 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();
    }
}

6 ответов

Решение

virtual на всех свойствах была проблема здесь для меня.. Не понимаю, почему это оказало такое влияние, когда я масштабировал его до своего проекта, но так оно и было.. Надеюсь, это поможет любому, кто столкнулся с той же проблемой..

Удаление "виртуального" ключевого слова из свойств коллекции позволяет обойти эту проблему, не позволяя Entity Framework создавать прокси-сервер отслеживания изменений. Тем не менее, это не решение для многих людей, потому что прокси отслеживания изменений может быть очень удобным и может помочь предотвратить проблемы, когда вы забудете обнаружить изменения в нужных местах в вашем коде.

Лучшим подходом было бы модифицировать ваши классы POCO, чтобы они создавали свойства коллекции в своем методе доступа get, а не в конструкторе. Вот оригинальный класс POCO Author, модифицированный для создания прокси-сервера отслеживания изменений:

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);
    }
}

В приведенном выше коде свойство collection больше не является автоматическим, а имеет поле поддержки. Лучше, если вы оставите установщик защищенным, предотвращая последующее изменение этих свойств любым кодом (кроме прокси). Вы заметите, что конструктор больше не был необходим и был удален.

Проблема, упомянутая выше Dejan.S относительно использования "List" для инициализации коллекции, по-прежнему возникает в EF5 RTM и ASP.NET 4.5 RTM:

Выпуск списка

НО, если вы удалите виртуальное ключевое слово из первичного ключа (например, UserId в приведенном выше снимке экрана), это работает! Таким образом, кажется, что все ваши свойства могут быть виртуальными, за исключением первичного ключа.

У меня сначала работает код, но единственное (основное) отличие от моего кода в том, что я инициализирую его как список, а не как коллекцию... поэтому мой код читает что-то вроде:

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 коллекция - нет необходимости добавлять книгу в коллекцию и добавлять автора в книгу, потому что об этом должна заботиться структура сущностей.

Если это не работает для вас. Дай мне знать.

HTHS,
Чарльз

Попробуйте использовать эту подпись. Я надеюсь, что это сработало.

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);
    }
}

Проблема в этом случае заключается в том, что создаются прокси-серверы отслеживания изменений, поскольку все свойства вашего класса помечены как виртуальные. По соглашению это запускает генерацию прокси отслеживания изменений.

Таким образом, вы можете удалить виртуальное ключевое слово из одного или нескольких свойств или просто указать контексту не создавать прокси-серверы отслеживания изменений в соответствии с разделом "Работа с объектами POCO".

var ctx = new MyDbContext();
ctx.Configuration.ProxyCreationEnabled = false;
Другие вопросы по тегам