在Entity Framework中使用存储过程(二):具有继承关系实体的存
在《实现存储过程的自动映射》中,我通过基于T4的代码生成实现了CUD存储过程的自动映射。由于映射的都是基于数据表结构的标准的存储过程,所以它们适合概念模型和存储模型结构相同的场景。如果两种模型存在差异,在进行数据更新操作的时候就会出错。本篇文章主要介绍当概念模型中具有继承关系的两个实体映射到数据库关联的两个表,如何使用存储过程。
一、创建具有继承关系的实体假设数据库中有如下两个关联的表:T_EMP和T_SALES。T_EMP用于存储员工信息,主键为代表员工ID号的EMP_ID。为了简单起见,我仅仅定义两个额外的字段:FIRST_NAME和LAST_NAME。另一个表T_EMP用于存储销售人员的信息,它具有一样的主键EMP_ID,额外的两个字段代表负责的区域(Territory)和提成的比率(Commission Rate)。两者通过EMP_ID进行关联。 然后我们通过选择这两个表创建.edmx模型。由于这两个表之间具有关联,.edmx模型得两个实体之间会默认创建联系,你首先需要删除此联系。由于销售人员也是公司的员工,它属于是员工类型的子类。所以你需要建立它们之间的继承关系。由于具有继承关系的两个实体不能有重复的属性,属于你需要删除掉T_SALES的EMP_ID属性。最后你需要修正实体和属性的名称使之更具可读性。最后的.edmx模型如下图所示。 二、基于继承关系实体的查询与更新在引入存储过程之前,我们先来谈谈针对于如上一个具有继承关系实体的.edmx模型,如果进行查询和更新。使用过EF的读者应该很清楚,客户端代码进行数据的查询和更新都是通过自动生成的一个继承自ObjectContext的类来完成的。我们不妨来看看针对上面创建的.edmx模型,这个类具有怎样的定义。由于我为该模型的Entity Container起名为HrEntities,随后最终生成的是如下一个同名的类。 1: public partial class HrEntities : ObjectContext 3: public ObjectSet<Employee> Employees{get} 5: { 7: } 9:? 11: { 14: class Sales : Employee
16: 17: }
我们可以看到,虽然在模型中有两个实体,但是对于HrEntities来说,它仅仅具有一个类型为ObjectSet<Employee>的Employees属性(没有ObjectSet<Sales>类型的属性)和对应的AddToEmployee方法。但是针对这个两个实体对应的类都是存在的,并且存在继承关系。理解起来也容易,Sales也是Employee,所以Employees属性表述的ObjectSet可以同时包括普通的Employee和Sales。 最后我们在一个控制台应用中编写如下一段代码。这段代码中,先删除掉现有的Employee(包括Sales)记录,然后分别添加一个Employee对象和Sales对象。最后通过查询确保它被成功提交到数据库中。 2: { 4: { 6: { 8: } 10:? 12: Employee sales = Sales.CreateSales("002",1)">"Yan Yan",1)">"Xu",1)">"West",10);
14: context.AddToEmployees(sales); 16:? 19: Console.WriteLine("Employee ID: {0}; First Name: {1}; Last Name: {2}; Is Sales: {3}",
21: } 23: } 下面是我们希望的输出结果: 2: Employee ID: 002; First Name: Yan Yan; Last Name: Xu; Is Sales: Yes
从上面的代码中我们可以看到,当我们通过ObjectContext添加一个Employee对象的时候,它会先根据对象的真实类型,判断仅仅需要添加Employee对应的数据表记录,还是需要同时在Employee和Sales对应的两张数据表中同时添加一条记录。修改和删除操作采用的机制也是如此。 三、映射标准的CUD存储过程到目前为止,我们的程序运行的很好,现在我们分别Employee和Sales实体映射我们创建的标准的数据表,你可以手工是完成,也可以利用在《实现存储过程的自动映射》提到的代码生成的方式。在这之前我们不妨先来看看我们标准的存储过程长什么模样。下面是基于T_EMP数据表的CUD存储过程。 2: @p_emp_id VARCHAR(50),
5: AS
7: INSERT T_Emp(EMP_ID,FIRST_NAME,LAST_NAME) 9: END
11:? 13: @o_emp_id 14: @p_first_name NVARCHAR(50),1)" id="lnum15"> 15: @p_last_name NVARCHAR(50)
17: BEGIN
19: SET FIRST_NAME = @p_first_name,LAST_NAME = @p_last_name
21: 22: 23:? 25: @o_emp_id VARCHAR(50)
29: WHERE EMP_ID = @o_emp_id
31: GO 下面三个是基于T_SALES数据表的三个存储过程。 2: @p_emp_id 3: @p_territory NVARCHAR(50),1)" id="lnum4"> 4: @p_commission_rate INT
13: @o_emp_id 14: @p_territory NVARCHAR(50),1)" id="lnum15"> 15: @p_commission_rate INTSET TERRITORY = @p_territory,1)" id="lnum20"> 20: COMMISSION_RATE = @p_commission_rate 完成存储过程的映射后,再次运行上面的代码,会有如下一个UpdateException异常抛出来。追踪InnerException,你会发现一条有用的异常消息:The INSERT statement conflicted with the FOREIGN KEY constraint "FK_T_SALES_T_EMP". The conflict occurred in database "EFExtensions",table "dbo.T_EMP",column 'EMP_ID'.The statement has been terminated. 之所以出现上述的异常在于:当我们添加一个Sale对象的时候,只有Sales实体对象的Insert存储过程被执行。而该存储过程仅仅是为T_SALES数据表中插入数据,但是此时主表T_EMP没有相应的记录,违反外键约束。在进行数据的修改和删除时,也有相同的问题。 四、修正存储过程为了解决这个问题,我们只需要修改子类对应表的存储过程,让它们同时去添加、修改和删除主记录。下面列出了修正后的存储过程定义。 P_SALES_I 12: INSERT T_SALES(EMP_ID,COMMISSION_RATE)
14: END P_SALES_U 2: @o_emp_id 9: UPDATE T_EMP
12: WHERE EMP_ID = @o_emp_id
14: 15: 16: COMMISSION_RATE = @p_commission_rate 18: END P_SALES_D 6: DELETE T_SALES
DELETE T_EMP 11: END 然后在EF的模型设计器中对新的参数进行映射即可。 在Entity Framework中使用存储过程(一):实现存储过程的自动映射
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- asp.net-mvc-3 – .NET MVC 3以编程方式设置布局
- jquery发起get/post请求_或_获取html页面数据
- asp.net-mvc – telerik-grid onRowSelect如何获取id?
- [译]ASP.NET Core 2.0 路由引擎详解
- 这应该是目前最快速有效的ASP.NET Core学习方式(视频)
- asp.net-mvc – 使用多值键创建RouteValueDictionary
- asp.net-mvc – Elmah显示,“没有OWIN身份验证管理器与请求
- 从ASP.NET工作进程ID获取性能计数器实例名称(w3wp#XX)
- asp.net-mvc-3 – 在ASP.NET MVC 3视图中渲染System.Drawin
- asp.net-mvc – asp.net mvc 4 – 好的是每个线程共享DbCon
- 使用ASP.Net和JSON格式化实现jQuery的jgGrid
- asp.net中的泛型处理程序是什么?
- asp.net – IE10条件IE注释<! - >功能启用程序
- asp.net-mvc – 如何锁定一个asp.net mvc动作?
- asp.net-mvc-4 – DataAnnotation的必需属性
- asp.net-mvc – ASP.NET MVC:自定义排序
- asp.net – 使用jquery调用webmethod时始终获得“
- asp.net – .NET 4.0实现OutputCacheProvider
- asp.net-mvc – ASP.NET MVC,Nhibernate和小型/中
- asp.net-mvc-3 – MVC默认重定向错误页面并不总是