不能形成一些简单的POCO用于“Code First”实体框架,请检查错误

时间:2011-10-09 13:44:33

标签: asp.net-mvc-3 entity-framework entity-framework-4 entity-framework-4.1

所以我决定先使用代码/ DbContext方法,但已经有了一个现有的数据库文件。没有什么复杂的,所以我想我可以为各自的POCO创建带有DbSets的DbContext派生容器类,创建到我的数据库的连接字符串,我应该设置。但是我相信我在实体类中正确声明属性时遇到了困难,因为我在尝试通过导航属性访问对象时遇到错误。通常在我尝​​试Object reference not set to an instance of an object时告诉我context.Products.Find(1).Category.CATNAME;等。同时尝试使用虚拟关键字声明集合属性也无济于事。

数据库架构的一些细节是:

  

在Categories表中,PCATID是CategoryID中的外键   相同的Categories表,可以为null。

     

Products表中的CategoryID和RootCategoryID都可以为null   是Categories表中CategoryID的外键。

我目前正在测试一些东西,但最终会将很多字段设置为非null类型。

enter image description here

这是我的实体POCO和实体Dbset容器类:

    public class Category
{
    [Key]
    public int CategoryID { get; set; }

    public string CATNAME { get; set; }

    public int PCATID { get; set; }

    public ICollection<Category> Categories { get; set; }

    public ICollection<Product> Products { get; set; }

}


public class Product
{
    [Key]
    public int ProductID { get; set; }

    public int CategoryID { get; set; }

    public int RootCategoryID { get; set; }


    public string Name { get; set; }

    public string ShortDescription { get; set; }

    public string LongDescription { get; set; }

    public string Keywords { get; set; }

    public decimal ListPrice { get; set; }

    public Category Category { get; set; }

}


public class EFDbContext: DbContext
{

    public DbSet<Product> Products { get; set; }


    public DbSet<Category> Categories { get; set; }


}

4 个答案:

答案 0 :(得分:2)

您需要使PCATID成为可以为空的属性,因为您已声明它可以为null。将所有这些导航属性和集合属性设置为虚拟。 EF将无法检测类别层次结构,因此您可以使用属性或流畅的API来配置它。

public class Category
{
    [Key]
    public int CategoryID { get; set; }

    public string CATNAME { get; set; }

    [ForeignKey("ParentCategory")]
    public int? PCATID { get; set; }

    [InverseProperty("Categories")]
    public virtual Category ParentCategory { get; set; }

    [InverseProperty("ParentCategory")]
    public virtual ICollection<Category> Categories { get; set; }

    public virtual ICollection<Product> Products { get; set; }

}

答案 1 :(得分:1)

Requirements for Creating POCO Proxies

所有内容都为POCO做好了准备,但此时并未对Lazy Loading进行整理。默认情况下,LL已启用,但为了启用延迟加载,Category属性必须为Virtual(创建一个捕获引用并加载数据的代理)。如果您不想延迟加载,请在EFDbContext构造函数中禁用它。

所以你的选择是:

public virtual Category Category { get; set; } 

public class EFDbContext: DbContext 
{
    public static EFDbContext()
    {
        LazyLoadingEnabled = false
    }
    ...
}

你可能想要做第一个......

答案 2 :(得分:1)

您确定要真正使用Code First吗?或者你只是想使用DbContext和DbSet?使用DbContext和DbSet,您可以使用Database First获得相同的好处。由于您已经拥有了数据库,因此通常会更加简单。

请参阅:http://blogs.msdn.com/b/adonet/archive/2011/03/15/ef-4-1-model-amp-database-first-walkthrough.aspx

Code First和Database First与DbContext之间的唯一区别是Code首先使用流畅的映射模型,而Database First使用.edmx文件。使用现有数据库可以更轻松地维护.edmx。

如果您受到约束并决定使用Code First,那么我建议您使用Entity Framework Power Tools CTP1并将数据库逆向工程设计为Code First。

答案 3 :(得分:1)

我同意@Eranga关于班级Category(+1到@Eranga)。

public class Category {
    [Key]
    public int CategoryID { get; set; }

    public string CATNAME { get; set; }

    [ForeignKey("ParentCategory")]
    public int? PCATID { get; set; }

    [InverseProperty("Categories")]
    public virtual Category ParentCategory { get; set; }

    [InverseProperty("ParentCategory")]
    public virtual ICollection<Category> Categories { get; set; }

    public virtual ICollection<Product> Products { get; set; }

}

您的Linq查询也存在问题:

context.Products.Find(1).Category.CATNAME;

EF仅从您使用Include请求的表中返回数据,或者在函数中使用此表。 使用此代码可以完成所有工作:

            db.Products
            .Include(p => p.Category) // here I demand to load data from Category table
            .First(p => p.ProductID == 3)
            .Category
            .CATNAME;