Я не уверен, что это возможно, но я не смог найти четкую документацию для этого прецедента. Я использую 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 # должен иметь более элегантный и простой способ выразить это.