【问题标题】:F# FSharp.Data.SqlClient not recognizing multiple return tables from Stored ProcedureF# FSharp.Data.SqlClient 无法识别存储过程中的多个返回表
【发布时间】:2017-01-10 05:38:11
【问题描述】:

我不确定这是否可行,但我无法找到此用例的清晰文档。我正在使用 F# 4 和 FSharp.Data.SqlClient 库连接到 SQL Server 2016。我想调用一个返回多个表并将这些表转换为相应记录的存储过程。在这种情况下,第一个表由items 组成,第二个表由customers 组成。

我的直觉是它应该看起来像这样:

let items, customers = cmd.Execute()

我的直觉是 items 将是 IEnumerable<item>customers 将是 IEnumerable<customer> 其中 itemcustomer 都是记录类型。看起来正在发生的事情是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 对应于第二个返回的表。智能感知表明 FSharp.Data.SqlClient 只看到第一个表。当我将鼠标悬停在cmd.Execute() 上时,弹出窗口会显示"This expression was expected to have type 'a*'b but here has type System.Collections.Generic.IEnumerable&lt;SqlProgrammabilityProvider&lt;...&gt;.dbo.ExampleProcedure.Record&gt;"。如果我执行以下操作,我可以访问存储过程中的 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

这甚至可能吗?我的方法错了吗?我找不到关于这个用例的明确文档,但我认为它会很常见,它会被涵盖。

更新

只是为了澄清我想要实现的目标,我将展示如何在 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# 必须有更优雅、更简洁的方式来表达这一点。

【问题讨论】:

    标签: sql-server stored-procedures f# f#-data


    【解决方案1】:

    我不知道 F#,但是这是一个数据访问问题。

    当一个存储过程返回多个结果集时,你需要一个一个地依次访问它们。

    cmd.ExecuteReader() 返回指向第一个结果集的数据读取器实例。您需要处理此结果集,可能正在使用自定义类的实例填充列表,然后调用方法“NextResult”,您将可以访问下一个结果集等等。

    方法“NextResult”的引用:https://msdn.microsoft.com/pt-br/library/system.data.sqlclient.sqldatareader.nextresult(v=vs.110).aspx

    【讨论】:

      猜你喜欢
      • 2013-07-06
      • 2011-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-13
      • 1970-01-01
      • 2016-01-25
      相关资源
      最近更新 更多