FSharp.Data.SqlClient


Controlling output

1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
//Connection and query definition are shared for most of the examples below

[<Literal>]
let productsSql = " 
    SELECT TOP (@top) Name AS ProductName, SellStartDate, Size
    FROM Production.Product 
    WHERE SellStartDate > @SellStartDate
"
  • Sequence of custom records is default result set type.
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
9: 
type QueryProductAsRecords = SqlCommandProvider<productsSql, connectionString>
let queryProductAsRecords = new QueryProductAsRecords(connectionString)

let records = 
    queryProductAsRecords.AsyncExecute(top = 7L, SellStartDate = System.DateTime.Parse "2002-06-01")
    |> Async.RunSynchronously 
    |> List.ofSeq

records |> Seq.iter (printfn "%A")

These records implement DynamicObject for easy binding and JSON.NET serialization and Equals for structural equality.

  • Sync execution
  • Seq of tuples as result set type
  • Consider ResultType.Tuples to work around unique column name limitation for ResultType.Records.
1: 
2: 
3: 
4: 
5: 
6: 
7: 
8: 
type QueryProductSync = SqlCommandProvider<productsSql, connectionString, ResultType = ResultType.Tuples>

do
    use cmd = new QueryProductSync(connectionString)
    let tuples = cmd.Execute(top = 7L, SellStartDate = System.DateTime.Parse "2002-06-01") 

    for productName, sellStartDate, size in tuples do
        printfn "Product name: %s. Sells start date %A, size: %A" productName sellStartDate size
  • Typed data table as result set
  • DataTable result type is an enabler for data binding and update scenarios. Look at data modification for details.
1: 
2: 
3: 
4: 
5: 
do 
    use cmd = new SqlCommandProvider<productsSql, connectionString, ResultType.DataTable>(connectionString)
    let table = cmd.Execute(top = 7L, SellStartDate = System.DateTime.Parse "2002-06-01") 
    for row in table.Rows do
        printfn "Product name: %s. Sells start date %O, size: %A" row.ProductName row.SellStartDate row.Size
  • Single row hint. Must be provided explicitly. Cannot be inferred
  • Nullable columns mapped to Option<_> type
  • Calling SQL Table-Valued Function
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
type QueryPersonInfoSingletoneAsRecords = 
    SqlCommandProvider<"SELECT * FROM dbo.ufnGetContactInformation(@PersonId)"
                        , connectionString
                        , SingleRow = true>

let singleton = new QueryPersonInfoSingletoneAsRecords(connectionString)

let person = singleton.AsyncExecute(PersonId = 2) |> Async.RunSynchronously |> Option.get
match person.FirstName, person.LastName with
| Some first, Some last -> printfn "Person id: %i, name: %s %s" person.PersonID first last 
| _ -> printfn "What's your name %i?" person.PersonID
  • Same as previous but using tuples as result type
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
[<Literal>]
let queryPersonInfoSingletoneQuery = 
    "SELECT PersonID, FirstName, LastName FROM dbo.ufnGetContactInformation(@PersonId)"

type QueryPersonInfoSingletoneTuples = 
    SqlCommandProvider<queryPersonInfoSingletoneQuery, connectionString, ResultType.Tuples, SingleRow=true>

QueryPersonInfoSingletoneTuples
    .Create(connectionString)
    .Execute(PersonId = 2).Value
    |> (function
        | id, Some first, Some last -> printfn "Person id: %i, name: %s %s" person.PersonID first last 
        | id, _, _ -> printfn "What's your name %i?" person.PersonID
    ) 
  • Same as previous but using typed DataTable as result type
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
type QueryPersonInfoSingletoneDataTable = 
    SqlCommandProvider<
        "SELECT * FROM dbo.ufnGetContactInformation(@PersonId)", 
        connectionString, 
        ResultType = ResultType.DataTable>

do 
    use cmd = new QueryPersonInfoSingletoneDataTable(connectionString)
    let table = cmd .AsyncExecute(PersonId = 2) |> Async.RunSynchronously 
    for row in table.Rows do
        printfn "Person info:Id - %i,FirstName - %O,LastName - %O" row.PersonID row.FirstName row.LastName 

// you can refer to the table type
let table2 : QueryPersonInfoSingletoneDataTable.Table = 
    let cmd = new QueryPersonInfoSingletoneDataTable(connectionString)
    cmd.Execute(PersonId = 2)

// you can refer to the row type
for row : QueryPersonInfoSingletoneDataTable.Table.Row in table2.Rows do
    printfn "Person info:Id - %i,FirstName - %O,LastName - %O" row.PersonID row.FirstName row.LastName 
  • Same as previous but using SqlProgrammabilityProvider<...>
  • Worth noting that Stored Procedure/Function generated command instances have explicit ExecuteSingle/ AsyncExecuteSingle methods because there is no single place to specify SingleRow=true as for SqlCommandProvider.
1: 
2: 
3: 
4: 
5: 
6: 
7: 
type AdventureWorks2012 = SqlProgrammabilityProvider<connectionString>
do
    use cmd = new AdventureWorks2012.dbo.ufnGetContactInformation(connectionString)
    cmd.ExecuteSingle(1) //opt-in for explicit call to 
    |> Option.iter(fun x ->  
        printfn "Person info:Id - %i,FirstName - %O,LastName - %O" x.PersonID x.FirstName x.LastName 
    )
  • One column only result set is inferred. Combined with SingleRow hint it gives single value as result
  • AsyncExecute/Execute are just regular F# methods, so args can be passed by name or by position
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
type QueryPersonInfoSingleValue = 
    SqlCommandProvider<
        "SELECT FirstName + ' '  + LastName FROM dbo.ufnGetContactInformation(@PersonId)", 
        connectionString, 
        SingleRow=true>

do 
    let personId = 2
    use cmd = new QueryPersonInfoSingleValue(connectionString)
    cmd.Execute( personId)
    |> Option.iter (fun name -> printf "Person with id %i has name %s" personId name.Value)
  • Single value
  • Running the same command more than once with diff params
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
type GetServerTime = 
    SqlCommandProvider<
        "IF @IsUtc = CAST(1 AS BIT) SELECT GETUTCDATE() ELSE SELECT GETDATE()", 
        connectionString, 
        SingleRow=true>

let getSrvTime = new GetServerTime(connectionString)

getSrvTime.AsyncExecute(IsUtc = true) |> Async.RunSynchronously |> printfn "%A"
getSrvTime.Execute(IsUtc = false) |> printfn "%A"
  • Non-query
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
[<Literal>]
let invokeSp = "
    EXEC HumanResources.uspUpdateEmployeePersonalInfo 
        @BusinessEntityID, 
        @NationalIDNumber,
        @BirthDate, 
        @MaritalStatus, 
        @Gender
"
type UpdateEmplInfoCommand = SqlCommandProvider<invokeSp, connectionString>
let nonQuery = new UpdateEmplInfoCommand(connectionString)
let rowsAffected = 
    nonQuery.Execute(
        BusinessEntityID = 2, NationalIDNumber = "245797967", 
        BirthDate = System.DateTime(1965, 09, 01), MaritalStatus = "S", Gender = "F") 
  • Non-query with MS SQL HierarchyId using SqlProgrammabilityProvider<...>
 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
open System
open System.Data
open Microsoft.SqlServer.Types

do 
    use cmd = new AdventureWorks2012.HumanResources.uspUpdateEmployeeLogin(connectionString)
    let hierarchyId = SqlHierarchyId.Parse(SqlTypes.SqlString("/1/4/2/"))
    cmd.Execute(
        BusinessEntityID = 291, 
        CurrentFlag = true, 
        HireDate = DateTime(2013,1,1), 
        JobTitle = "gatekeeper", 
        LoginID = "adventure-works\gat0", 
        OrganizationNode = hierarchyId
    )
    |> printfn "Records afftected: %i"

Result sequence is un-buffered by default

Although it implements standard seq<_> (IEnumerable<_>) interface it can be evaluated only once. It is done mostly for memory efficiency. It behaves as forward-only cursor similar to underlying SqlDataReader. If multiple passes over the sequence required use standard Seq.cache combinator.

1: 
2: 
3: 
4: 
type Get42 = SqlCommandProvider<"SELECT * FROM (VALUES (42), (43)) AS T(N)", connectionString>
let xs = (new Get42(connectionString)).Execute() |> Seq.cache 
printfn "#1: %i " <| Seq.nth 0 xs 
printfn "#2: %i " <| Seq.nth 1 xs //see it fails here if result is not piped into Seq.cache 

Output result types summary:

  • Records (default) .NET-style class with read-only properties. WebAPI/ASP.NET MVC/Json.NET/WPF, Data Binding
  • Tuples - convenient option for F# combined with pattern matching
  • DataTable with inferred data rows similar to Records. Update scenarios. WPF data binding
  • DataReader - for rare cases when structure of output cannot be inferred

In later case, resulting SqlDataReader can be wrapped into something like that:

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
module SqlDataReader =  
    open System.Data.SqlClient
    let toMaps (reader: SqlDataReader) = 
        seq {
            use __ = reader
            while reader.Read() do
                yield [
                    for i = 0 to reader.FieldCount - 1 do
                        if not( reader.IsDBNull(i)) 
                        then yield reader.GetName(i), reader.GetValue(i)
                ] |> Map.ofList 
        }

Note that combined with |> Map.tryFind(key) this approach can be used to achieve Option semantics for each row, in other words, such function will return None for NULL values. Keep in mind though that the incorrect column name will also return None. The same approach can be used to produce ExpandoObject for dynamic scenarios.

Multiple items
type LiteralAttribute =
  inherit Attribute
  new : unit -> LiteralAttribute

Full name: Microsoft.FSharp.Core.LiteralAttribute

--------------------
new : unit -> LiteralAttribute
val productsSql : string

Full name: Output.productsSql
type QueryProductAsRecords = obj

Full name: Output.QueryProductAsRecords
type SqlCommandProvider

Full name: FSharp.Data.SqlCommandProvider



<summary>Typed representation of a T-SQL statement to execute against a SQL Server database.</summary>
<param name='CommandText'>Transact-SQL statement to execute at the data source.</param>
<param name='ConnectionStringOrName'>String used to open a SQL Server database or the name of the connection string in the configuration file in the form of “name=&lt;connection string name&gt;”.</param>
<param name='ResultType'>A value that defines structure of result: Records, Tuples, DataTable, or SqlDataReader.</param>
<param name='SingleRow'>If set the query is expected to return a single row of the result set. See MSDN documentation for details on CommandBehavior.SingleRow.</param>
<param name='ConfigFile'>The name of the configuration file that’s used for connection strings at DESIGN-TIME. The default value is app.config or web.config.</param>
<param name='AllParametersOptional'>If set all parameters become optional. NULL input values must be handled inside T-SQL.</param>
<param name='ResolutionFolder'>A folder to be used to resolve relative file paths to *.sql script files at compile time. The default value is the folder that contains the project or script.</param>
<param name='DataDirectory'>The name of the data directory that replaces |DataDirectory| in connection strings. The default value is the project or script directory.</param>
val connectionString : string

Full name: Output.connectionString
val queryProductAsRecords : QueryProductAsRecords

Full name: Output.queryProductAsRecords
val records : obj list

Full name: Output.records
namespace System
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end

Full name: System.DateTime

--------------------
System.DateTime()
   (+0 other overloads)
System.DateTime(ticks: int64) : unit
   (+0 other overloads)
System.DateTime(ticks: int64, kind: System.DateTimeKind) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, calendar: System.Globalization.Calendar) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: System.DateTimeKind) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: System.Globalization.Calendar) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
   (+0 other overloads)
System.DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: System.DateTimeKind) : unit
   (+0 other overloads)
System.DateTime.Parse(s: string) : System.DateTime
System.DateTime.Parse(s: string, provider: System.IFormatProvider) : System.DateTime
System.DateTime.Parse(s: string, provider: System.IFormatProvider, styles: System.Globalization.DateTimeStyles) : System.DateTime
Multiple items
type Async
static member AsBeginEnd : computation:('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit)
static member AwaitEvent : event:IEvent<'Del,'T> * ?cancelAction:(unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate)
static member AwaitIAsyncResult : iar:IAsyncResult * ?millisecondsTimeout:int -> Async<bool>
static member AwaitTask : task:Task<'T> -> Async<'T>
static member AwaitWaitHandle : waitHandle:WaitHandle * ?millisecondsTimeout:int -> Async<bool>
static member CancelDefaultToken : unit -> unit
static member Catch : computation:Async<'T> -> Async<Choice<'T,exn>>
static member FromBeginEnd : beginAction:(AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg:'Arg1 * beginAction:('Arg1 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * beginAction:('Arg1 * 'Arg2 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromBeginEnd : arg1:'Arg1 * arg2:'Arg2 * arg3:'Arg3 * beginAction:('Arg1 * 'Arg2 * 'Arg3 * AsyncCallback * obj -> IAsyncResult) * endAction:(IAsyncResult -> 'T) * ?cancelAction:(unit -> unit) -> Async<'T>
static member FromContinuations : callback:(('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T>
static member Ignore : computation:Async<'T> -> Async<unit>
static member OnCancel : interruption:(unit -> unit) -> Async<IDisposable>
static member Parallel : computations:seq<Async<'T>> -> Async<'T []>
static member RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:CancellationToken -> 'T
static member Sleep : millisecondsDueTime:int -> Async<unit>
static member Start : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions * ?cancellationToken:CancellationToken -> Task<'T>
static member StartChild : computation:Async<'T> * ?millisecondsTimeout:int -> Async<Async<'T>>
static member StartChildAsTask : computation:Async<'T> * ?taskCreationOptions:TaskCreationOptions -> Async<Task<'T>>
static member StartImmediate : computation:Async<unit> * ?cancellationToken:CancellationToken -> unit
static member StartWithContinuations : computation:Async<'T> * continuation:('T -> unit) * exceptionContinuation:(exn -> unit) * cancellationContinuation:(OperationCanceledException -> unit) * ?cancellationToken:CancellationToken -> unit
static member SwitchToContext : syncContext:SynchronizationContext -> Async<unit>
static member SwitchToNewThread : unit -> Async<unit>
static member SwitchToThreadPool : unit -> Async<unit>
static member TryCancelled : computation:Async<'T> * compensation:(OperationCanceledException -> unit) -> Async<'T>
static member CancellationToken : Async<CancellationToken>
static member DefaultCancellationToken : CancellationToken

Full name: Microsoft.FSharp.Control.Async

--------------------
type Async<'T>

Full name: Microsoft.FSharp.Control.Async<_>
static member Async.RunSynchronously : computation:Async<'T> * ?timeout:int * ?cancellationToken:System.Threading.CancellationToken -> 'T
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val ofSeq : source:seq<'T> -> 'T list

Full name: Microsoft.FSharp.Collections.List.ofSeq
module Seq

from Microsoft.FSharp.Collections
val iter : action:('T -> unit) -> source:seq<'T> -> unit

Full name: Microsoft.FSharp.Collections.Seq.iter
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
type QueryProductSync = obj

Full name: Output.QueryProductSync
type ResultType =
  | Records = 0
  | Tuples = 1
  | DataTable = 2
  | DataReader = 3

Full name: FSharp.Data.ResultType
ResultType.Tuples: ResultType = 1
val cmd : QueryProductSync
val tuples : 'a (requires 'a :> seq<string * 'b * 'c>)
val productName : string
val sellStartDate : 'a
val size : 'a
val cmd : System.IDisposable
ResultType.DataTable: ResultType = 2
val table : obj
val row : obj
type QueryPersonInfoSingletoneAsRecords = obj

Full name: Output.QueryPersonInfoSingletoneAsRecords
val singleton : QueryPersonInfoSingletoneAsRecords

Full name: Output.singleton
val person : obj

Full name: Output.person
module Option

from Microsoft.FSharp.Core
val get : option:'T option -> 'T

Full name: Microsoft.FSharp.Core.Option.get
union case Option.Some: Value: 'T -> Option<'T>
val first : string
val last : string
val queryPersonInfoSingletoneQuery : string

Full name: Output.queryPersonInfoSingletoneQuery
type QueryPersonInfoSingletoneTuples = obj

Full name: Output.QueryPersonInfoSingletoneTuples
val id : obj
type QueryPersonInfoSingletoneDataTable = obj

Full name: Output.QueryPersonInfoSingletoneDataTable
val cmd : QueryPersonInfoSingletoneDataTable
val table : 'a
val row : 'a
val table2 : obj

Full name: Output.table2
type AdventureWorks2012 = obj

Full name: Output.AdventureWorks2012
type SqlProgrammabilityProvider

Full name: FSharp.Data.SqlProgrammabilityProvider



<summary>Typed access to SQL Server programmable objects: stored procedures, functions and user defined table types.</summary>
<param name='ConnectionStringOrName'>String used to open a SQL Server database or the name of the connection string in the configuration file in the form of “name=&lt;connection string name&gt;”.</param>
<param name='ResultType'>A value that defines structure of result: Records, Tuples, DataTable, or SqlDataReader.</param>
<param name='ConfigFile'>The name of the configuration file that’s used for connection strings at DESIGN-TIME. The default value is app.config or web.config.</param>
<param name='DataDirectory'>The name of the data directory that replaces |DataDirectory| in connection strings. The default value is the project or script directory.</param>
val iter : action:('T -> unit) -> option:'T option -> unit

Full name: Microsoft.FSharp.Core.Option.iter
val x : obj
type QueryPersonInfoSingleValue = obj

Full name: Output.QueryPersonInfoSingleValue
val personId : int
val cmd : QueryPersonInfoSingleValue
val name : 'a
val printf : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printf
type GetServerTime = obj

Full name: Output.GetServerTime
val getSrvTime : GetServerTime

Full name: Output.getSrvTime
val invokeSp : string

Full name: Output.invokeSp
type UpdateEmplInfoCommand = obj

Full name: Output.UpdateEmplInfoCommand
val nonQuery : UpdateEmplInfoCommand

Full name: Output.nonQuery
val rowsAffected : obj

Full name: Output.rowsAffected
namespace System.Data
namespace Microsoft
namespace Microsoft.SqlServer
namespace Microsoft.SqlServer.Types
val cmd : IDisposable
val hierarchyId : SqlHierarchyId
type SqlHierarchyId =
  struct
    member CompareTo : obj:obj -> int + 1 overload
    member Equals : obj:obj -> bool
    member GetAncestor : n:int -> SqlHierarchyId
    member GetDescendant : child1:SqlHierarchyId * child2:SqlHierarchyId -> SqlHierarchyId
    member GetHashCode : unit -> int
    member GetLevel : unit -> SqlInt16
    member GetReparentedValue : oldRoot:SqlHierarchyId * newRoot:SqlHierarchyId -> SqlHierarchyId
    member IsDescendantOf : parent:SqlHierarchyId -> SqlBoolean
    member IsNull : bool
    member Read : r:BinaryReader -> unit
    ...
  end

Full name: Microsoft.SqlServer.Types.SqlHierarchyId
SqlHierarchyId.Parse(input: SqlTypes.SqlString) : SqlHierarchyId
namespace System.Data.SqlTypes
Multiple items
type SqlString =
  struct
    new : data:string -> SqlString + 6 overloads
    member Clone : unit -> SqlString
    member CompareInfo : CompareInfo
    member CompareTo : value:obj -> int + 1 overload
    member CultureInfo : CultureInfo
    member Equals : value:obj -> bool
    member GetHashCode : unit -> int
    member GetNonUnicodeBytes : unit -> byte[]
    member GetUnicodeBytes : unit -> byte[]
    member IsNull : bool
    ...
  end

Full name: System.Data.SqlTypes.SqlString

--------------------
SqlTypes.SqlString()
SqlTypes.SqlString(data: string) : unit
SqlTypes.SqlString(data: string, lcid: int) : unit
SqlTypes.SqlString(lcid: int, compareOptions: SqlTypes.SqlCompareOptions, data: byte []) : unit
SqlTypes.SqlString(data: string, lcid: int, compareOptions: SqlTypes.SqlCompareOptions) : unit
SqlTypes.SqlString(lcid: int, compareOptions: SqlTypes.SqlCompareOptions, data: byte [], fUnicode: bool) : unit
SqlTypes.SqlString(lcid: int, compareOptions: SqlTypes.SqlCompareOptions, data: byte [], index: int, count: int) : unit
SqlTypes.SqlString(lcid: int, compareOptions: SqlTypes.SqlCompareOptions, data: byte [], index: int, count: int, fUnicode: bool) : unit
Multiple items
type DateTime =
  struct
    new : ticks:int64 -> DateTime + 10 overloads
    member Add : value:TimeSpan -> DateTime
    member AddDays : value:float -> DateTime
    member AddHours : value:float -> DateTime
    member AddMilliseconds : value:float -> DateTime
    member AddMinutes : value:float -> DateTime
    member AddMonths : months:int -> DateTime
    member AddSeconds : value:float -> DateTime
    member AddTicks : value:int64 -> DateTime
    member AddYears : value:int -> DateTime
    ...
  end

Full name: System.DateTime

--------------------
DateTime()
   (+0 other overloads)
DateTime(ticks: int64) : unit
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int) : unit
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, kind: DateTimeKind) : unit
   (+0 other overloads)
type Get42 = obj

Full name: Output.Get42
val xs : seq<int>

Full name: Output.xs
val cache : source:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.cache
val nth : index:int -> source:seq<'T> -> 'T

Full name: Microsoft.FSharp.Collections.Seq.nth
module SqlDataReader

from Output
namespace System.Data.SqlClient
val toMaps : reader:SqlDataReader -> seq<Map<string,obj>>

Full name: Output.SqlDataReader.toMaps
val reader : SqlDataReader
type SqlDataReader =
  inherit DbDataReader
  member Close : unit -> unit
  member Depth : int
  member FieldCount : int
  member GetBoolean : i:int -> bool
  member GetByte : i:int -> byte
  member GetBytes : i:int * dataIndex:int64 * buffer:byte[] * bufferIndex:int * length:int -> int64
  member GetChar : i:int -> char
  member GetChars : i:int * dataIndex:int64 * buffer:char[] * bufferIndex:int * length:int -> int64
  member GetDataTypeName : i:int -> string
  member GetDateTime : i:int -> DateTime
  ...

Full name: System.Data.SqlClient.SqlDataReader
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val __ : SqlDataReader
SqlDataReader.Read() : bool
val i : int
property SqlDataReader.FieldCount: int
val not : value:bool -> bool

Full name: Microsoft.FSharp.Core.Operators.not
SqlDataReader.IsDBNull(i: int) : bool
SqlDataReader.GetName(i: int) : string
SqlDataReader.GetValue(i: int) : obj
Multiple items
module Map

from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> =
  interface IEnumerable
  interface IComparable
  interface IEnumerable<KeyValuePair<'Key,'Value>>
  interface ICollection<KeyValuePair<'Key,'Value>>
  interface IDictionary<'Key,'Value>
  new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
  member Add : key:'Key * value:'Value -> Map<'Key,'Value>
  member ContainsKey : key:'Key -> bool
  override Equals : obj -> bool
  member Remove : key:'Key -> Map<'Key,'Value>
  ...

Full name: Microsoft.FSharp.Collections.Map<_,_>

--------------------
new : elements:seq<'Key * 'Value> -> Map<'Key,'Value>
val ofList : elements:('Key * 'T) list -> Map<'Key,'T> (requires comparison)

Full name: Microsoft.FSharp.Collections.Map.ofList
Fork me on GitHub