SQLProvider

Adding a Mapper using dataContext to use generated types from the DB

Typically, F# is about writing business logic and not about OR-mapping. Consider using your database types as is. And select only the columns you need, not full entities. But sometimes you want to map objects to different ones, for example to interact with other languages like C# domain.

First, add a Domain Model

open System

type Employee = {
    EmployeeId : int64
    FirstName : string
    LastName : string
    HireDate : DateTime
}

Then you can create the mapper using dataContext to use the generated types from the DB

let mapEmployee (dbRecord:sql.dataContext.``main.EmployeesEntity``) : Employee =
    { EmployeeId = dbRecord.EmployeeId
      FirstName = dbRecord.FirstName
      LastName = dbRecord.LastName
      HireDate = dbRecord.HireDate }

This could be useful if you e.g. want to use SQLProvider objects in some reflection based code-generator (because the normal objects are erased).

MapTo

SqlProvider also has a .MapTo<'T> convenience method:

let ctx = sql.GetDataContext()

let orders = ctx.Main.Orders
let employees = ctx.Main.Employees

type Employee2 = {
    FirstName:string
    LastName:string
    }

let qry = query { for row in employees do
                  select row} |> Seq.map (fun x -> x.MapTo<Employee2>())

The target type can be a record (as in the example) or a class type with properties named as the source columns and with a parameterless setter.

Target will support mapping database nullable fields to Option and ValueOption types automatically.

The target field name can also be different than the column name; in this case, it must be decorated with the MappedColumnAttribute custom attribute:

open FSharp.Data.Sql.Common

type Employee3 = {
    [<MappedColumn("FirstName")>] GivenName:string
    [<MappedColumn("LastName")>] FamilyName:string
    }

let qry2 =
          query {
                for row in employees do
                select row} |> Seq.map (fun x -> x.MapTo<Employee3>())

TemplateAsRecord

If you want to use SQLProvider as code-generator and copy and paste the tables as separate classes (not recommended!), you can use TemplateAsRecord under your database table type which is located under dataContext types:

sql.dataContext.DesignTimeCommands.TemplateAsRecord.``main.OrdersTemplate``

// intellisense will generate you code that you can copy and paste as template to create your own type:
// ``type MainOrders = { CustomerId : String voption; EmployeeId : Int64 voption; Freight : Decimal voption; OrderDate : DateTime voption; OrderId : Int64; RequiredDate : DateTime voption; ShipAddress : String voption; ShipCity : String voption; ShipCountry : String voption; ShipName : String voption; ShipPostalCode : String voption; ShipRegion : String voption; ShippedDate : DateTime voption }``

The main reason to do this would be to create some reflection schema or MapTo object templates without manual typing.

ColumnValues

Or alternatively, the ColumnValues from SQLEntity can be used to create a map, with the column as a key:

let rows =
        query {
            for row in employees do
            select row} |> Seq.toArray

let employees2map = rows |> Seq.map(fun i -> i.ColumnValues |> Map.ofSeq)
let firstNames = employees2map |> Seq.map (fun x -> x.["FirstName"])
Multiple items
type LiteralAttribute = inherit Attribute new: unit -> LiteralAttribute

--------------------
new: unit -> LiteralAttribute
[<Literal>] val resolutionPath: string = "C:\git\SQLProvider\docs\content\core/../../files/sqlite"
[<Literal>] val connectionString: string = "Data Source=C:\git\SQLProvider\docs\content\core\..\northwindEF.db;Version=3;Read Only=false;FailIfMissing=True;"
Multiple items
namespace FSharp

--------------------
namespace Microsoft.FSharp
Multiple items
namespace FSharp.Data

--------------------
namespace Microsoft.FSharp.Data
namespace FSharp.Data.Sql
type sql = obj
namespace FSharp.Data.Sql.Common
[<Struct>] type DatabaseProviderTypes = | MSSQLSERVER = 0 | SQLITE = 1 | POSTGRESQL = 2 | MYSQL = 3 | ORACLE = 4 | MSACCESS = 5 | ODBC = 6 | FIREBIRD = 7 | MSSQLSERVER_DYNAMIC = 8 | MSSQLSERVER_SSDT = 9 | DUCKDB = 10 | EXTERNAL = 11
<summary> Specifies the database provider type for the SQL type provider. Each provider has its own specific implementation for SQL generation and data type mapping. </summary>
Common.DatabaseProviderTypes.SQLITE: Common.DatabaseProviderTypes = 1
<summary> SQLite database using System.Data.SQLite or Microsoft.Data.Sqlite </summary>
[<Struct>] type SQLiteLibrary = | SystemDataSQLite = 0 | MonoDataSQLite = 1 | AutoSelect = 2 | MicrosoftDataSqlite = 3
<summary> Specifies which SQLite library to use for connections. Different libraries may have different capabilities and platform support. </summary>
Common.SQLiteLibrary.SystemDataSQLite: Common.SQLiteLibrary = 0
<summary> .NET Framework default </summary>
[<Struct>] type CaseSensitivityChange = | ORIGINAL = 0 | TOUPPER = 1 | TOLOWER = 2
<summary> Specifies how to handle case sensitivity when generating table and column names. </summary>
Common.CaseSensitivityChange.ORIGINAL: Common.CaseSensitivityChange = 0
<summary> Keep original casing from the database </summary>
namespace System
type Employee = { EmployeeId: int64 FirstName: string LastName: string HireDate: DateTime }
Multiple items
val int64: value: 'T -> int64 (requires member op_Explicit)

--------------------
type int64 = Int64

--------------------
type int64<'Measure> = int64
Multiple items
val string: value: 'T -> string

--------------------
type string = String
Multiple items
[<Struct>] type DateTime = new: date: DateOnly * time: TimeOnly -> unit + 16 overloads member Add: value: TimeSpan -> DateTime member AddDays: value: float -> DateTime member AddHours: value: float -> DateTime member AddMicroseconds: 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 ...
<summary>Represents an instant in time, typically expressed as a date and time of day.</summary>

--------------------
DateTime ()
   (+0 other overloads)
DateTime(ticks: int64) : DateTime
   (+0 other overloads)
DateTime(date: DateOnly, time: TimeOnly) : DateTime
   (+0 other overloads)
DateTime(ticks: int64, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(date: DateOnly, time: TimeOnly, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, calendar: Globalization.Calendar) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, kind: DateTimeKind) : DateTime
   (+0 other overloads)
DateTime(year: int, month: int, day: int, hour: int, minute: int, second: int, calendar: Globalization.Calendar) : DateTime
   (+0 other overloads)
val mapEmployee: dbRecord: Employee -> Employee
val dbRecord: Employee
Employee.EmployeeId: int64
Employee.FirstName: string
Employee.LastName: string
Employee.HireDate: DateTime
val ctx: obj
val orders: obj
val employees: Linq.IQueryable<obj>
type Employee2 = { FirstName: string LastName: string }
val qry: obj seq
val query: Linq.QueryBuilder
val row: obj
custom operation: select ('Result) Calls Linq.QueryBuilder.Select
Multiple items
module Seq from FSharp.Data.Sql

--------------------
module Seq from Microsoft.FSharp.Collections
val map: mapping: ('T -> 'U) -> source: 'T seq -> 'U seq
val x: obj
type Employee3 = { GivenName: string FamilyName: string }
Multiple items
type MappedColumnAttribute = inherit Attribute new: name: string -> MappedColumnAttribute member Name: string
<summary> Attribute for mapping entity properties to database columns with different names. Use this when your database column name differs from your preferred F# property name. </summary>

--------------------
new: name: string -> MappedColumnAttribute
val qry2: obj seq
val rows: obj array
val toArray: source: 'T seq -> 'T array
val employees2map: Map<string,obj> seq
val i: obj
Multiple items
module Map from Microsoft.FSharp.Collections

--------------------
type Map<'Key,'Value (requires comparison)> = interface IReadOnlyDictionary<'Key,'Value> interface IReadOnlyCollection<KeyValuePair<'Key,'Value>> interface IEnumerable interface IStructuralEquatable interface IComparable interface IEnumerable<KeyValuePair<'Key,'Value>> interface ICollection<KeyValuePair<'Key,'Value>> interface IDictionary<'Key,'Value> new: elements: ('Key * 'Value) seq -> Map<'Key,'Value> member Add: key: 'Key * value: 'Value -> Map<'Key,'Value> ...

--------------------
new: elements: ('Key * 'Value) seq -> Map<'Key,'Value>
val ofSeq: elements: ('Key * 'T) seq -> Map<'Key,'T> (requires comparison)
val firstNames: obj seq
val x: Map<string,obj>

Type something to start searching.