我不确定这是否可能,但我无法找到此用例的明确文档。我正在使用F#4和FSharp.Data.SqlClient
库连接到Sql Server 2016.我想调用一个返回多个表的存储过程并将这些表转换为相应的记录。在这种情况下,第一个表由items
组成,第二个表由customers
组成。我的直觉是看起来应该是这样的:
let items, customers = cmd.Execute()
我的直觉是items
将是IEnumerable<item>
而customers
将是IEnumerable<customer>
,其中item
和customer
都是记录类型。它看起来正在发生的是FSharp.Data.SqlClient
只看到存储过程中第一个返回的表。我正在研究SQL Server 2016 Developer实例。以下是设置示例的T-SQL:
create table Item (
ItemID int identity(1, 1) primary key,
ItemName nvarchar(50)
)
go
create table Customer (
CustomerID int identity(1, 1) primary key,
CustomerName nvarchar(50)
)
go
insert into Item (ItemName) values ('A');
insert into Item (ItemName) values ('B');
insert into Item (ItemName) values ('C');
insert into Customer (CustomerName) values ('Gary');
insert into Customer (CustomerName) values ('Sergei');
insert into Customer (CustomerName) values ('Elise');
go
create procedure dbo.ExampleProcedure
as
begin
set nocount on;
select
ItemID,
ItemName
from Item
select
CustomerID,
CustomerName
from Customer
end;
这是我正在测试的F#脚本。它显示了我希望能够做什么,但我在最后一行得到了编译错误:
#r "../packages/FSharp.Data.SqlClient.1.8.2/lib/net40/FSharp.Data.SqlClient.dll"
#r "../packages/FSharp.Data.2.3.2/lib/net40/FSharp.Data.dll"
#r "System.Xml.Linq.dll"
open FSharp.Data
[<Literal>]
let connStr =
"Data Source=**connection string**;"
type queryExample = SqlProgrammabilityProvider<connStr>
do
use cmd = new queryExample.dbo.ExampleProcedure(connStr)
let items, customers = cmd.Execute()
我希望items
对应于第一个返回的表,customers
对应于第二个返回的表。 intellisense表明FSharp.Data.SqlClient只看到第一个表。当我将鼠标悬停在cmd.Execute()
上时,弹出窗口显示"This expression was expected to have type 'a*'b but here has type System.Collections.Generic.IEnumerable<SqlProgrammabilityProvider<...>.dbo.ExampleProcedure.Record>"
。如果我执行以下操作,则可以访问存储过程中的Items
查询:
// Learn more about F# at http://fsharp.org. See the 'F# Tutorial' project
// for more guidance on F# programming.
#r "../packages/FSharp.Data.SqlClient.1.8.2/lib/net40/FSharp.Data.SqlClient.dll"
#r "../packages/FSharp.Data.2.3.2/lib/net40/FSharp.Data.dll"
#r "System.Xml.Linq.dll"
open FSharp.Data
[<Literal>]
let connStr =
"Data Source=**connection string**;"
type queryExample = SqlProgrammabilityProvider<connStr>
do
use cmd = new queryExample.dbo.ExampleProcedure(connStr)
for item in cmd.Execute() do
printfn "%A" item.ItemID
这甚至可能吗?我的方法有误吗?我找不到关于这个用例的明确文档,但我认为这将是常见的,它将被覆盖。我错过了什么?谢谢你的帮助。
更新2016-01-10:
只是为了澄清我想要实现的目标,我将展示如何在C#中解决这个问题。在C#中,我创建了一个DataSet
对象,并用存储过程的结果填充它。从那里我挑选出可以使用的各个表格。在提取表之后,我使用LINQ将行转换为相应的对象。它通常看起来如下:
using System.Data;
using System.Data.SqlClient;
var connStr = "**connection string**"
var sqlConnection = new SqlConnection(connStr );
var sqlCommand = new SqlCommand("ExampleProcedure", sqlConnection);
sqlCommand.CommandType = CommandType.StoredProcedure;
var dataSet = new DataSet();
var adapter = new SqlDataAdapter(sqlCommand);
adapter.Fill(dataSet);
var itemsTable = dataSet.Tables[0];
// Turn the itemsTable into a List<Item> using LINQ here
var customersTable = dataSet.Tables[1];
// Turn the customersTable into List<Customer> using LINQ here
我发现这对于提取单个表这样简单的事情来说过于冗长,但也许我对代码混乱过于敏感。我知道F#必须有更优雅和简洁的表达方式。
答案 0 :(得分:0)
我不知道F#,但这是一个数据访问问题。
当存储过程返回多个结果集时,您需要逐个访问它们。
cmd.ExecuteReader()返回指向第一个结果集的datareader实例。您需要处理此结果集,可能正在填充包含自定义类实例的列表,而不是调用方法&#34; NextResult&#34;并且您将可以访问下一个结果集,依此类推。
该方法的参考&#34; NextResult&#34;:https://msdn.microsoft.com/pt-br/library/system.data.sqlclient.sqldatareader.nextresult(v=vs.110).aspx