Ответ 1
virtual
для всех свойств была проблема здесь для меня.. Не поймите, почему это так повлияло, когда я расширил ее до моего проекта, но так, как это было. Надеюсь, это поможет любому, кто получил ту же проблему.
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();
}
}
virtual
для всех свойств была проблема здесь для меня.. Не поймите, почему это так повлияло, когда я расширил ее до моего проекта, но так, как это было. Надеюсь, это поможет любому, кто получил ту же проблему.
Удаление "виртуального" ключевого слова из свойств коллекции работает вокруг проблемы, не позволяя 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);
}
}
В приведенном выше коде свойство коллекции больше не является автоматическим, а имеет поле поддержки. Это лучше, если вы оставите защитный щит защищенным, не позволяя любому коду (кроме прокси) впоследствии модифицировать эти свойства. Вы заметите, что конструктор больше не нужен и был удален.
Проблема, упомянутая выше Dejan.S в отношении использования "List" для инициализации коллекции, все еще встречается в RTM RTF и RTF версии 4.5 для .NET Framework:
НО, если вы удаляете ключевое слово виртуальное из первичного ключа (например, 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;