C# 数据库连接方式全面解析:从 ADO.NET 到 Entity Framework
本文面向 C# 开发者,深度剖析主流数据库连接技术栈
目录
· C# 数据库连接技术演进
· 主流数据库 ADO.NET 直连详解
· Entity Framework Core 深度解析
· Dapper 轻量级 ORM 实战
· 应用场景与性能对比
· 架构选择指南
C# 数据库连接技术演进
.NET 数据访问技术栈发展历程
技术选型矩阵
| 技术方案 | 推出时间 | 当前状态 | 推荐场景 |
|---|---|---|---|
| ADO.NET | .NET Framework 1.0 | 稳定维护 | 高性能、底层控制 |
| LINQ to SQL | .NET 3.5 | 已淘汰 | 不推荐新项目 |
| Entity Framework 6 | 2013年 | 维护模式 | 现有 .NET Framework 项目 |
| Entity Framework Core | 2016年 | 积极发展 | 新项目首选 |
| Dapper | 2011年 | 稳定维护 | 高性能微ORM |
主流数据库 ADO.NET 直连详解
- SQL Server 连接
基础连接配置
using System.Data.SqlClient;
// 基础连接字符串
var connectionString = "Server=localhost;Database=MyApp;User Id=sa;Password=YourPassword;TrustServerCertificate=true;";
// 使用 SqlConnection
using (var connection = new SqlConnection(connectionString))
{
await connection.OpenAsync();
// 执行命令
using (var command = new SqlCommand("SELECT * FROM Users WHERE Id = @Id", connection))
{
command.Parameters.AddWithValue("@Id", userId);
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
Console.WriteLine(reader["UserName"]);
}
}
}
}
连接字符串参数详解
| 参数 | 说明 | 示例值 | 推荐配置 |
|---|---|---|---|
| Server | 服务器地址 | localhost, .\SQLEXPRESS | 根据环境配置 |
| Database | 数据库名 | MyApp | 明确指定 |
| User Id / Password | 认证信息 | - | 使用集成认证更安全 |
| TrustServerCertificate | SSL证书信任 | true | 开发环境true,生产谨慎 |
| Connection Timeout | 连接超时 | 30 | 根据网络调整 |
| Pooling | 连接池 | true | 默认开启,性能关键 |
| Max Pool Size | 最大连接数 | 100 | 根据并发调整 |
- Oracle 数据库连接
使用 Oracle.ManagedDataAccess
using Oracle.ManagedDataAccess.Client;
// 安装 NuGet 包: Oracle.ManagedDataAccess
var connectionString = "Data Source=localhost:1521/XE;User Id=myuser;Password=mypassword;";
using (var connection = new OracleConnection(connectionString))
{
await connection.OpenAsync();
using (var command = new OracleCommand("SELECT * FROM EMPLOYEES WHERE DEPARTMENT_ID = :DeptId", connection))
{
command.Parameters.Add(":DeptId", OracleDbType.Int32).Value = 50;
using (var reader = await command.ExecuteReaderAsync())
{
while (await reader.ReadAsync())
{
Console.WriteLine($"{reader["FIRST_NAME"]} {reader["LAST_NAME"]}");
}
}
}
}
- MySQL 连接
使用 MySqlConnector
using MySql.Data.MySqlClient;
// 安装 NuGet 包: MySqlConnector
var connectionString = "Server=localhost;Database=testdb;Uid=root;Pwd=password;";
using (var connection = new MySqlConnection(connectionString))
{
await connection.OpenAsync();
using (var command = new MySqlCommand("CALL GetUserOrders(@UserId)", connection))
{
command.CommandType = CommandType.StoredProcedure;
command.Parameters.AddWithValue("@UserId", 123);
using (var reader = await command.ExecuteReaderAsync())
{
// 处理结果集
}
}
}
- SQLite 连接
轻量级数据访问
using Microsoft.Data.Sqlite;
// 安装 NuGet 包: Microsoft.Data.Sqlite
var connectionString = "Data Source=app.db;Cache=Shared";
using (var connection = new SqliteConnection(connectionString))
{
await connection.OpenAsync();
// 创建表
using (var command = new SqliteCommand(
"CREATE TABLE IF NOT EXISTS Users (Id INTEGER PRIMARY KEY, Name TEXT NOT NULL)",
connection))
{
await command.ExecuteNonQueryAsync();
}
}
Entity Framework Core 深度解析
EF Core 8 新特性实战
DbContext 配置
public class ApplicationDbContext : DbContext
{
public DbSet<User> Users { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// SQL Server 配置
optionsBuilder.UseSqlServer(
"Server=localhost;Database=MyApp;Trusted_Connection=true;TrustServerCertificate=true;",
options => options.EnableRetryOnFailure());
// 启用敏感数据日志记录(仅开发环境)
optionsBuilder.EnableSensitiveDataLogging();
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// 配置User实体
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Email)
.IsRequired()
.HasMaxLength(100);
entity.HasIndex(e => e.Email)
.IsUnique();
// 全局查询过滤器
entity.HasQueryFilter(e => !e.IsDeleted);
});
// 配置复杂关系
modelBuilder.Entity<Order>(entity =>
{
entity.HasOne(o => o.User)
.WithMany(u => u.Orders)
.HasForeignKey(o => o.UserId)
.OnDelete(DeleteBehavior.Restrict);
});
}
}
// 实体类定义
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public bool IsDeleted { get; set; }
// 导航属性
public ICollection<Order> Orders { get; set; }
}
public class Order
{
public int Id { get; set; }
public decimal TotalAmount { get; set; }
public DateTime OrderDate { get; set; }
public int UserId { get; set; }
// 导航属性
public User User { get; set; }
public ICollection<OrderItem> OrderItems { get; set; }
}
依赖注入配置
// Program.cs ( .NET 6+ )
var builder = WebApplication.CreateBuilder(args);
// 配置DbContext
builder.Services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
// 生产环境优化
if (!builder.Environment.IsDevelopment())
{
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
}
});
// 配置Repository模式
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IOrderRepository, OrderRepository>();
var app = builder.Build();
EF Core 高级特性
- 显式编译查询
// 性能优化:显式编译查询
private static readonly Func<ApplicationDbContext, int, Task<User>> _userByIdQuery =
EF.CompileAsyncQuery((ApplicationDbContext context, int id) =>
context.Users.FirstOrDefault(u => u.Id == id));
public async Task<User> GetUserByIdAsync(int id)
{
return await _userByIdQuery(_context, id);
}
- 批量操作
// EF Core 7+ 批量操作
public async Task BulkUpdateUsersAsync(List<User> users)
{
// 批量更新
_context.Users.UpdateRange(users);
await _context.SaveChangesAsync();
// 或者使用第三方库:EFCore.BulkExtensions
// await _context.BulkUpdateAsync(users);
}
- 拦截器
// 实现审计拦截器
public class AuditInterceptor : SaveChangesInterceptor
{
public override ValueTask<InterceptionResult<int>> SavingChangesAsync(
DbContextEventData eventData,
InterceptionResult<int> result,
CancellationToken cancellationToken = default)
{
if (eventData.Context is ApplicationDbContext context)
{
foreach (var entry in context.ChangeTracker.Entries<IAuditable>())
{
if (entry.State == EntityState.Added)
{
entry.Entity.CreatedAt = DateTime.UtcNow;
entry.Entity.CreatedBy = "system";
}
else if (entry.State == EntityState.Modified)
{
entry.Entity.UpdatedAt = DateTime.UtcNow;
entry.Entity.UpdatedBy = "system";
}
}
}
return new ValueTask<InterceptionResult<int>>(result);
}
}
Dapper 轻量级 ORM 实战
Dapper 基础用法
using Dapper;
public class UserRepository
{
private readonly IDbConnection _connection;
public UserRepository(IDbConnection connection)
{
_connection = connection;
}
// 简单查询
public async Task<User> GetUserByIdAsync(int id)
{
const string sql = "SELECT * FROM Users WHERE Id = @Id";
return await _connection.QuerySingleOrDefaultAsync<User>(sql, new { Id = id });
}
// 多结果集查询
public async Task<(User user, IEnumerable<Order> orders)> GetUserWithOrdersAsync(int userId)
{
const string sql = @"
SELECT * FROM Users WHERE Id = @UserId;
SELECT * FROM Orders WHERE UserId = @UserId";
using (var multi = await _connection.QueryMultipleAsync(sql, new { UserId = userId }))
{
var user = await multi.ReadSingleOrDefaultAsync<User>();
var orders = await multi.ReadAsync<Order>();
return (user, orders);
}
}
// 复杂查询与映射
public async Task<IEnumerable<UserOrderDto>> GetUserOrdersAsync()
{
const string sql = @"
SELECT u.Id, u.UserName, o.Id as OrderId, o.TotalAmount, o.OrderDate
FROM Users u
INNER JOIN Orders o ON u.Id = o.UserId
WHERE u.IsDeleted = 0";
return await _connection.QueryAsync<UserOrderDto>(sql);
}
}
// DTO 类
public class UserOrderDto
{
public int Id { get; set; }
public string UserName { get; set; }
public int OrderId { get; set; }
public decimal TotalAmount { get; set; }
public DateTime OrderDate { get; set; }
}
Dapper 扩展用法
- 存储过程调用
public async Task<decimal> GetUserTotalSpentAsync(int userId)
{
const string sql = "EXEC dbo.GetUserTotalSpent @UserId";
return await _connection.ExecuteScalarAsync<decimal>(sql, new { UserId = userId });
}
- 批量插入
public async Task BulkInsertUsersAsync(IEnumerable<User> users)
{
const string sql = @"
INSERT INTO Users (UserName, Email, CreatedAt)
VALUES (@UserName, @Email, @CreatedAt)";
await _connection.ExecuteAsync(sql, users);
}
应用场景与性能对比
性能基准测试数据
| 操作类型 | ADO.NET | Dapper | EF Core (跟踪) | EF Core (非跟踪) |
|---|---|---|---|---|
| 简单查询(单记录) | 1.0x | 1.05x | 1.8x | 1.3x |
| 复杂连接查询 | 1.0x | 1.1x | 2.2x | 1.5x |
| 批量插入(1000条) | 1.0x | 1.2x | 3.5x | 2.8x |
| 存储过程调用 | 1.0x | 1.02x | 1.5x | 1.4x |
基准测试环境:.NET 8, SQL Server 2022, 标准硬件配置
企业级应用架构推荐
- 电商系统 - 混合架构
// 订单核心服务 - 使用Dapper保证性能
public class OrderService
{
private readonly IOrderRepository _orderRepo;
private readonly IProductRepository _productRepo;
public async Task<OrderResult> CreateOrderAsync(OrderRequest request)
{
// 使用Dapper处理复杂业务逻辑
using var transaction = await _orderRepo.BeginTransactionAsync();
try
{
// 库存检查
var stockInfo = await _productRepo.CheckStockAsync(request.Items);
if (!stockInfo.IsAvailable)
return OrderResult.Failed("库存不足");
// 创建订单
var orderId = await _orderRepo.CreateOrderAsync(request);
await transaction.CommitAsync();
return OrderResult.Success(orderId);
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
}
// 商品管理 - 使用EF Core提高开发效率
public class ProductService
{
private readonly ApplicationDbContext _context;
public async Task<Product> UpdateProductAsync(int productId, ProductUpdateDto dto)
{
var product = await _context.Products.FindAsync(productId);
if (product == null)
throw new NotFoundException("商品不存在");
// EF Core 变更跟踪自动处理更新
product.Name = dto.Name;
product.Price = dto.Price;
product.Description = dto.Description;
await _context.SaveChangesAsync();
return product;
}
}
- 报表系统 - ADO.NET 优化
public class ReportService
{
public async Task<SalesReport> GenerateSalesReportAsync(DateTime startDate, DateTime endDate)
{
const string sql = @"
SELECT
p.Category,
COUNT(o.Id) as OrderCount,
SUM(o.TotalAmount) as TotalSales,
AVG(o.TotalAmount) as AverageOrderValue
FROM Orders o
INNER JOIN Products p ON o.ProductId = p.Id
WHERE o.OrderDate BETWEEN @StartDate AND @EndDate
GROUP BY p.Category";
using var connection = new SqlConnection(_connectionString);
var results = await connection.QueryAsync<SalesData>(sql, new { startDate, endDate });
return new SalesReport
{
Period = $"{startDate:yyyy-MM-dd} 到 {endDate:yyyy-MM-dd}",
Data = results.ToList()
};
}
}
架构选择指南
技术选型决策矩阵
| 考虑维度 | ADO.NET | Dapper | EF Core |
|---|---|---|---|
| 开发速度 | ★☆☆ | ★★☆ | ★★★ |
| 运行性能 | ★★★ | ★★☆ | ★☆☆ |
| 可维护性 | ★☆☆ | ★★☆ | ★★★ |
| 团队技能要求 | 高 | 中 | 低 |
| 数据库迁移支持 | 无 | 无 | 优秀 |
| 复杂查询支持 | 优秀 | 良好 | 良好 |
具体场景推荐
- 新项目启动
推荐:EF Core + Dapper 混合架构
// 启动配置
builder.Services.AddDbContext<ApplicationDbContext>(...);
builder.Services.AddScoped<IDapperContext, DapperContext>();
// 根据不同场景选择技术
public class UserService
{
// CRUD使用EF Core
public async Task UpdateUserProfileAsync(UserProfileDto dto)
{
var user = await _context.Users.FindAsync(dto.UserId);
// ... EF Core 操作
}
// 报表查询使用Dapper
public async Task<UserStatistics> GetUserStatisticsAsync(int userId)
{
return await _dapperContext.QuerySingleAsync<UserStatistics>(
"EXEC GetUserStatistics @UserId", new { UserId = userId });
}
}
- 遗留系统现代化
推荐:渐进式迁移
· 阶段1:保持 ADO.NET,添加 Dapper 包装
· 阶段2:引入 EF Core 处理新功能
· 阶段3:逐步迁移核心业务到 EF Core
- 高性能API服务
推荐:Dapper 为主
// 配置只读副本连接
services.AddSingleton<IDbConnection>(sp =>
new SqlConnection(config.GetConnectionString("ReadOnly")));
// 使用Dapper处理所有数据访问
public class HighPerformanceService
{
public async Task<PagedResult<User>> GetUsersAsync(int page, int pageSize)
{
const string sql = @"
SELECT * FROM Users
ORDER BY Id
OFFSET @Offset ROWS
FETCH NEXT @PageSize ROWS ONLY;
SELECT COUNT(*) FROM Users;";
using var multi = await _connection.QueryMultipleAsync(sql, new {
Offset = (page - 1) * pageSize,
PageSize = pageSize
});
var users = await multi.ReadAsync<User>();
var total = await multi.ReadSingleAsync<int>();
return new PagedResult<User>(users, total, page, pageSize);
}
}
最佳实践总结
- 连接管理
// 使用using确保连接释放 using var connection = new SqlConnection(connectionString); await connection.OpenAsync(); // 或者使用依赖注入管理生命周期 services.AddScoped<IDbConnection>(sp => new SqlConnection(sp.GetRequiredService<IConfiguration>().GetConnectionString("Default"))); - 性能优化
// EF Core 优化 options.UseSqlServer(connectionString, options => { options.EnableRetryOnFailure(3, TimeSpan.FromSeconds(5), null); }); // 只读查询使用AsNoTracking var users = await _context.Users.AsNoTracking().ToListAsync(); - 安全考虑
// 始终使用参数化查询 var command = new SqlCommand("SELECT * FROM Users WHERE Name = @Name", connection); command.Parameters.AddWithValue("@Name", userName); // 不要这样做! // var command = new SqlCommand($"SELECT * FROM Users WHERE Name = '{userName}'", connection);
数据库连接方式应用场景分析
| 应用场景 | 推荐技术 | 理由 | 示例 |
|---|---|---|---|
| 高性能交易系统 | Dapper + 存储过程 | 最小化ORM开销,最大化控制 | 金融交易核心 |
| 企业级业务系统 | EF Core + Dapper混合 | 开发效率与性能平衡 | ERP、CRM系统 |
| 快速原型开发 | EF Core | 快速迭代,代码优先 | MVP项目 |
| 数据仓库/报表 | ADO.NET/Dapper | 复杂查询优化,存储过程 | BI报表系统 |
| 微服务架构 | 根据服务特点选择 | 不同服务不同需求 | 分布式系统 |
| 移动应用本地存储 | SQLite + EF Core | 轻量级,LINQ支持 | Xamarin, MAUI应用 |
各场景DB直连和ORM框架使用分析
- DB直连适用场景分析
适用场景:
- 高性能要求的核心业务逻辑
- 复杂报表和数据分析查询
- 存储过程密集的应用
- 需要精细控制SQL执行的场景
优势:
- 极致性能,无额外开销
- 完全控制SQL生成和执行计划
- 支持所有数据库特定功能
- 避免ORM的学习和维护成本
劣势:
- 开发效率较低
- 代码重复度高
- 维护成本随项目规模增长
- 容易产生SQL注入安全问题
- ORM框架适用场景分析
适用场景:
- 快速业务应用开发
- 团队技术水平参差不齐
- 需要数据库迁移支持
- 多数据库支持需求
优势:
- 大幅提升开发效率
- 强类型检查,编译时错误检测
- 自动处理连接管理和事务
- 内置安全机制防止SQL注入
劣势:
- 性能开销
- 复杂查询可能效率低下
- 学习曲线
- 隐藏底层细节,调试困难
混合架构实践建议
// 混合架构示例:根据操作类型选择技术
public class HybridDataService
{
private readonly ApplicationDbContext _efContext;
private readonly IDbConnection _dapperConnection;
public HybridDataService(ApplicationDbContext efContext, IDbConnection dapperConnection)
{
_efContext = efContext;
_dapperConnection = dapperConnection;
}
// CRUD操作使用EF Core
public async Task<User> CreateUserAsync(User user)
{
_efContext.Users.Add(user);
await _efContext.SaveChangesAsync();
return user;
}
// 复杂查询使用Dapper
public async Task<List<UserStats>> GetUserStatisticsAsync()
{
const string sql = @"
SELECT
u.Id,
u.UserName,
COUNT(o.Id) as OrderCount,
SUM(o.TotalAmount) as TotalSpent
FROM Users u
LEFT JOIN Orders o ON u.Id = o.UserId
GROUP BY u.Id, u.UserName
ORDER BY TotalSpent DESC";
return (await _dapperConnection.QueryAsync<UserStats>(sql)).ToList();
}
// 批量操作使用原生ADO.NET
public async Task BulkInsertOrdersAsync(List<Order> orders)
{
using var bulkCopy = new SqlBulkCopy(_dapperConnection.ConnectionString);
bulkCopy.DestinationTableName = "Orders";
// 配置列映射
bulkCopy.ColumnMappings.Add("Id", "Id");
bulkCopy.ColumnMappings.Add("UserId", "UserId");
bulkCopy.ColumnMappings.Add("TotalAmount", "TotalAmount");
bulkCopy.ColumnMappings.Add("OrderDate", "OrderDate");
using var dataTable = ConvertToDataTable(orders);
await bulkCopy.WriteToServerAsync(dataTable);
}
}
未来展望
随着 .NET 8 和即将到来的 .NET 9,C# 数据访问技术继续演进:
· EF Core 8 带来了新的 JSON 列映射、原始集合等特性
· 性能持续优化,缩小与原生ADO.NET的差距
· 云原生支持 更好的与 Azure Cosmos DB、Azure SQL 集成
· AOT编译支持 为高性能场景提供新的可能
资源推荐:
· Microsoft EF Core 文档
· Dapper 官方GitHub
· .NET 数据访问架构指南
选择合适的数据访问策略是项目成功的关键因素之一。希望本文能为您的技术决策提供有价值的参考!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)