Donald 10.1.0

dotnet add package Donald --version 10.1.0                
NuGet\Install-Package Donald -Version 10.1.0                
此命令旨在在 Visual Studio 的包管理器控制台中使用,因为它使用了 NuGet 模块的版本 Install-Package
<PackageReference Include="Donald" Version="10.1.0" />                
对于支持 PackageReference 的项目,将此 XML 节点复制到项目文件以引用该包。
paket add Donald --version 10.1.0                
#r "nuget: Donald, 10.1.0"                
#r 指令可以在 F# Interactive 和 Polyglot Notebooks 中使用。将此内容复制到交互式工具或脚本的源代码中,以引用该包。
// Install Donald as a Cake Addin
#addin nuget:?package=Donald&version=10.1.0

// Install Donald as a Cake Tool
#tool nuget:?package=Donald&version=10.1.0                

Donald

NuGet Version build

认识 Donald (Chamberlin)。

如果你是一名程序员并且使用过数据库,他已经在很大程度上影响了你的生活。

这个库就是以他命名的。

特别感谢 @dsyme 另一位重要的 Donald,以及 F#'s BDFL

主要功能

Donald 是一个通用的库,旨在让使用 ADO.NET 更安全、更简洁。它是一个完全通用的抽象,将与所有 ADO.NET 实现一起工作。

设计目标

  • 支持所有 ADO 实现
  • 提供简洁、类型安全的 API 与数据库交互
  • 启用异步工作流
  • 简化对象映射
  • 改进数据访问性能
  • 在出现异常时提供额外的上下文

入门指南

安装 Donald NuGet 包

PM>  Install-Package Donald

或者使用 dotnet CLI

dotnet add package Donald

快速入门

open Donald

type Author =
    { FullName : string }

let authors (conn : IDbConnection) : Author list =
    conn
    |> Db.newCommand "
        SELECT  full_name
        FROM    author
        WHERE   author_id = @author_id"
    |> Db.setParams [
        "author_id", SqlType.Int32 1 ]
    |> Db.query (fun rd ->
        { FullName = rd.ReadString "full_name" })

使用 SQLite 的示例

对于此示例,假设我们有一个名为 connIDbConnection

提醒:Donald 侧重于与 任何 ADO 实现一起工作(SQL Server、SQLite、MySQL、Postgresql 等)。

考虑以下模型

type Author =
    { AuthorId : int
      FullName : string }

module Author -
    let ofDataReader (rd : IDataReader) : Author =
        { AuthorId = rd.ReadInt32 "author_id"
          FullName = rd.ReadString "full_name" }

查询多个强类型结果

重要:默认情况下,Donald将使用CommandBehavior.SequentialAccess。更多信息,请参阅性能

conn
|> Db.newCommand "SELECT author_id, full_name FROM author"
|> Db.query Author.ofDataReader // Author list

// Async
conn
|> Db.newCommand "SELECT author_id, full_name FROM author"
|> Db.Async.query Author.ofDataReader // Task<Author list>

查询单个强类型结果

conn
|> Db.newCommand "SELECT author_id, full_name FROM author"
|> Db.setParams [ "author_id", SqlType.Int32 1 ]
|> Db.querySingle Author.ofDataReader // Author option

// Async
conn
|> Db.newCommand "SELECT author_id, full_name FROM author"
|> Db.setParams [ "author_id", SqlType.Int32 1 ]
|> Db.Async.querySingle Author.ofDataReader // Task<Author option>

执行一个语句

conn
|> Db.newCommand "INSERT INTO author (full_name)"
|> Db.setParams [ "full_name", SqlType.String "John Doe" ]
|> Db.exec // unit

// Async
conn
|> Db.newCommand "INSERT INTO author (full_name)"
|> Db.setParams [ "full_name", SqlType.String "John Doe" ]
|> Db.Async.exec // Task<unit>

执行一个语句多次

conn
|> Db.newCommand "INSERT INTO author (full_name)"
|> Db.execMany [
    "full_name", SqlType.String "John Doe"
    "full_name", SqlType.String "Jane Doe" ] // unit

// Async
conn
|> Db.newCommand "INSERT INTO author (full_name)"
|> Db.Async.execMany [
    "full_name", SqlType.String "John Doe"
    "full_name", SqlType.String "Jane Doe" ] //Task<unit>

在显式事务中执行语句

这可以通过两种方式实现

  1. 使用Db.batchDb.Async.batch,这些方法以全有或全无的方式处理操作。
conn
|> Db.batch (fun tran ->
    for fullName in [ "John Doe"; "Jane Doe" ] do
        tran
        |> Db.newCommandForTransaction "INSERT INTO author (full_name) VALUES (@full_name)"
        |> Db.setParams ["full_name", SqlType.String fullName ]
        |> Db.exec)
  1. 使用扩展方法:TryBeginTransaction()TryCommit()TryRollback()
// Safely begin transaction or throw CouldNotBeginTransactionError on failure
use tran = conn.TryBeginTransaction()

for fullName in [ "John Doe"; "Jane Doe" ] do
    tran
    |> Db.newCommandForTransaction "INSERT INTO author (full_name) VALUES (@full_name)"
    |> Db.setParams ["full_name", SqlType.String fullName ]
    |> Db.exec

// Attempt to commit, will rollback automatically on failure, or throw DbTransactionException
tran.TryCommit ()

// Will rollback or throw DbTransactionException
// tran.TryRollback ()

命令参数

命令参数由SqlType表示,其中包含了所有相关类型的实例。

type SqlType =
    | Null
    | String     of string
    | AnsiString of string
    | Boolean    of bool
    | Byte       of byte
    | Char       of char
    | AnsiChar   of char
    | Decimal    of decimal
    | Double     of double
    | Float      of float
    | Guid       of Guid
    | Int16      of int16
    | Int32      of int32
    | Int        of int32
    | Int64      of int64
    | DateTime   of DateTime
    | Bytes      of byte[]

let p1 : SqlType = SqlType.Null
let p2 : SqlType = SqlType.Int32 1

还提供了一些辅助方法,这些方法会隐式调用相应的F#转换函数。这对于在程序中处理值类型特别有用。

let p1 : SqlType = sqlInt32 "1" // equivalent to SqlType.Int32 (int "1")

读取值

为了使从reader获取值更加简单,提供了两套扩展方法:

  1. 获取值,自动默认
  2. 获取值作为option<'a>

假设我们有一个名为rd的活动的IDataReader,并且目前正在读取一行,下面这些扩展方法可以简化值的读取:

rd.ReadString "some_field"         // string -> string
rd.ReadBoolean "some_field"        // string -> bool
rd.ReadByte "some_field"           // string -> byte
rd.ReadChar "some_field"           // string -> char
rd.ReadDateTime "some_field"       // string -> DateTime
rd.ReadDecimal "some_field"        // string -> Decimal
rd.ReadDouble "some_field"         // string -> Double
rd.ReadFloat "some_field"          // string -> float32
rd.ReadGuid "some_field"           // string -> Guid
rd.ReadInt16 "some_field"          // string -> int16
rd.ReadInt32 "some_field"          // string -> int32
rd.ReadInt64 "some_field"          // string -> int64
rd.ReadBytes "some_field"          // string -> byte[]

rd.ReadStringOption "some_field"   // string -> string option
rd.ReadBooleanOption "some_field"  // string -> bool option
rd.ReadByteOption "some_field"     // string -> byte option
rd.ReadCharOption "some_field"     // string -> char option
rd.ReadDateTimeOption "some_field" // string -> DateTime option
rd.ReadDecimalOption "some_field"  // string -> Decimal option
rd.ReadDoubleOption "some_field"   // string -> Double option
rd.ReadFloatOption "some_field"    // string -> float32 option
rd.ReadGuidOption "some_field"     // string -> Guid option
rd.ReadInt16Option "some_field"    // string -> int16 option
rd.ReadInt32Option "some_field"    // string -> int32 option
rd.ReadInt64Option "some_field"    // string -> int64 option
rd.ReadBytesOption "some_field"    // string -> byte[] option

如果你需要一个显式的Nullable<'a>,可以使用Option.asNullable

异常

存在一些自定义异常,它们在ADO.NET抛出的异常中混合了上下文相关的元数据。

/// Details of failure to connection to a database/server.
type DbConnectionException =
    inherit Exception
    val ConnectionString : string option

/// Details of failure to execute database command or transaction.
type DbExecutionException =
    inherit Exception
    val Statement : string option
    val Step : DbTransactionStep option

/// Details of failure to access and/or cast an IDataRecord field.
type DbReaderException =
    inherit Exception
    val FieldName : string option

/// Details of failure to commit or rollback an IDbTransaction
type DbTransactionException =
    inherit Exception
    val Step : DbTransactionStep

性能

默认情况下,IDataReader使用CommandBehavior.SequentialAccess进行消费。这允许按块(即流式传输)读取行和列,但是只能向前读取。与一次性完全加载到内存中,并可从任何方向读取的方式相比,这种方法尤其适用于阅读大型CLOB(字符串)和BLOB(二进制)数据。也适用于标准查询结果,并且可以在性能上感受到显著的提升。

唯一需要注意的顺序访问的细微差别是,列必须按照在SELECT子句中发现相同的顺序读取。除了这一点外,对于库用户而言,没有明显差异。

配置CommandBehavior可以通过以下两种方式完成

let sql = "SELECT author_id, full_name FROM author"

conn
|> Db.newCommand sql
|> Db.setCommandBehavior CommandBehavior.Default
|> Db.query Author.ofDataReader

发现错误?

有关这个[问题](https://github.com/pimbrouwers/Donald/issues)。

许可证

Pim Brouwers在多伦多,安大略省用♥构建。许可协议为Apache License 2.0

产品 兼容和额外的计算目标框架版本。
.NET net6.0 兼容。 net6.0-android 已计算。 net6.0-ios 已计算。 net6.0-maccatalyst 已计算。 net6.0-macos 已计算。 net6.0-tvos 已计算。 net6.0-windows 已计算。 net7.0 兼容。 net7.0-android 已计算。 net7.0-ios 已计算。 net7.0-maccatalyst 已计算。 net7.0-macos 已计算。 net7.0-tvos 已计算。 net7.0-windows 已计算。 net8.0 兼容。 net8.0-android 已计算。 net8.0-browser 已计算。 net8.0-ios 已计算。 net8.0-maccatalyst 已计算。 net8.0-macos 已计算。 net8.0-tvos 已计算。 net8.0-windows 已计算。
兼容的目标框架
包含的目标框架(在包中)
了解有关 目标框架.NET Standard 的更多信息。

NuGet 包

此包未由任何 NuGet 包使用。

GitHub 仓库

此包未由任何流行的 GitHub 仓库使用。

版本 下载 上次更新
10.1.0 665 3/20/2024
10.0.2 1,015 12/12/2023
10.0.1 928 7/11/2023
10.0.0 136 7/8/2023
10.0.0-alpha3 154 2/11/2023
10.0.0-alpha2 138 2/4/2023
10.0.0-alpha1 126 2/3/2023
9.0.1 1,318 1/11/2023
9.0.0 287 12/23/2022
8.0.2 12,366 11/23/2022
8.0.1 303 11/23/2022
8.0.0 359 11/23/2022
7.1.0 2,676 12/17/2021
7.0.0 310 12/14/2021
7.0.0-alpha1 251 11/1/2021
6.2.5 609 8/4/2021
6.2.4 356 8/4/2021
6.2.3 366 7/30/2021
6.2.2 438 7/27/2021
6.2.1 329 7/27/2021
6.2.0 553 7/26/2021
6.1.0 445 7/6/2021
6.1.0-beta3 210 7/5/2021
6.1.0-beta2 224 7/4/2021
6.1.0-beta1 324 7/4/2021
6.0.0 404 4/11/2021
5.1.3 397 3/29/2021
5.1.2 423 2/27/2021
5.1.1 439 1/23/2021
5.0.1 1,017 12/3/2020
5.0.0 410 12/1/2020
5.0.0-alpha3 265 12/1/2020
5.0.0-alpha2 261 11/30/2020
5.0.0-alpha1 247 11/30/2020
4.0.0 462 11/12/2020
3.0.4 1,641 10/31/2020
3.0.3 722 8/2/2020
3.0.2 505 7/17/2020
3.0.1 484 7/14/2020
3.0.0 522 6/29/2020
2.0.2 466 5/1/2020
2.0.1 447 4/27/2020
2.0.0 434 4/27/2020
1.0.6 417 4/24/2020
1.0.4 415 4/24/2020
1.0.3 426 4/24/2020
1.0.2 430 4/24/2020
1.0.1 631 4/18/2020
1.0.0 471 4/5/2020