所以我决定先使用代码/ 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类型。
这是我的实体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; }
}
答案 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;