咱们已经知道EF能够将L2E或Entity SQL的查询语句自动转换成SQL命令,也能够根据实体的状态自动生成Insert/update/delete的Sql命令。这节介绍EF中使用预先定义的存储过程对一张或者多种表进行CURD操做。html
EF API会新建一个function来映射数据库中的自定义函数或存储过程。下边讲解EF DbFirst模式下存储过程的用法,EF CodeFirst存储过程的用法会在之后的EF CodeFirst系列中介绍。数据库
首先在数据库建立一个名为GetCoursesByStudentId的存储过程,这个存储过程返回一个学生的全部课程。浏览器
CREATE PROCEDURE [dbo].[GetCoursesByStudentId] -- Add the parameters for the stored procedure here @StudentId int = null AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; -- Insert statements for procedure here select c.courseid, c.coursename,c.Location, c.TeacherId from student s left outer join studentcourse sc on sc.studentid = s.studentid left outer join course c on c.courseid = sc.courseid where s.studentid = @StudentId END
这一步和普通生成EMD过程是同样的,值得注意的是在Choose Your Database Objects and Settings这一步勾选咱们新建的存储过程(GetCoursesByStudentId)和下边的Import selected stored procedures and functions into the entity model ,以下图所示app
GetCoursesByStudentId()返回Course实体集合,因此咱们不须要返回一个新的复杂类型。右键Function Imports下的GetCoursesByStudentId方法,选择Edit,出现如下界面,把Entities设置为Course便可函数
经过上边两步,在context中会生成一个GetCoursesByStudentId方法:post
如今咱们就能够愉快地使用context.GetCoursesByStudentId来执行存储过程了!以下:spa
using (var context = new SchoolDBEntities()) { var courses = context.GetCoursesByStudentId(1); foreach (Course cs in courses) Console.WriteLine(cs.CourseName); }
在数据库中执行的命令为: exec [dbo].[GetCoursesByStudentId] @StudentId=1 设计
一点补充:EF中的表值函数和查询的存储过程使用的步骤是如出一辙的(表值函数和存储过程原本就很相似,一个最重要的区别是EF中表值函数的返回值可用linq查询过滤)3d
这一部分介绍怎么经过存储过程来执行CUD(creat,update,delete)操做。code
咱们在数据库添加如下几个存储:
Sp_InsertStudentInfo(添加):
CREATE PROCEDURE [dbo].[sp_InsertStudentInfo] -- Add the parameters for the stored procedure here @StandardId int = null, @StudentName varchar(50) AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; INSERT INTO [SchoolDB].[dbo].[Student]([StudentName],[StandardId]) VALUES(@StudentName, @StandardId) SELECT SCOPE_IDENTITY() AS StudentId END
sp_UpdateStudent(修改):
CREATE PROCEDURE [dbo].[sp_UpdateStudent] -- Add the parameters for the stored procedure here @StudentId int, @StandardId int = null, @StudentName varchar(50) AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; Update [SchoolDB].[dbo].[Student] set StudentName = @StudentName,StandardId = @StandardId where StudentID = @StudentId; END
sp_DeleteStudent(删除):
CREATE PROCEDURE [dbo].[sp_DeleteStudent] -- Add the parameters for the stored procedure here @StudentId int AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; DELETE FROM [dbo].[Student] where StudentID = @StudentId END
首先咱们要升级EDM把这些存储过程添加当咱们的EDM中。右键设计器,选择Update Model from Database,就出现了升级界面,以下图所示,展开Stored Procedure and Functions,勾选咱们上边建立的三个存储过程,而后点击Finish。
这时模型浏览器中在Store Model中有了这三个存储过程,可是Function Imports中没有,以下所示:
打开模型设计器在Student实体上右键,选择Stored Procedure Mapping,来打开映射详情界面,以下图
在下面的映射详细界面,咱们看到<Select Insert Function>, <Select Update Function>, and <Select Delete Function>,给这些下拉菜单分别选择对应的存储过程,同时选择存储过程的输入输出参数,以下图所示:
右击Student实体,选择Validate,确保没有错误
如今咱们执行add,update,或者delete时,EF再也不执行自动生成的SQL命令,而是经过这些存储过程来执行,下面是一个栗子:
using (var context = new SchoolDBEntities()) { Student student = new Student() { StudentName = "New student using SP"}; context.Students.Add(student); //执行 sp_InsertStudentInfo context.SaveChanges(); student.StudentName = "Edit student using SP"; //执行 sp_UpdateStudent context.SaveChanges(); context.Students.Remove(student); //执行 sp_DeleteStudentInfo context.SaveChanges(); }
调用SaveChange()方法时,在数据库中执行的命令以下:
exec [dbo].[sp_InsertStudentInfo] @StandardId=NULL,@StudentName='New student using SP' go exec [dbo].[sp_UpdateStudent] @StudentId=47,@StandardId=NULL,@StudentName='Edit student using SP' go exec [dbo].[sp_DeleteStudent] @StudentId=47 go
注意:不管是使用存储过程仍是默认生成的Sql命令,当插入一条记录并执行完SaveChange()方法后,这个新的实例会当即分配一个Id。这样设计是为了有效地追踪实体,让咱们能够对实体执行进一步的操做(如没有id执行update会抛出异常),以下图:
EF系列目录连接:Entity Franmework系列教程汇总