Code First添加到集合中?如何使用Code First和存储库?

Dej*_*n.S 14 entity-framework code-first entity-framework-4 asp.net-mvc-2

编辑:这只发生在具有存储库的大型项目中.有没有人使用EF4和CodeFirst方法并使用存储库?请建议我.

你好.我目前正在使用EF4 CodeFirst Classes.在我的测试项目中,我有两个类,作者和书(作者得到书).我正在尝试做的是我在我的作者类中有一个AddBook,但似乎不能像我不能将它添加到集合中..这里是我的类和两个不同的例外.

 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

例外:无法设置类型为"Author_4CF5D4EE9​​54712D3502C5DCDDAA549C8E5BF02A0B2133E8826A1AC5A40A15D2A"的属性"Books",因为集合已设置为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

例外:对象引用未设置为对象的实例.

无法设置,因为集合已设置为EntityCollection.

这很自然,因为Collection没有设置为new,但是我得到了第一个异常.那么如何在EF中首先使用代码呢?

也许我应该补充说我的It可能会与我的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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Pan*_*ndo 30

通过阻止实体框架创建更改跟踪代理,从集合属性中删除"虚拟"关键字可解决此问题.但是,对于许多人来说,这不是一个解决方案,因为更改跟踪代理可以非常方便,并且可以在您忘记检测代码中正确位置的更改时帮助防止出现问题.

更好的方法是修改POCO类,以便它们在get访问器中而不是在构造函数中实例化集合属性.这是原始的作者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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,collection属性不再是自动的,而是具有支持字段.如果您保护setter更好,防止任何代码(代理除外)随后修改这些属性.您会注意到构造函数不再是必需的并被删除.

  • 但为什么代理会导致此异常? (2认同)

Dej*_*n.S 6

virtual 关于所有的属性是我的问题..不要理解为什么它有这样的影响当我把它扩展到我的项目,但它是如何...希望这有助于任何人有同样的问题..

  • 我相信,如果我们将所有属性设为虚拟,我们允许EF生成更改跟踪代理. (4认同)

nur*_*uri 6

Dejan.S上面提到的关于使用'List'初始化集合的问题仍然发生在EF5 RTM和ASP.NET 4.5 RTM中:

列出init问题

但是,如果从主键中删除虚拟关键字(例如上面的screencap中的UserId),它就可以了!所以看起来你的所有属性都可以是虚拟的,除了主键.