Donald 10.1.0
dotnet add package Donald --version 10.1.0
NuGet\Install-Package Donald -Version 10.1.0
<PackageReference Include="Donald" Version="10.1.0" />
paket add Donald --version 10.1.0
#r "nuget: Donald, 10.1.0"
// 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
认识 Donald (Chamberlin)。
如果你是一名程序员并且使用过数据库,他已经在很大程度上影响了你的生活。
这个库就是以他命名的。
主要功能
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 的示例
对于此示例,假设我们有一个名为 conn
的 IDbConnection
提醒: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>
在显式事务中执行语句
这可以通过两种方式实现
- 使用
Db.batch
或Db.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)
- 使用扩展方法:
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获取值更加简单,提供了两套扩展方法:
- 获取值,自动默认
- 获取值作为
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 已计算。 |
-
net6.0
- FSharp.Core (>= 6.0.0)
-
net7.0
- FSharp.Core (>= 6.0.0)
-
net8.0
- FSharp.Core (>= 6.0.0)
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 |