10-7. TPH继承模型中使用存储过程
问题
用一个存储过程来填充TPH继承模型的实体
解决方案
假设已有如Figure 10-7所示模型. 我们有两个派生实体: Instructor(教员)和Student(学生).
这个模型使用TPH继承方式,所以数据库中只有一个表. Person(人员)表有一个鉴别列,用来把表的记录映射到不同的派生实体上. 我们想用一个存储过程来填充实体.
Figure 10-7. A model for instructors and students
用下面的步骤,达到用一个存储过程来返回实体的目的:
1.在你的数据库中创建如Listing 10-18所示的存储过程. 这个存储过程返回所有人员.
Listing 10-18. The GetAllPeople Stored Procedure, Which Returns All the People, Both
Students and Instructors, in the Model
create procedure [Chapter10].[GetAllPeople]
as
begin
select * from chapter10.Person
end
2. 右击模型的设计视图,选择“从数据库更新模型”.选择存储过程GetAllPeople. 单击“完成”,把存储过程添加到模型中.
3. ( 译注:我的环境是win10+vs2013+ef6.1.3,是不需要这步的,第1步已经把这步也完成了,只是最后的“返回以下内容的集合”必须修改一下),右击模型的设计视图, 选择“新增“ ➤ 函数导入. 从“存储过程/函数名称”下拉框中选择GetAllPeople. 在“函数导入名称“文本框中输入:GetAllPeople. 这个就是在模型中的方法名称.在“返回以下内容的集合”里勾选“实体”,在下拉框里选择Person.单击“确定”.将会创建<FunctionImportMapping>框架.
4. 右击 .edmx 文件, 选择“打开方式” ➤ XML Editor.编辑.edmx文件的mapping 小节下
的<FunctionImportMapping> 标签,用 Listing 10-19所示代码去匹配(因为像EF6RecipesModel的命名与你的例子可能不同).它会映射被存储过程返回的列与Person类型的实体的属性。
(译注:所给的示例数据库里的PersonType列,类型为varchar,不可为空。我自己跟着这里所说的步骤做了一下,运行后发现有错误。看了原书网站上下载的代码后发现这一列为nvarchar,并且可为空,所以改了数据库之后,再“从数据库更新模型”一次,就可以了。)
Listing 10-19. The FunctionImportMapping Conditionally Maps Rows to Either the
Instructor or Student Entity
<FunctionImportMapping FunctionImportName="GetAllPeople"
FunctionName="EF6RecipesModel.Store.GetAllPeople">
<ResultMapping>
<EntityTypeMapping TypeName="EFRecipesModel.Student">
<ScalarProperty Name="Degree" ColumnName="Degree" />
<Condition ColumnName="PersonType" Value="Student"/>
</EntityTypeMapping>
<EntityTypeMapping TypeName="EF6RecipesModel.Instructor">
<ScalarProperty Name="Salary" ColumnName="Salary"/>
<Condition ColumnName="PersonType" Value="Instructor"/>
</EntityTypeMapping>
</ResultMapping>
</FunctionImportMapping>
5. Follow the pattern in Listing 10-20 to use the GetAllPeople stored procedure via the
GetAllPeople() method
Listing 10-20. Querying the Model Using the GetAllPeople Stored Procedure via
the GetAllPeople() Method.
static void Main(string[] args)
{
using (var context = new EFRecipesEntities1007())
{
context.People.Add(new Instructor
{
Name = "Karen Stanford",
Salary = 62500M
});
context.People.Add(new Instructor
{
Name = "Robert Morris",
Salary = 61800M
});
context.People.Add(new Student
{
Name = "Jill Mathers",
Degree = "Computer Science"
});
context.People.Add(new Student
{
Name = "Steven Kennedy",
Degree = "Math"
});
context.SaveChanges();
}
using (var context = new EFRecipesEntities1007())
{
Console.WriteLine("Instructors and Students");
var allPeople = context.GetAllPeople();
foreach (var person in allPeople)
{
if (person is Instructor)
Console.WriteLine("Instructor {0} makes {1}/year",
person.Name,
((Instructor)person).Salary);
else if (person is Student)
Console.WriteLine("Student {0}'s major is {1}",
person.Name, ((Student)person).Degree);
}
}
Console.WriteLine("\npress any key to exit...");
Console.ReadKey();
}
输出结果如Listing 10-20:
===================================================================
Instructors and Students
Instructor Karen Stanford makes $62,500.00/year
Instructor Robert Morris makes $61,800.00/year
Student Jill Mathers's major is Computer Science
Student Steven Kennedy's major is Math
=================================================================================
它是如何工作的
用一个存储过程填充TP继承模型的实体,比TPT (见10-6小节)要简单些. 这里的存储过程只是检索出表Person的所有行. 我们在<FunctionImportMapping>标签里对应关系(列名+值来确定是某种实体),(见 Listing 10-19),就是把表的鉴别列(PersonType)的不同的值,转化为相对应的实体
.在10-6小节我们这么做,在本小节,我们也是这么做。