本文接着上篇文章Linq to SQL之使用存储过程 (1),继续探讨如何在Linq to SQL中使用存储过程。
在写存储过程的时候,有时候会用到返回值而不是output参数,现在看看怎样取到该返回值呢?
比如这样一个存储过程:
create procedure dbo.linqDemo4 @input varchar(20) as select * from customers return 20
设计器自动生成的函数如下,可以看到并没有提供方式取到该存储过程的返回值:
[Function(Name="dbo.linqDemo4")] public ISingleResult<Customer> linqDemo4([Parameter(DbType="VarChar(20)")] string input) { IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), input); return ((ISingleResult<Customer>)(result.ReturnValue)); }
只能靠自己了,增加一个函数对它进行包装,以此来取到返回值
public ISingleResult<Customer> linqDemo4WithReturnValue(string input, out int returnValue) { ISingleResult<Customer> result = linqDemo4(input); returnValue = (int)result.ReturnValue; return (ISingleResult<Customer>)(result); }
增加一个out参数returnValue,这样就能从结果中取到这个返回值。不知道以后的设计器能不能自动识别。
有时候会到这种需求,存储过程返回多个结果集合,那么这时候怎么操作才能把结果集分开呢。比如下面这个存储过程,能不能把Customer和Order的结果集分别取到呢?
create procedure dbo.linqDemo5 as select * from customers select * from orders通过设计器来映射存储过程,不能识别多个结果集。如果自动创建结果类的话,它只识别出第一个返回的结果集,比如上面这个存储过程,自动生成的结果类
linqDemo5Result里面只包括customer表的所有字段。不过,Linq to SQL中提供了ResultType Attribute来标志该存储过程会返回什么类型的对象以及IMultipleResults接口来满足获得多个结果集的问题。首先看看自动生成的方法:
[Function(Name="dbo.linqDemo5")] public ISingleResult<linqDemo5Result> linqDemo5() { IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod()))); return ((ISingleResult<linqDemo5Result>)(result.ReturnValue)); }
我们对它进行修改,用ResultType标记返回的结果中将包含哪些类型,再使用IMultipleResults返回多个结果集
[Function(Name="dbo.linqDemo5")] [ResultType(typeof(Customer))] [ResultType(typeof(Order))] public IMultipleResults linqDemo5() { return (IMultipleResults)(this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())))).ReturnValue; }
在我们的代码中如下使用:
NorthwindDataContext ctx = new NorthwindDataContext(); IMultipleResults results = ctx.linqDemo5(); foreach (var c in results.GetResult<Customer>()) { Console.WriteLine(c); } foreach (var o in results.GetResult<Order>()) { Console.WriteLine(o); }
值得注意的是GetResult的顺序依赖于存储过程中返回结果的顺序,如果先返回customer结果集就必须先调用GetResult<Customer>,否则会出现异常。可以说在调用GetResult的时候,根据对象属性映射列来取值,一旦发现不匹配就会出现错误。假设里面使用的dataReader,构造Customer对象的时候对属性进行赋值,c.CustomerID=reader["CustomerID"],如果没有这一列就抛出异常了。所以说在存储过程中使用多个结果集限制性非常大。