ZetCode

C# Dapper

上次修改时间:2023 年 7 月 23 日

在本文中,我们将展示如何使用 Dapper 在 C# 中进行数据库编程。在示例中,我们使用 PostgreSQL。

Dapper

Dapper 是一个适用于 .NET 平台的简单对象映射器。它是一个将面向对象域模型映射到传统关系数据库的框架。

Dapper 的目标是代码简洁性和性能。

Dapper 没有特定于数据库的实现细节,它可以跨所有 .NET ADO 提供程序工作,包括 SQLite、SQL CE、Firebird、Oracle、MySQL、PostgreSQL 和 SQL Server。Dapper 由 Stack Overflow 团队创建。

$ dotnet add package Dapper

要使用 Dapper,我们使用 dotnet 工具将包引用添加到项目中。

$ dotnet add package Npgsql

我们还包括 PostgreSQL 的驱动程序。

cars_postgre.sql
CREATE TABLE cars(id serial PRIMARY KEY, name VARCHAR(255), price INT);
INSERT INTO cars(name, price) VALUES('Audi', 52642);
INSERT INTO cars(name, price) VALUES('Mercedes', 57127);
INSERT INTO cars(name, price) VALUES('Skoda', 9000);
INSERT INTO cars(name, price) VALUES('Volvo', 29000);
INSERT INTO cars(name, price) VALUES('Bentley', 350000);
INSERT INTO cars(name, price) VALUES('Citroen', 21000);
INSERT INTO cars(name, price) VALUES('Hummer', 41400);
INSERT INTO cars(name, price) VALUES('Volkswagen', 21600);

在我们的示例中,我们使用这个表。

C# Dapper ExecuteScalar

ExecuteScalar 方法执行一个查询,该查询选择单个值。

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

var ver = con.ExecuteScalar<string>("SELECT version()");
Console.WriteLine(ver);

该示例检索 PostgreSQL 数据库的版本。

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

我们提供 PostgreSQL 数据库的连接字符串。

using var con = new NpgsqlConnection(cs);

我们创建一个新的 NpgsqlConnection

con.Open();

Open 方法打开与数据库的新连接。

var version = con.ExecuteScalar<string>("SELECT version()");

ExecuteScalar 方法执行 SELECT version() 查询,该查询返回单个值:PostgreSQL 的版本。

$ dotnet run
PostgreSQL 11.1, compiled by Visual C++ build 1914, 64-bit

C# Dapper Query

Query 方法执行查询并将其映射到动态对象列表。

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

var cars = con.Query<Car>("SELECT * FROM cars").ToList();
cars.ForEach(car => Console.WriteLine(car));

record Car(int Id, string Name, int Price);

该示例检索 cars 表中的所有行。

var cars = con.Query<Car>("SELECT * FROM cars").ToList();

Query 方法执行 SELECT * FROM cars 语句并返回一个对象列表。

cars.ForEach(car => Console.WriteLine(car));

我们遍历列表并将所有元素打印到控制台。

$ dotnet run
1 Audi 52642
2 Mercedes 57127
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600

C# Dapper ExecuteReader

ExecuteReader 执行 SQL 并返回一个 IDataReader。这通常在查询结果不由 Dapper 处理时使用,例如,用于填充 DataTableDataSet

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

var reader = con.ExecuteReader("SELECT * FROM cars");

while (reader.Read())
{
    long id = reader.GetInt64(0);
    string name = reader.GetString(1);
    int price = reader.GetInt32(2);

    Console.WriteLine($"{id} {name} {price}");
}

在该示例中,我们使用 ExecuteReader 从表中检索所有行。

while (reader.Read())
{
    long id = reader.GetInt64(0);
    string name = reader.GetString(1);
    int price = reader.GetInt32(2);

    Console.WriteLine($"{id} {name} {price}");
}

在这里,Dapper 没有进行映射。我们手动处理列。

$ dotnet run
1 Audi 52642
3 Skoda 9000
4 Volvo 29000
5 Bentley 350000
6 Citroen 21000
7 Hummer 41400
8 Volkswagen 21600
2 Mercedes 52000

C# Dapper Execute

Execute 方法执行一个 SQL 语句。它用于执行 INSERT、UPDATE 和 DELETE 语句。

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

int affectedRows = con.Execute("UPDATE cars SET price = 52000 WHERE id = 1");
Console.WriteLine($"UPDATE affected rows: {affectedRows}");

该示例更新单个汽车的价格并返回受影响的行数。

int affectedRows = con.Execute("UPDATE cars SET price = 52000 WHERE id = 1");

UPDATE 语句更新汽车的价格。Execute 方法返回更新的行数。

Console.WriteLine($"UPDATE affected rows: {affectedRows}");

更新的行数将打印到终端。

$ dotnet run
UPDATE affected rows: 1

C# Dapper 参数化查询

参数化查询提高了安全性和性能。当我们编写参数化查询时,我们使用占位符而不是直接将值写入查询中。

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

var car = con.QueryFirst<Car>("SELECT * FROM cars WHERE id=@id",
    new { id = 3 });

Console.WriteLine(car);

record Car(int Id, string Name, int Price);

该示例从表中选择一个特定的行。

var car = con.QueryFirst<Car>("SELECT * FROM cars WHERE id=@id",
    new { id = 3 });

QueryFirst 返回 SQL 查询的第一个结果。@id 是一个要填充的占位符。第二个参数是填充占位符的参数。

$ dotnet run
Car { Id = 3, Name = Skoda, Price = 9000 }

下一个示例提供多个参数。

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

var cars = con.Query<Car>("SELECT * FROM cars WHERE id IN (@id1, @id2)",
    new { id1 = 1, id2 = 2 });

Console.WriteLine(string.Join("\n", cars));

record Car(int Id, string Name, int Price);

我们查询两辆汽车。我们提供了一个带有给定 ID 的匿名对象。

$ dotnet run
Car { Id = 1, Name = Audi, Price = 52642 }
Car { Id = 2, Name = Mercedes, Price = 52000 }

C# Dapper 删除行

以下示例从表中删除一行。

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

int delRows = con.Execute(@"DELETE FROM cars WHERE Id = @Id", new { Id = 1 });

if (delRows > 0)
{
    Console.WriteLine("car deleted");
}

该示例使用 Execute 方法删除一行。

C# Dapper QueryMultiple

QueryMultiple 方法执行一个返回多个结果集的命令,并依次返回每个结果集。

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

var sql = @"select * from cars where Id = @id1;
            select * from cars where Id = @id2;
            select * from cars where Id = @id3";

using var multi = con.QueryMultiple(sql, new { id1 = 1, id2 = 2, id3 = 3});

var c1 = multi.Read<Car>().Single();
var c2 = multi.Read<Car>().Single();
var c3 = multi.Read<Car>().Single();

Console.WriteLine(c1);
Console.WriteLine(c2);
Console.WriteLine(c3);

record Car(int Id, string Name, int Price);

该示例一次返回三个 SELECT 语句。

var sql = @"select * from cars where Id = @id1;
            select * from cars where Id = @id2;
            select * from cars where Id = @id3";

我们定义一个多重选择语句。每个语句都用分号分隔。

using var multi = con.QueryMultiple(sql, new { id1 = 1, id2 = 2, id3 = 3});

这些语句使用 QueryMultiple 执行。我们在 params 对象中提供 ID。

var c1 = multi.Read<Car>().Single();
var c2 = multi.Read<Car>().Single();
var c3 = multi.Read<Car>().Single();

我们使用 Read 读取 car 对象。

$ dotnet run
Car { Id = 1, Name = Audi, Price = 52642 }
Car { Id = 2, Name = Mercedes, Price = 57127 }
Car { Id = 3, Name = Skoda, Price = 9000 }

C# Dapper DynamicParameters

DynamicParameters 是一个参数包,可以传递给 Dapper 的 Query 和 Execute 方法。

Program.cs
using System.Data;
using Npgsql;
using Dapper;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

var query = "INSERT INTO cars(name, price) VALUES(@name, @price)";

var dp = new DynamicParameters();
dp.Add("@name", "Lada", DbType.AnsiString, ParameterDirection.Input, 255);
dp.Add("@price", 36600);

int res = con.Execute(query, dp);

if (res > 0)
{
    Console.WriteLine("row inserted");
}

该示例将新行插入到 cars 表中。

var dp = new DynamicParameters();
dp.Add("@name", "Lada", DbType.AnsiString, ParameterDirection.Input, 255);
dp.Add("@price", 36600);

我们动态地提供参数值及其类型。

int res = con.Execute(query, dp);

动态参数作为 Execute 方法的第二个参数传递。

C# Dapper 批量插入

我们可以使用 Execute 插入多行。

Program.cs
using Dapper;
using Npgsql;

string cs = @"User ID=postgres;Password=passwd;Host=localhost;Port=5432;Database=testdb";

using var con = new NpgsqlConnection(cs);
con.Open();

var stm = "INSERT INTO cars(name, price) VALUES(@name, @price)";

var data = new List<Car>
{
    new Car (Name: "Lada 2", Price : 63444 ),
    new Car (Name: "Toyota 2", Price : 63330 )
};

int n = con.Execute(stm, data);

Console.WriteLine($"{n} cars inserted");

record Car(string Name, int Price);

该程序将两辆汽车插入到表中。

int n = con.Execute(stm, data);

Execute 方法将语句和对象列表作为参数。

来源

Dapper Github 页面

在本文中,我们展示了如何使用 Dapper 在 C# 中进行数据库编程。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。我从 2007 年开始撰写编程文章。到目前为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。我拥有超过十年的编程教学经验。

列出所有 C# 教程