Код Первое добавление в коллекции?Как использовать Code First с репозиториями? - PullRequest
14 голосов
/ 05 октября 2010

РЕДАКТИРОВАТЬ: Это происходит только в крупных проектах с репозиториями. Кто-нибудь использует 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.

И вполне естественно, что я получаю это исключение, потому что Коллекция не установлена ​​в новое, но затем я получаю это первое исключение. так как же это сделать с первым кодом в 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 ]

30 голосов
/ 28 марта 2012

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

Лучшим подходом было бы модифицировать ваши классы POCO, чтобы они создавали свойства коллекции в своем методе доступа get, а не в конструкторе. Вот оригинальный класс 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);
    }
}

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

6 голосов
/ 27 августа 2012

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

List init issue

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

6 голосов
/ 06 октября 2010

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

4 голосов
/ 05 октября 2010

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

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,
Charles

2 голосов
/ 20 января 2013

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

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);
    }
}
0 голосов
/ 13 августа 2014

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

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

var ctx = new MyDbContext();
ctx.Configuration.ProxyCreationEnabled = false;
...