Подтвердить что ты не робот

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

EDIT: Это происходит только в проектах с крупными проектами с репозиториями. Есть ли кто-нибудь, использующий EF4 с использованием CodeFirst и использующий репозитории? Пожалуйста, сообщите мне.

Привет. Im в настоящее время работает с 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();
    }
}
4b9b3361

Ответ 1

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

Ответ 2

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

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

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

Ответ 3

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

List init issue

НО, если вы удаляете ключевое слово виртуальное из первичного ключа (например, UserId в приведенном выше скринкапе), оно работает! Таким образом, кажется, что все ваши свойства могут быть виртуальными, ЗА ИСКЛЮЧЕНИЕМ первичного ключа.

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

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

HTHS,
Чарльз

Ответ 5

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

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

Ответ 6

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

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

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