普通存储过程

首先在查询分析器运行下面的代码来创建一个存储过程:

create proc sp_singleresultset

as

set nocount on

select * from customers

然后打开IDE的服务器资源管理器,之前我们从表中拖动表到dbml设计视图,这次我们从存储过程中找到刚才创建的存储过程,然后拖动到设计视图。在方法面板中可以看到已经创建了一个sp_singleresultset的方法,如下图:

然后打开Northwind.designer.cs,可以找到下面的代码:

[Function(Name="dbo.sp_singleresultset")]

public ISingleResult<sp_singleresultsetResult> sp_singleresultset()

{

IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())));

return ((ISingleResult<sp_singleresultsetResult>)(result.ReturnValue));

}

我们可以发现,IDE为这个存储过程单独生成了返回结果集的实体定义,你可能会觉得很奇怪,IDE怎么知道这个存储过程将会返回哪些数据那?其实,在把存储过程拖拽入dbml设计视图的时候,IDE就执行了类似下面的命令:

SET FMTONLY ON;

exec Northwind.dbo.sp_singleresultset

SET FMTONLY OFF;

这样就可以直接获取存储过程返回的元数据而无须执行存储过程。

其实我们存储过程返回的就是顾客表的数据,如果你觉得为存储过程单独设置结果集实体有些浪费的话可以在存储过程的属性窗口中调整返回类型从“自动生成的类型”到Customer,不过以后你只能通过删除方法面板中的存储过程,然后重新添加来还原到“自动生成的类型”。下面,我们可以写如下的Linq to object代码进行查询:

var 单结果集存储过程 =

from c in ctx.sp_singleresultset()

where c.CustomerID.StartsWith("A")

select c;

在这里确实是Linq to object的,因为查询句法不会被整句翻译成SQL,而是从存储过程的返回对象中再去对对象进行查询。SQL代码如下:

EXEC @RETURN_VALUE = [dbo].[sp_singleresultset]

-- @RETURN_VALUE: Output Int32 (Size = 0; Prec = 0; Scale = 0) []

带参数的存储过程

创建如下存储过程:

create proc [dbo].[sp_withparameter]

@customerid nchar(5),

@rowcount int output

as

set nocount on

set @rowcount = (select count(*) from customers where customerid = @customerid)

使用同样的方法生成存储过程方法,然后使用下面的代码进行测试:

int? rowcount = -1;

ctx.sp_withparameter("", ref rowcount);

Response.Write(rowcount);

ctx.sp_withparameter("ALFKI", ref rowcount);

Response.Write(rowcount);

结果输出了“01”。说明ID为“”的顾客数为0,而ID为“ALFKI”的顾客数为1。存储过程的输出参数被封装成了ref参数,对于C#语法来说非常合情合理。SQL代码如下:

EXEC @RETURN_VALUE = [dbo].[sp_withparameter] @customerid = @p0, @rowcount = @p1 OUTPUT

-- @p0: Input StringFixedLength (Size = 5; Prec = 0; Scale = 0) []

-- @p1: InputOutput Int32 (Size = 0; Prec = 0; Scale = 0) [-1]

-- @RETURN_VALUE: Output Int32 (Size = 0; Prec = 0; Scale = 0) []

带返回值的存储过程

再来创建第三个存储过程:

create proc [dbo].[sp_withreturnvalue]

@customerid nchar(5)

as

set nocount on

if exists (select 1 from customers where customerid = @customerid)

return 101

else

return 100

生成方法后,可以通过下面的代码进行测试:

Response.Write(ctx.sp_withreturnvalue(""));

Response.Write(ctx.sp_withreturnvalue("ALFKI"));

运行后程序输出“100101”

 

多结果集的存储过程

再来创建一个多结果集的存储过程:

create proc [dbo].[sp_multiresultset]

as

set nocount on

select * from customers

select * from employees

找到生成的存储过程方法:

[Function(Name="dbo.sp_multiresultset")]

public ISingleResult<sp_multiresultsetResult> sp_multiresultset()

{

IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())));

return ((ISingleResult<sp_multiresultsetResult>)(result.ReturnValue));

}

由于现在的VS2008会把多结果集存储过程识别为单结果集存储过程(只认识第一个结果集),我们只能对存储过程方法多小动手术,修改为:

[Function(Name="dbo.sp_multiresultset")]

[ResultType(typeof(Customer))]

[ResultType(typeof(Employee))]

public IMultipleResults sp_multiresultset()

{

IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())));

return (IMultipleResults)(result.ReturnValue);

}

然后使用下面的代码测试:

var 多结果集存储过程 = ctx.sp_multiresultset();

var Customers = 多结果集存储过程.GetResult<Customer>();

var Employees = 多结果集存储过程.GetResult<Employee>();

GridView1.DataSource = from emp in Employees where emp.FirstName.Contains("A") select emp;

GridView1.DataBind();

GridView2.DataSource = from c in Customers where c.CustomerID.StartsWith("A") select c;

GridView2.DataBind();

使用存储过程新增数据

存储过程除了可以直接调用之外,还可以用于实体的增删改操作。还记得在《一步一步学Linq to sql(三):增删改》中创建的留言簿程序吗?下面我们就来改造这个程序,使用存储过程而不是系统生成的SQL实现实体增删改。首先,我们创建下面的存储过程

create proc sendmessage

@username varchar(50),

@message varchar(500)

as

insert into tbguestbook

(id,username,posttime,[message],isreplied,reply)

values

(newid(),@username,getdate(),@message,0,'')

然后,打开留言簿dbml,把存储过程从服务器资源管理器拖拽到设计视图上。右键点击tbGuestBook实体类,选择配置行为。如下图,为插入操作选择刚才创建的存储过程方法,并进行参数匹配:

由于我们的存储过程只接受2个参数,相应修改以下创建留言的按钮处理事件:

protected void btn_SendMessage_Click(object sender, EventArgs e)

{

tbGuestBook gb = new tbGuestBook();

gb.UserName = tb_UserName.Text;

gb.Message = tb_Message.Text;

ctx.tbGuestBooks.Add(gb);

ctx.SubmitChanges();

SetBind();

}

运行程序后可以发现,在提交修改的时候调用了下面的SQL:

EXEC @RETURN_VALUE = [dbo].[sendmessage] @username = @p0, @message = @p1

-- @p0: Input AnsiString (Size = 5; Prec = 0; Scale = 0) [zhuye]

-- @p1: Input AnsiString (Size = 11; Prec = 0; Scale = 0) [new message]

-- @RETURN_VALUE: Output Int32 (Size = 0; Prec = 0; Scale = 0) []

 

使用存储过程删除数据

创建如下存储过程:

create proc delmessage

@id uniqueidentifier

as

delete tbguestbook where id=@id

按照前面的步骤生成存储过程方法,并为删除操作执行这个存储过程方法。在选择参数的时候我们可以看到,ID分当前值和原始值,我们选择当前值即可,如下图:

无须改动任何逻辑代码,进行删除留言操作后可以跟踪到下面的SQL:

EXEC @RETURN_VALUE = [dbo].[delmessage] @id = @p0

-- @p0: Input Guid (Size = 0; Prec = 0; Scale = 0) [9e3c5ee3-2575-458e-899d-4b0bf73e0849]

-- @RETURN_VALUE: Output Int32 (Size = 0; Prec = 0; Scale = 0) []

 

使用存储过程更改数据

创建如下存储过程:

create proc replymessage

@id uniqueidentifier,

@reply varchar(500)

as

update tbguestbook set reply=@reply,isreplied=1 where id=@id

       由于更新的时候并不会更新主键,所以我们可以为两个参数都指定当前值。回复留言后可以跟踪到下面的SQL:

EXEC @RETURN_VALUE = [dbo].[replymessage] @id = @p0, @reply = @p1

-- @p0: Input Guid (Size = 0; Prec = 0; Scale = 0) [67a69d0f-a88b-4b22-8939-fed021eb1cb5]

-- @p1: Input AnsiString (Size = 6; Prec = 0; Scale = 0) [464456]

-- @RETURN_VALUE: Output Int32 (Size = 0; Prec = 0; Scale = 0) []

假设有这样一种应用,我们需要修改留言簿中不合法的用户名:

create proc modiusername

@oldusername varchar(50),

@newusername varchar(50)

as

update tbguestbook set username=@newusername where username = @oldusername

有个网友起名叫“admin”,我们要把所有这个名字修改为“notadmin”。那么,可以如下图设置update操作:

然后运行下面的测试代码:

var messages = from gb in ctx.tbGuestBooks

select gb;

foreach (var gb in messages)

{

if(gb.UserName == "admin")

gb.UserName = "notadmin";

}

运行程序后能跟踪到下面的SQL:

SELECT [t0].[ID], [t0].[UserName], [t0].[PostTime], [t0].[Message], [t0].[IsReplied], [t0].[Reply]

FROM [dbo].[tbGuestBook] AS [t0]

EXEC @RETURN_VALUE = [dbo].[modiusername] @oldusername = @p0, @newusername = @p1

-- @p0: Input AnsiString (Size = 5; Prec = 0; Scale = 0) [admin]

-- @p1: Input AnsiString (Size = 8; Prec = 0; Scale = 0) [notadmin]

-- @RETURN_VALUE: Output Int32 (Size = 0; Prec = 0; Scale = 0) []

到这里,你应该能明白当前值和原始值的含义了吧。

一步一步学Linq to sql(五):存储过程的更多相关文章

  1. (转载)一步一步学Linq to sql系列文章

    现在Linq to sql的资料还不是很多,本人水平有限,如果有错或者误导请指出,谢谢. 一步一步学Linq to sql(一):预备知识 一步一步学Linq to sql(二):DataContex ...

  2. 步步学LINQ to SQL:为实体类添加关系【转】

    [IT168 专稿]本文详细为你阐述了如何在你的应用程序中实现LINQ to SQL.附件的示例程序包括了这里探讨的所有代码,还提供了一个简单的WPF图形界面程序来显示通过数据绑定返回的结果集. 第一 ...

  3. 步步学LINQ to SQL:使用LINQ检索数据【转】

    [IT168 专稿]该系列教程描述了如何采用手动的方式映射你的对象类到数据表(而不是使用象SqlMetal这样的自动化工具)以便能够支持数据表之间的M:M关系和使用实体类的数据绑定.即使你选择使用了自 ...

  4. 步步学LINQ to SQL:将类映射到数据库表【转】

    [IT168 专稿]该系列教程描述了如何采用手动的方式映射你的对象类到数据表(而不是使用象SqlMetal这样的自动化工具)以便能够支持数据表之间的M:M关系和使用实体类的数据绑定.即使你选择使用了自 ...

  5. 一步一步学Linq to sql(六):探究特性

    延迟执行 IQueryable query = from c in ctx.Customers select c; 这样的查询句法不会导致语句立即执行,它仅仅是一个描述,对应一个SQL.仅仅在需要使用 ...

  6. 一步一步学Linq to sql(四):查询句法

    select 描述:查询顾客的公司名.地址信息 查询句法: var 构建匿名类型1 = from c in ctx.Customers select new { 公司名 = c.CompanyName ...

  7. 一步一步学Linq to sql(三):增删改

    示例数据库 字段名 字段类型 允许空 字段说明 ID uniqueidentifier 表主键字段 UserName varchar(50) 留言用户名 PostTime datetime 留言时间 ...

  8. 一步一步学Linq to sql(二):DataContext与实体

    DataContext DataContext类型(数据上下文)是System.Data.Linq命名空间下的重要类型,用于把查询句法翻译成SQL语句,以及把数据从数据库返回给调用方和把实体的修改写入 ...

  9. 一步一步学Linq to sql(一):预备知识

    什么是Linq to sql Linq to sql(或者叫DLINQ)是LINQ(.NET语言集成查询)的一部分,全称基于关系数据的 .NET 语言集成查询,用于以对象形式管理关系数据,并提供了丰富 ...

随机推荐

  1. Kubernetes API server工作原理

    作为Kubernetes的使用者,每天用得最多的命令就是kubectl XXX了. kubectl其实就是一个控制台,主要提供的功能: 1. 提供Kubernetes集群管理的REST API接口,包 ...

  2. oozie coordinator 定时调度

      (本段内容摘自http://blog.sina.com.cn/s/blog_e699b42b0102xjqw.html  Oozie总结 行成于思的博客)      Oozie提出了Coordin ...

  3. python入门3 python变量,id(),is运算符

    python变量无需声明数据类型,可以直接赋值使用. 比如: num=100 #整数 str="字符串" #字符串 turple1 =('mon','tue','wed','thu ...

  4. http中COOKIE和SESSION有什么区别?(转知乎)

    作者:知乎用户链接:https://www.zhihu.com/question/19786827/answer/28752144来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...

  5. Asp.net网站优化【转】

    阅读目录 开始 配置OutputCache 启用内容过期 解决资源文件升级问题 启用压缩 删除无用的HttpModule 其它优化选项 本文将介绍一些方法用于优化ASP.NET网站性能,这些方法都是不 ...

  6. HDU 5723 最小生成树上的期望

    题意:求最小生成树,和任意两个点之间距离的期望 官方题解: 最后求两遍点的积的时候,还是要判断父子关系. 注意 long long #include <bits/stdc++.h> usi ...

  7. springboot(服务端接口)获取URL请求参数的几种方法

    原文地址:http://www.cnblogs.com/xiaoxi/p/5695783.html 一.下面为7种服务端获取前端传过来的参数的方法  常用的方法为:@RequestParam和@Req ...

  8. sql字段为datetime,插入''的时候默认为1900年

    Microsoft SQL Server Database Engine 用两个 4 字节的整数内部存储 datetime 数据类型的值. 第一个 4 字节存储“基础日期”(即 1900 年 1 月  ...

  9. [Oracle]Audit(一)--认识Audit

    1.Audit的概念 Audit是监视和记录用户对数据库进行的操作,以供DBA进行问题分析.利用Audit功能,可以完成以下任务: 监视和收集特定数据库活动的数据.例如管理员能够审计哪些表被更新,在某 ...

  10. Oracle中的一些查询语句及其执行顺序

    查询条件: 1)LIKE:模糊查询,需要借助两个通配符,%:表示0到多个字符:_:标识单个字符. 2)IN(list):用来取出符合列表范围中的数据. 3)NOT IN(list): 取出不符合此列表 ...