2017-01-10 3 views
4

Я не уверен, что это возможно, но я не смог найти четкую документацию для этого прецедента. Я использую F # 4 и библиотеку FSharp.Data.SqlClient для подключения к Sql Server 2016. Я хочу вызвать хранимую процедуру, которая возвращает несколько таблиц и превращает эти таблицы в соответствующие записи. В этом случае первая таблица состоит из items, а вторая таблица состоит из customers. Мой инстинкт, что он должен выглядеть примерно так:F # FSharp.Data.SqlClient не распознает несколько таблиц возврата из хранимой процедуры

let items, customers = cmd.Execute() 

Моя кишка является то, что items бы IEnumerable<item> и customers бы IEnumerable<customer> где item и customer оба типа записи. Однако, похоже, что FSharp.Data.SqlClient видит только первую возвращенную таблицу из хранимой процедуры. Я работаю над экземпляром разработчика SQL Server 2016. Вот пример 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(), popup говорит "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

Я не знаю, F #, однако это проблема доступа к данным.

Когда хранимая процедура возвращает несколько наборов результатов, вам необходимо получить доступ к ним последовательно, по одному.

cmd.ExecuteReader() возвращает экземпляр datareader, указывающий на первый набор результатов. Вам нужно обработать этот набор результатов, может быть заполнение списка экземплярами настраиваемого класса, чем вы вызываете метод «NextResult», и у вас будет доступ к следующему набору результатов и так далее.

Ссылка на метод «NextResult»: https://msdn.microsoft.com/pt-br/library/system.data.sqlclient.sqldatareader.nextresult(v=vs.110).aspx