本文面向 C# 开发者,深度剖析主流数据库连接技术栈

目录

· C# 数据库连接技术演进
· 主流数据库 ADO.NET 直连详解
· Entity Framework Core 深度解析
· Dapper 轻量级 ORM 实战
· 应用场景与性能对比
· 架构选择指南

C# 数据库连接技术演进

.NET 数据访问技术栈发展历程

ADO.NET 1.0
LINQ to SQL
Entity Framework 4.0
Entity Framework 6
Entity Framework Core
Dapper
EF Core 8.0

技术选型矩阵

技术方案 推出时间 当前状态 推荐场景
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 直连详解

  1. 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 根据并发调整
  1. 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"]}");
            }
        }
    }
}
  1. 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())
        {
            // 处理结果集
        }
    }
}
  1. 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 高级特性

  1. 显式编译查询
// 性能优化:显式编译查询
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);
}
  1. 批量操作
// EF Core 7+ 批量操作
public async Task BulkUpdateUsersAsync(List<User> users)
{
    // 批量更新
    _context.Users.UpdateRange(users);
    await _context.SaveChangesAsync();
    
    // 或者使用第三方库:EFCore.BulkExtensions
    // await _context.BulkUpdateAsync(users);
}
  1. 拦截器
// 实现审计拦截器
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 扩展用法

  1. 存储过程调用
public async Task<decimal> GetUserTotalSpentAsync(int userId)
{
    const string sql = "EXEC dbo.GetUserTotalSpent @UserId";
    return await _connection.ExecuteScalarAsync<decimal>(sql, new { UserId = userId });
}
  1. 批量插入
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, 标准硬件配置

企业级应用架构推荐

  1. 电商系统 - 混合架构
// 订单核心服务 - 使用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;
    }
}
  1. 报表系统 - 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
开发速度 ★☆☆ ★★☆ ★★★
运行性能 ★★★ ★★☆ ★☆☆
可维护性 ★☆☆ ★★☆ ★★★
团队技能要求
数据库迁移支持 优秀
复杂查询支持 优秀 良好 良好

具体场景推荐

  1. 新项目启动

推荐: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. 遗留系统现代化

推荐:渐进式迁移

· 阶段1:保持 ADO.NET,添加 Dapper 包装
· 阶段2:引入 EF Core 处理新功能
· 阶段3:逐步迁移核心业务到 EF Core

  1. 高性能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);
    }
}

最佳实践总结

  1. 连接管理
    // 使用using确保连接释放
    using var connection = new SqlConnection(connectionString);
    await connection.OpenAsync();
    
    // 或者使用依赖注入管理生命周期
    services.AddScoped<IDbConnection>(sp => 
        new SqlConnection(sp.GetRequiredService<IConfiguration>().GetConnectionString("Default")));
    
  2. 性能优化
    // EF Core 优化
    options.UseSqlServer(connectionString, options =>
    {
        options.EnableRetryOnFailure(3, TimeSpan.FromSeconds(5), null);
    });
    
    // 只读查询使用AsNoTracking
    var users = await _context.Users.AsNoTracking().ToListAsync();
    
  3. 安全考虑
    // 始终使用参数化查询
    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框架使用分析

  1. DB直连适用场景分析

适用场景:

  • 高性能要求的核心业务逻辑
  • 复杂报表和数据分析查询
  • 存储过程密集的应用
  • 需要精细控制SQL执行的场景

优势:

  • 极致性能,无额外开销
  • 完全控制SQL生成和执行计划
  • 支持所有数据库特定功能
  • 避免ORM的学习和维护成本

劣势:

  • 开发效率较低
  • 代码重复度高
  • 维护成本随项目规模增长
  • 容易产生SQL注入安全问题
  1. 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 数据访问架构指南

选择合适的数据访问策略是项目成功的关键因素之一。希望本文能为您的技术决策提供有价值的参考!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐