So sánh ADO.NET và Dapper trong C#

So sánh ADO.NET và Dapper trong C#

Tổng quan

Không có lựa chọn "tốt nhất" tuyệt đối, mà phụ thuộc vào bối cảnh. Đối với hầu hết các dự án kinh doanh, Dapper thường hiệu quả hơn; còn đối với các trường hợp cần kiểm soát cao hoặc phát triển lớp cơ sở hạ tầng, ADO.NET vẫn không thể thay thế.

Mối quan hệ bản chất

Dapper là một kết nối ORM nhẹ dựa trên ADO.NET, chứ không phải là sự thay thế. Nó sử dụng các đối tượng như IDbConnection, IDbCommand... từ ADO.NET ở phía dưới, nhưng cung cấp phân mảnh đối tượnggắn kết tham số.

Mã của bạn → Dapper → ADO.NET → Driver cơ sở dữ liệu → Cơ sở dữ liệu

So sánh từng khía cạnh

Yếu tố ADO.NET Dapper
Số lượng mã Nhiều, cần mở đóng kết nối thủ công, ánh xạ trường Ít, chỉ cần một dòng truy vấn + ánh xạ
Hiệu suất Tốc độ nhanh nhất (không chi phí) Gần như nguyên bản, chênh lệch micro giây có thể bỏ qua
Chi phí học tập Cao, cần hiểu Command/Reader/Adapter... Thấp, chỉ cần viết SQL là có thể bắt đầu
Khả năng kiểm soát SQL Kiểm soát hoàn toàn Kiểm soát hoàn toàn (viết SQL thủ công)
Ánh xạ đối tượng Ánh xạ thủ công reader["Name"] Ánh xạ tự động sang POCO
Xử lý tham số Tạo SqlParameter thủ công Đối tượng ẩn danh/động được mở rộng tự động
Quy trình lưu trữ Hỗ trợ nguyên bản nhưng mã dài dòng Hỗ trợ nguyên bản, mã ngắn gọn
Giao dịch Quản lý thủ công API đơn giản tích hợp sẵn
Thao tác hàng loạt Cần tự thực hiện Sử dụng Execute + giao dịch, ngắn gọn
Nhiều kết quả Xử lý thủ công bằng NextResult() Xử lý đẹp mắt bằng QueryMultiple
Phụ thuộc Có sẵn trong .NET, không phụ thuộc Gói NuGet (khoảng 200KB)
Khó khăn khi gỡ lỗi Thấp, logic minh bạch Thấp, SQL và tham số có thể ghi nhật ký
Mức độ áp dụng Lớp cơ sở/đầu vào Lớp ứng dụng kinh doanh

So sánh trực quan về mã

Truy vấn một bản ghi

ADO.NET:

using var conn = new SqlConnection(connStr);
conn.Open();
using var cmd = new SqlCommand("SELECT Id, Name, Age FROM Users WHERE Id = @Id", conn);
cmd.Parameters.AddWithValue("@Id", 1);
using var reader = cmd.ExecuteReader();
if (reader.Read())
{
    var user = new User
    {
        Id = (int)reader["Id"],
        Name = (string)reader["Name"],
        Age = (int)reader["Age"]
    };
}

Dapper:

using var conn = new SqlConnection(connStr);
var user = conn.QueryFirstOrDefault<User>(
    "SELECT Id, Name, Age FROM Users WHERE Id = @Id",
    new { Id = 1 });

Rõ ràng ngay lập tức — ADO.NET cần 12+ dòng để hoàn thành, Dapper chỉ cần 3 dòng.

Chèn hàng loạt

ADO.NET:

using var conn = new SqlConnection(connStr);
conn.Open();
using var tx = conn.BeginTransaction();
try
{
    foreach (var user in users)
    {
        using var cmd = new SqlCommand(
            "INSERT INTO Users(Name,Age) VALUES(@Name,@Age)", conn, tx);
        cmd.Parameters.AddWithValue("@Name", user.Name);
        cmd.Parameters.AddWithValue("@Age", user.Age);
        cmd.ExecuteNonQuery();
    }
    tx.Commit();
}
catch { tx.Rollback(); throw; }

Dapper:

using var conn = new SqlConnection(connStr);
conn.Execute(
    "INSERT INTO Users(Name,Age) VALUES(@Name,@Age)",
    users, transaction: conn.BeginTransaction());

Tham khảo hiệu suất

Trên cơ sở BenchmarkDotNet cho các tình huống truy vấn (100.000 lần ánh xạ):

Hành động ADO.NET Dapper Chênh lệch
Truy vấn đơn giản ~1,8ms ~2,1ms +17%
Truy vấn có tham số ~2,0ms ~2,3ms +15%
Chèn hàng loạt (1000 bản ghi) ~45ms ~47ms +4%

Chi phí hiệu suất của Dapper chủ yếu đến từ phản chiếu (sau lần gọi đầu tiên sẽ được lưu cache), và các lần gọi sau gần như không tốn thêm chi phí. Trong môi trường kinh doanh thực tế, I/O cơ sở dữ liệu mới là điểm nghẽn, khoảng cách này có thể bỏ qua.

Lựa chọn theo tình huống

Tình huống Đề xuất Lý do
Dự án kinh doanh thông thường Dapper Hiệu suất phát triển cao, mã ngắn gọn, chi phí bảo trì thấp
Dự án microservices/API Dapper Kết hợp với mô hình Repository, phát triển nhanh chóng
Phát triển driver/cung cấp cơ sở dữ liệu ADO.NET Cần thực hiện giao diện nền tảng, không thể phụ thuộc vào lớp trên
Cảnh huống hiệu suất tối đa (giao dịch tần suất cao) ADO.NET Mỗi micro giây đều quan trọng, loại bỏ chi phí ánh xạ
Học hiểu nguyên lý cơ sở dữ liệu ADO.NET Hiểu về quản lý kết nối, thực thi lệnh, giao dịch...
Dự án cũ đã có nhiều mã ADO.NET Cả hai đều có thể Có thể dần đưa Dapper vào, không cần viết lại
Cần ánh xạ phức tạp (truy vấn nhiều bảng → đối tượng lồng nhau) Dapper Hỗ trợ Query<T1,T2,T3> rất hữu ích

Làm rõ những hiểu lầm phổ biến

  1. "Dapper không an toàn" — Sai. Dapper sử dụng truy vấn có tham số, phòng chống SQL injection giống ADO.NET.
  2. "Dapper chậm" — Sai. Dapper là ORM nhỏ nhất với hiệu suất tốt nhất, gần như nguyên bản ADO.NET.
  3. "Dùng Dapper thì không cần hiểu ADO.NET" — Sai. Các khái niệm như quản lý kết nối, giao dịch, thời gian chờ của Dapper đều đến từ ADO.NET, hiểu nền tảng mới có thể dùng tốt lớp trên.
  4. "Dapper không thể dùng stored procedure" — Sai. Chỉ cần thiết lập commandType: CommandType.StoredProcedure.

Kết luận: Đối với 90% các tình huống kinh doanh, Dapper là lựa chọn ưu việt; 10% còn lại liên quan đến lớp cơ sở, hiệu suất tối đa hoặc mục đích học tập, hãy sử dụng ADO.NET nguyên bản. Hai công cụ này không đối lập, Dapper là sự bổ sung cho ADO.NET chứ không phải thay thế.

Đăng vào ngày 14 tháng 8 lúc 14:33