MVC学习笔记四:利用Entity Framework调用存储过程
2013-11-07 23:59
459 查看
MVC利用EF调用存储过程
这一章记录一下,如何通过EF调用数据库中的存储过程。依然按照前面的两种数据库操作方式,一种是DbContext,第二种是ObjectContext.
在这之前,先在数据库中建立几张简单的表,方便做实例用。相关脚本如下,可供参考:
第一张表:City
USE [mydb] GO /****** Object: Table [dbo].[City] Script Date: 11/08/2013 23:06:16 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[City]( [CityId] [int] IDENTITY(1,1) NOT NULL, [ChinaName] [nchar](10) NOT NULL, [PinYin] [nvarchar](50) NOT NULL, [Description] [nvarchar](50) NULL, CONSTRAINT [PK_City] PRIMARY KEY CLUSTERED ( [CityId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO然后手工插入几条数据,这里只简单插入3条数据如下:
再建立一张商店表:Store
USE [mydb] GO /****** Object: Table [dbo].[Store] Script Date: 11/08/2013 23:11:43 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Store]( [StoreId] [int] IDENTITY(1,1) NOT NULL, [StoreName] [nvarchar](50) NOT NULL, [CityId] [int] NOT NULL, [Description] [nvarchar](50) NULL, CONSTRAINT [PK_Store] PRIMARY KEY CLUSTERED ( [StoreId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO手工插入几条数据如下,这里有7条:
最后建立一张销售表:Sale
USE [mydb] GO /****** Object: Table [dbo].[Sale] Script Date: 11/08/2013 23:14:42 ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE TABLE [dbo].[Sale]( [Id] [int] IDENTITY(1,1) NOT NULL, [BusinessDate] [datetime] NOT NULL, [StoreId] [int] NOT NULL, [TotalAccount] [decimal](18, 0) NOT NULL, CONSTRAINT [PK_Sale] PRIMARY KEY CLUSTERED ( [BusinessDate] ASC, [StoreId] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO手工插入几条数据,如下:
好了,这里示例实现的简单功能就是:取出2013年11月1号所有店铺各自的销售金额一览。
这里需要写一个简单的存储过程,返回类似下面格式的表:
在数据库中新建一个存储过程:GetIphoneSaleDailyReport,它接受一个日期形式的参数。这里为了测试方便,指定成'2013-11-1'这一天。
use mydb go SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO -- ============================================= -- Author: <Author,,Name> -- Create date: <Create Date,,> -- Description: <Description,,> -- ============================================= CREATE PROCEDURE GetIphoneSaleDailyReport -- Add the parameters for the stored procedure here @businessDate as datetime AS BEGIN -- SET NOCOUNT ON added to prevent extra result sets from -- interfering with SELECT statements. SET NOCOUNT ON; select CONVERT(varchar(100),a.BusinessDate,23) as 日期,aa.ChinaName as '城市',aa.StoreName as '分店',aa.Description as '分店说明',a.TotalAccount '销售总计' from mydb.dbo.Sale as a left join (select c.ChinaName,b.StoreName,b.StoreId,b.Description from mydb..Store b inner join mydb..City c on b.CityId=c.CityId) aa on a.StoreId=aa.StoreId where a.BusinessDate=@businessDate END GO可以先在数据库测试一下,看看存储过程是否新建成功:
exec GetIphoneSaleDailyReport '2013-11-1'如果返回上面的一览表,就说明存储过程没什么问题了。
然后打开之前介绍的示例项目FirstMvcWithEF,双击打开Apples.edmx文件,鼠标右击空白处选择“从数据库更新模型”如下:
将存储过程添加到edmx文件中:
点击完成,结束添加。这时候从edmx的模型浏览器里可以看出,多出了一个存储过程,如下:
同样,再在edmx界面空白处,右击鼠标 新增 函数导入:
设置界面如下,选择之前加入的存储过程,由于存储过程返回的是一张表,这里选择复杂类型,而且系统也自动帮我创建了一个复杂类型,点击“获取列信息”可以看到存储过程返回的各种列名及其它列类型信息。
上面的准备工作已经做完,接下来介绍两种方式执行存储过程。
一.DbContext方式
如果使用的是VS2012,那么系统默认指定的可能就是这种方式。首先,在Controllers文件夹里新建一个控制器,取名“ReportController”,在它的默认Index方法上新建一个视图。
编译项目,在Index方法上新建一个强类型的视图,但是我始终找不到上面的复杂类型“GetIphoneSaleDailyReport_Result”,在项目其它地方也引用不到它,感到很奇怪,所以这种方式就先不能实现了,如有朋友知道如何处理,可以帮忙指点下
但是具体的调用存储过程是可以使用如下的方式:
public virtual IEnumerable<TEntity> GetWithRawSql(string query, params object[] parameters) { return dbSet.SqlQuery(query, parameters).ToList(); } public ActionResult Details(int id) { var query = "exec T_Get @p0"; return View(unitOfWork.CourseRepository.GetWithRawSql(query, id).Single()); }
二.ObjectContext方式
按照之前介绍的方式,将方式改成ObjectContext,不清楚的可以看这里,有可能还要删除Iphones.cs文件(如果之前使用DbContext遗留下来的话)。这时候再去新建上面的Index视图时,选择强类型,就可以找到复杂属性“GetIphoneSaleDailyReport_Result”了
,注意模板支架选择List:
然后修改Index方法如下:
public ActionResult Index() { mydbEntities db = new mydbEntities(); var results = db.GetIphoneSaleDailyReport(DateTime.Parse("2013-11-1")); return View(results); }
修改对应的Index视图如下:
@model IEnumerable<FirstMvcWithEF.Entities.GetIphoneSaleDailyReport_Result> @{ ViewBag.Title = "Index"; } <h2>测试存储过程</h2> <div id="grid"> @{ var grid = new WebGrid(source: Model.ToList(), defaultSort: "分店", rowsPerPage: 7); } @grid.GetHtml( tableStyle: "table", headerStyle: "gridhead", alternatingRowStyle: "rowStyle", columns: grid.Columns( grid.Column("日期","日期",null,null,false), grid.Column("城市","城市"), grid.Column("分店","分店"), grid.Column("分店说明","分店说明"), grid.Column(null,"销售总计",format:@<text><input class="test-box" id="test-box" name="test-box" type="text" value="@item.销售总计"/></text>) ) ) </div>
OK,编译运行,看下效果,注意视图在Report下,地址后面要加/Report:
到此,调用存储过程成功了。