设计器 CUD 存储过程
此分步演练演示如何使用 Entity Framework Designer (EF Designer) 将实体类型的 create\insert、update 和 delete (CUD) 操作映射到存储过程。 默认情况下,Entity Framework 会自动为 CUD 操作生成 SQL 语句,但也可将存储过程映射到这些操作。
请注意,Code First 不支持映射到存储过程或函数。 但可使用 System.Data.Entity.DbSet.SqlQuery 方法调用存储过程或函数。 例如:
var query = context.Products.SqlQuery("EXECUTE [dbo].[GetAllProducts]");
将 CUD 操作映射到存储过程时的注意事项
将 CUD 操作映射到存储过程时,请注意以下事项:
- 如果要将其中一个 CUD 操作映射到存储过程,请映射所有这些操作。 如果不映射这三个操作,则未映射的操作将在执行时失败,并引发 UpdateException。
- 必须将存储过程的每个参数映射到实体属性。
- 如果服务器为插入的行生成主键值,则必须将此值映射回实体的键属性。 在下面的示例中,InsertPerson 存储过程返回新创建的主键,作为存储过程的结果集的一部分。 使用 EF Designer 的“<添加结果绑定>”功能将主键映射到实体键 (PersonID)。
- 存储过程调用与概念模型中的实体按 1:1 映射。 例如,如果在概念模型中实现了继承层次结构,然后映射了父(基)和子(派生)实体的 CUD 存储过程,那么保存“子”更改只会调用“子”的存储过程,而不会触发“父”的存储过程调用。
先决条件
若要完成此演练,您需要:
- Visual Studio 的最新版本。
- School 示例数据库。
设置项目
- 打开 Visual Studio 2012。
- 选择“文件”->“新建”->“项目”
- 在左窗格中,单击“Visual C#”,然后选择“控制台”模板。
- 输入“CUDSProcsSample”作为名称。
- 选择“确定”。
创建模型
在解决方案资源管理器中右键单击项目名称,然后选择“添加”->“新建项”。
从左侧菜单中选择“数据”,然后在“模板”窗格中选择“ADO.NET 实体数据模型”。
输入“CUDSProcs.edmx”作为文件名,然后单击“添加”。
在“选择模型内容”对话框中,选择“从数据库生成”,然后单击“下一步”。
单击“新建连接”。 在“连接属性”对话框中,输入服务器名称(例如 (localdb)\mssqllocaldb),选择身份验证方法,键入 School 作为数据库名称,然后单击“确定”。 “选择数据连接”对话框将根据你的数据库连接设置进行更新。
在“选择数据库对象”对话框中,在“表”节点下,选择“Person”表。
此外,在“存储过程和函数”节点下选择以下存储过程:DeletePerson、InsertPerson 和 UpdatePerson。
从 Visual Studio 2012 开始,EF Designer 支持批量导入存储过程。 默认情况下,将选中“将所选存储过程和函数导入到实体模型”。 由于在此示例中,我们有 insert、update 和 delete 实体类型的存储过程,因此我们不想导入它们,并将取消选中此复选框。
单击“完成” 。 系统将显示 EF Designer,它提供用于编辑模型的设计图面。
将 Person 实体映射到存储过程
右键单击 Person 实体类型并选择“存储过程映射”。
存储过程映射将显示在“映射详细信息”窗口中。
单击“<选择插入函数>”。 该字段变成一个下拉列表,该列表中包含存储模型中可以映射到概念模型中的实体类型的存储过程。 从下拉列表选择 InsertPerson。
此时将显示存储过程参数和实体属性之间的默认映射。 请注意,箭头指示映射方向:向存储过程参数提供属性值。
单击“<添加结果绑定>”。
键入 NewPersonID,它是由 InsertPerson 存储过程返回的参数的名称。 请确保不要键入前导空格或尾随空格。
按 Enter。
默认情况下,NewPersonID 映射到实体键 PersonID。 请注意,箭头指示映射的方向:向属性提供结果列的值。
单击“<选择更新函数>”,然后从结果下拉列表中选择 UpdatePerson。
此时将显示存储过程参数和实体属性之间的默认映射。
单击“<选择删除函数>”,然后从结果下拉列表中选择 DeletePerson。
此时将显示存储过程参数和实体属性之间的默认映射。
Person 实体类型的 insert、update 和 delete 操作现在将映射到存储过程。
如果要在使用存储过程更新或删除实体时启用并发检查,请使用以下选项之一:
- 使用 OUTPUT 参数从存储过程返回受影响的行数,并选中参数名称旁边的“受影响的行数参数”复选框。 如果调用操作时返回的值为零,则会引发 OptimisticConcurrencyException。
- 选中要用于并发检查的属性旁边的“使用原始值”复选框。 如果尝试更新,则向数据库写回数据时,将使用最初从数据库读取的属性的值。 如果值与数据库中的值不匹配,将引发 OptimisticConcurrencyException。
使用模型
打开 Program.cs 文件,其中定义了 Main 方法。 将以下代码添加到 Main 函数中。
此代码会创建一个新的 Person 对象,然后更新该对象,最后删除该对象。
using (var context = new SchoolEntities())
{
var newInstructor = new Person
{
FirstName = "Robyn",
LastName = "Martin",
HireDate = DateTime.Now,
Discriminator = "Instructor"
}
// Add the new object to the context.
context.People.Add(newInstructor);
Console.WriteLine("Added {0} {1} to the context.",
newInstructor.FirstName, newInstructor.LastName);
Console.WriteLine("Before SaveChanges, the PersonID is: {0}",
newInstructor.PersonID);
// SaveChanges will call the InsertPerson sproc.
// The PersonID property will be assigned the value
// returned by the sproc.
context.SaveChanges();
Console.WriteLine("After SaveChanges, the PersonID is: {0}",
newInstructor.PersonID);
// Modify the object and call SaveChanges.
// This time, the UpdatePerson will be called.
newInstructor.FirstName = "Rachel";
context.SaveChanges();
// Remove the object from the context and call SaveChanges.
// The DeletePerson sproc will be called.
context.People.Remove(newInstructor);
context.SaveChanges();
Person deletedInstructor = context.People.
Where(p => p.PersonID == newInstructor.PersonID).
FirstOrDefault();
if (deletedInstructor == null)
Console.WriteLine("A person with PersonID {0} was deleted.",
newInstructor.PersonID);
}
- 编译并运行该应用程序。 该程序生成以下输出 *
注意
PersonID 由服务器自动生成,因此很可能会看到不同的数字*
Added Robyn Martin to the context.
Before SaveChanges, the PersonID is: 0
After SaveChanges, the PersonID is: 51
A person with PersonID 51 was deleted.
如果使用的是 Visual Studio 旗舰版,则可将 Intellitrace 与调试器结合使用,以查看执行的 SQL 语句。