在上篇关于在entity framework多对多关系及有效负载一文中忘了说明:当手动修改edm模型的xml文件,是不被允许从数据库更新的,否则修改的内容会被刷新掉,就等于白做了。 最近比较忙,没有时间更新,早就想写一篇关于Inheritance的文章。在Ado.net Team blog上有关于Inheritance的文章,个人觉得不够精细
在上篇关于在entity framework多对多关系及有效负载一文中忘了说明:当手动修改edm模型的xml文件,是不被允许从数据库更新的,否则修改的内容会被刷新掉,就等于白做了。 最近比较忙,没有时间更新,早就想写一篇关于Inheritance的文章。在Ado.net Team blog上有关于Inheritance的文章,个人觉得不够精细,一起看看我做的关于继承的练习。(先看看模型 如下图)
图1
首先对于继承(Inheritance)在EDM模型中大概分为2类,
1.单张表的继承(只有基本实体(base entity)映射到表)
2.多张表的继承(继承和被继承的实体都映射到表)
在图1模型中这2方式都将被用到,在图1中的模型大概要表达的就是perosn存放基本信息,employee 继承自perosn,由于薪水计算方式的不同再次派生了HourSalaryEmployee 和monthSalaryEmployee,同时employeeTest中的department,rank是关联到TypeOfDepartment,TypeOfRank .在图1模型里我用到了3张表employeeTest,Perosn PickList,字段分别如下
employeeTest:[dbo].[employeeTest]([EmployeeID], [EmployeeNo], [Salary], [Hour], [Rate], [TypeOfDepartment], [TypeOfEmployee], [Rank])
Person:[dbo].[Perosn]([PersonID], [Name], [Age], [Country], [City], [BirthDay])
PickList:[dbo].[PickList]([code], [text], [value], [type])
先还是从简单的看起:在图1模型中 TypeOfDepartment,TypeOfRank继承自PickList这2个实体
通过PickList 的type 来界定每一个PickList对象的类型TypeOfDepartment OR TypeOfRank.
接下来看Person employeeTest MonthSalaryemployee HourSalryEmployee;
Person实体映射到Person 由于是基类 我把它的Abstract属性 设为true,
添加employeeTest 与Person 的继承关系,这里要注意的是:由于employeeTest,person分别映射2张数据库表,因此对于employeeTest表的主键必须映射 Person 实体的主键
也就是说每创建一个employeeTest实体将会保存到Person 和employeeTest 表中.对于按小时计算工资的HourSalaryemployee 需要Rate ,Hour,Salary,而MonthSalaryEmployee 则只需Salary.(在vs2008 sp 正式版之前,如果对于1张表的继承如果是将一张表的字段映射到不同的派生的实体,不把base entity 的Abstract属性设为true,是编译不能通过的,好像正式版没有了这个问题,对于实体的Abstract属性的true or false区别主要在于 抽象实体不可以实例化)。如图对于MonthSalaryEmployee和HourSalaryemployee 的类型区分通过TypeOfEmployee来实现,
当然从Peson 到employeeTest我没有设置类型区分的字段,当然如果需要从person派生出其他类型的实体student则就需要类型区分了.图1中的模型就说到这里了下面看看怎么来访问这个模型,怎样访问实体与派生的实体,创建一个test项目首先我们来实例化:看看employeeTest及其派生实体的实例化:
Code
1 [TestMethod]
2 public void InitTest()
3 {
4 using (testEntities context = new testEntities())
5 {
6
7 try
8 {
9 #region anthor emplyee
10 employeeTest et = new employeeTest
11 {
12 EmployeeNo = "e100" + new Random().Next(3, 100),
13 PersonID = Guid.NewGuid(),
14 Age = 20,
15 BirthDay = DateTime.Now,
16 City = "hk",
17 Country = "china",
18 Name = "eric",
19 TypeOfDepartment = context.PickListSet.Where(q => q.code == "d001").FirstOrDefault() as TypeOfDepartment,
20 TypeOfRank = context.PickListSet.Where(q => q.code == "r001").FirstOrDefault() as TypeOfRank
21 };
22 context.AddToPerosn(et);
23 HourSalaryEmployee he = new HourSalaryEmployee
24 {
25 EmployeeNo = "h100" + new Random().Next(3, 100),
26 Hour = 200,
27 Rate = 30,
28 Salary = 6000,
29 PersonID = Guid.NewGuid(),
30 Age = 20,
31 BirthDay = DateTime.Now,
32 City = "hk",
33 Country = "china",
34 Name = "viv",
35 TypeOfDepartment = context.PickListSet.Where(q => q.code == "d001").FirstOrDefault() as TypeOfDepartment,
36 TypeOfRank = context.PickListSet.Where(q => q.code == "r001").FirstOrDefault() as TypeOfRank
37 };
38
39 MonthSalaryEmployee me = new MonthSalaryEmployee()
40 {
41 EmployeeNo = "m100" + new Random().Next(3, 100),
42 Salary = 3500,
43 PersonID = Guid.NewGuid(),
44 Age = 20,
45 BirthDay = DateTime.Now,
46 City = "hk",
47 Country = "china",
48 Name = "allen",
49 TypeOfDepartment = context.PickListSet.Where(q => q.code == "d002").FirstOrDefault() as TypeOfDepartment,
50 TypeOfRank = context.PickListSet.Where(q => q.code == "r002").FirstOrDefault() as TypeOfRank
51
52 };
53 //TypeOfDepartment = null,
54 //TypeOfRank = null,
55 context.AddToPerosn(et);
56 context.AddToPerosn(he);
57 context.AddToPerosn(me);
58
59 #endregion
60
61 context.SaveChanges();
62 }
63 catch (Exception e)
64 {
65 Assert.Fail(string.Format("source:{0},innerException:{1}", e.Source, e.InnerException));
66 }
67
68 }
69 }
Person是抽象实体,无法实例化。访问模型中的继承关系,在LinqToEntity中有一个方法OfType(),可以在父类中筛选出想要的子类类型
Code
1 protected IQueryable<employeeTest> GetEmployeeList(testEntities context)
2 {
3 IQueryable<Perosn> list = context.Perosn.Select(q => q);
4 return list.OfType<employeeTest>();
5 }
6 protected IQueryable<HourSalaryEmployee> GetHourSalaryList(testEntities context)
7 {
8 IQueryable<employeeTest> list = GetEmployeeList(context);
9 return list.OfType<HourSalaryEmployee>();
10 }
11
12 protected IQueryable<MonthSalaryEmployee> GetMonthSalaryList(testEntities context)
13 {
14 IQueryable<employeeTest> list = GetEmployeeList(context);
15 return list.OfType<MonthSalaryEmployee>();
16 }
17
18 protected IQueryable<TypeOfDepartment> GetTypeOfDepartmentList(testEntities context)
19 {
20 IQueryable<TypeOfDepartment> list = context.PickListSet.OfType<TypeOfDepartment>();
21 return list;
22 }
23
24 protected IQueryable<TypeOfRank> GetTypeOfRankList(testEntities context)
25 {
26 IQueryable<TypeOfRank> list = context.PickListSet.OfType<TypeOfRank>();
27 return list;
28 }
29
30
当然也可以样
using (testEntities context = new testEntities())
{
string str = "h001";
var e = context.Perosn.OfType<employeeTest>().Where(q => q.EmployeeNo == str);
IQueryable<employeeTest> employeeList = GetEmployeeList(context);
IQueryable<HourSalaryEmployee> hourEmployeeList = GetHourSalaryList(context);
IQueryable<MonthSalaryEmployee> monthEmployeeList = GetMonthSalaryList(context);
IQueryable<TypeOfDepartment> departmentList = GetTypeOfDepartmentList(context);
IQueryable<TypeOfRank> rankList = GetTypeOfRankList(context);
}
通过这个练习,EDM中的继承用起来还算优雅,因该说可以让我们更oop,我想这也许ms 一再宣称Entity FrameWork不仅仅只是一个ORM框架.当然entity framework 也是有很多问题的,对于实体tracking 以及实体状态的判断在实际应用时的问题还是很多的。如同EF开发人员的blog上提到的一样,在下一个版本中将会做到很好!
刚刚整理了一下,把模型和测试代码以及数据库脚本分离出来了,给又需要了解entity framework 的朋友参考 代码下载