.NET Core 数据库ORM框架用法简述

.NET Core ORM框架用法简述

一、主流.NET Core ORM框架概述

在.NET Core生态系统中,主流的ORM(Object-Relational Mapping)框架包括:

  1. ​Entity Framework Core (EF Core)​ - 微软官方推出的ORM框架
  2. ​Dapper​ - 轻量级微ORM
  3. ​Npgsql.EntityFrameworkCore.PostgreSQL​ - PostgreSQL专用EF Core提供程序
  4. ​Pomelo.EntityFrameworkCore.MySql​ - MySQL专用EF Core提供程序
  5. ​LINQ to DB​ - 高性能ORM

本文重点介绍最常用的EF Core和Dapper。

二、Entity Framework Core (EF Core) 使用指南

1. 安装与配置

​安装NuGet包​​:

复制代码
Lua 复制代码
dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Microsoft.EntityFrameworkCore.SqlServer # SQL Server提供程序
# 或其他数据库提供程序

​DbContext配置​​:

复制代码
cs 复制代码
public class AppDbContext : DbContext
{
    public DbSet<User> Users { get; set; }
    public DbSet<Order> Orders { get; set; }
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=.;Database=MyApp;Trusted_Connection=True;");
    }
}

​依赖注入配置​​(推荐):

复制代码
cs 复制代码
// Startup.cs或Program.cs
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));

2. 数据模型定义

​实体类​​:

复制代码
cs 复制代码
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime BirthDate { get; set; }
    
    // 导航属性
    public ICollection<Order> Orders { get; set; }
}

public class Order
{
    public int Id { get; set; }
    public decimal Amount { get; set; }
    public DateTime OrderDate { get; set; }
    
    // 外键和导航属性
    public int UserId { get; set; }
    public User User { get; set; }
}

​Fluent API配置​​:

复制代码
cs 复制代码
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<User>()
        .Property(u => u.Name)
        .IsRequired()
        .HasMaxLength(50);
        
    modelBuilder.Entity<Order>()
        .HasOne(o => o.User)
        .WithMany(u => u.Orders)
        .HasForeignKey(o => o.UserId);
}

3. CRUD操作

​添加数据​​:

复制代码
cs 复制代码
using (var context = new AppDbContext())
{
    var user = new User { Name = "张三", BirthDate = new DateTime(1990, 1, 1) };
    context.Users.Add(user);
    context.SaveChanges();
}

​查询数据​​:

复制代码
cs 复制代码
// 简单查询
var users = context.Users.ToList();

// 条件查询
var activeUsers = context.Users
    .Where(u => u.Name.Contains("张"))
    .OrderBy(u => u.BirthDate)
    .ToList();

// 投影查询
var userNames = context.Users
    .Select(u => new { u.Id, u.Name })
    .ToList();

​更新数据​​:

复制代码
cs 复制代码
using (var context = new AppDbContext())
{
    var user = context.Users.Find(1);
    if (user != null)
    {
        user.Name = "李四";
        context.SaveChanges();
    }
}

​删除数据​​:

复制代码
cs 复制代码
using (var context = new AppDbContext())
{
    var user = context.Users.Find(1);
    if (user != null)
    {
        context.Users.Remove(user);
        context.SaveChanges();
    }
}

4. 高级功能

​异步操作​​:

复制代码
cs 复制代码
var user = await context.Users.FindAsync(1);
var users = await context.Users.Where(u => u.Name.Contains("张")).ToListAsync();

​事务处理​​:

复制代码
cs 复制代码
using (var transaction = await context.Database.BeginTransactionAsync())
{
    try
    {
        // 执行多个操作
        await context.SaveChangesAsync();
        await transaction.CommitAsync();
    }
    catch
    {
        await transaction.RollbackAsync();
        throw;
    }
}

​迁移管理​​:

复制代码
cs 复制代码
# 添加迁移
dotnet ef migrations add InitialCreate

# 更新数据库
dotnet ef database update

# 回滚迁移
dotnet ef database update PreviousMigration

三、Dapper使用指南

1. 安装与配置

​安装NuGet包​​:

复制代码
Lua 复制代码
dotnet add package Dapper
dotnet add package System.Data.SqlClient # SQL Server提供程序

​基本使用​​:

复制代码
cs 复制代码
using var connection = new SqlConnection("Server=.;Database=MyApp;Trusted_Connection=True;");
connection.Open();

2. CRUD操作

​查询数据​​:

复制代码
cs 复制代码
var users = connection.Query<User>("SELECT * FROM Users WHERE Name LIKE @Name", 
    new { Name = "%张%" });

var user = connection.QueryFirstOrDefault<User>("SELECT * FROM Users WHERE Id = @Id", 
    new { Id = 1 });

​插入数据​​:

复制代码
cs 复制代码
var id = connection.QuerySingle<int>(
    "INSERT INTO Users (Name, BirthDate) VALUES (@Name, @BirthDate); SELECT SCOPE_IDENTITY();",
    new { Name = "张三", BirthDate = DateTime.Now });

​更新数据​​:

复制代码
cs 复制代码
var affectedRows = connection.Execute(
    "UPDATE Users SET Name = @Name WHERE Id = @Id",
    new { Name = "李四", Id = 1 });

​删除数据​​:

复制代码
cs 复制代码
var deletedRows = connection.Execute("DELETE FROM Users WHERE Id = @Id", new { Id = 1 });

3. 高级功能

​存储过程调用​​:

复制代码
cs 复制代码
var users = connection.Query<User>("dbo.GetUsersByAgeRange", 
    new { MinAge = 18, MaxAge = 30 },
    commandType: CommandType.StoredProcedure);

​多结果集处理​​:

复制代码
cs 复制代码
using (var multi = connection.QueryMultiple(
    "SELECT * FROM Users; SELECT * FROM Orders", 
    commandType: CommandType.Text))
{
    var users = multi.Read<User>().ToList();
    var orders = multi.Read<Order>().ToList();
}

​动态参数​​:

复制代码
cs 复制代码
var sql = "SELECT * FROM Users WHERE 1=1";
var parameters = new DynamicParameters();
if (!string.IsNullOrEmpty(name))
{
    sql += " AND Name = @Name";
    parameters.Add("Name", name);
}
if (minAge.HasValue)
{
    sql += " AND Age >= @MinAge";
    parameters.Add("MinAge", minAge.Value);
}

var users = connection.Query<User>(sql, parameters);

四、EF Core与Dapper对比

特性 EF Core Dapper
​性能​ 中等(有ORM开销) 高(接近原生SQL)
​学习曲线​ 较陡峭(需理解LINQ、EF概念) 平缓(SQL知识即可)
​功能丰富度​ 高(迁移、跟踪、变更检测等) 低(仅数据访问)
​适用场景​ 复杂业务、快速开发 高性能需求、复杂SQL
​异步支持​ 原生支持 需手动实现
​事务管理​ 内置支持 需手动实现
​缓存​ 一级缓存 无内置缓存

五、选择建议

  1. ​选择EF Core当​​:

    • 需要快速开发CRUD应用
    • 团队熟悉ORM概念
    • 需要数据库迁移功能
    • 项目需要频繁变更数据模型
  2. ​选择Dapper当​​:

    • 需要极致性能
    • 执行复杂SQL查询
    • 已有成熟的SQL知识
    • 项目以读为主,写操作较少

六、最佳实践

EF Core最佳实践

  1. ​合理使用延迟加载​​:

    复制代码
    cs 复制代码
    // 禁用延迟加载(推荐)
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseLazyLoadingProxies(false);
    }
  2. ​批量操作优化​​:

    cs 复制代码
    // 使用AddRange代替多个Add
    context.Users.AddRange(usersList);
    
    // 对于大量数据,考虑分批处理
    foreach (var batch in usersList.Batch(500))
    {
        context.Users.AddRange(batch);
        context.SaveChanges();
    }
  3. ​避免N+1查询​​:

    cs 复制代码
    // 不好的做法(会导致N+1)
    var users = context.Users.ToList();
    foreach (var user in users)
    {
        var orders = context.Orders.Where(o => o.UserId == user.Id).ToList();
    }
    
    // 好的做法(预加载)
    var users = context.Users.Include(u => u.Orders).ToList();

Dapper最佳实践

  1. ​使用参数化查询​​:

    复制代码
    cs 复制代码
    // 安全的方式
    connection.Query<User>("SELECT * FROM Users WHERE Name = @Name", new { Name = userInput });
    
    // 避免拼接SQL字符串(有SQL注入风险)
    // connection.Query<User>($"SELECT * FROM Users WHERE Name = '{userInput}'");
  2. ​连接管理​​:

    复制代码
    cs 复制代码
    // 使用using确保连接释放
    using (var connection = new SqlConnection(connectionString))
    {
        connection.Open();
        // 执行操作
    }
  3. ​存储过程调用​​:

    复制代码
    cs 复制代码
    var result = connection.QueryFirstOrDefault<int>(
        "dbo.GetUserCountByRole",
        new { RoleId = roleId },
        commandType: CommandType.StoredProcedure);

七、性能优化技巧

EF Core性能优化

  1. ​启用查询缓存​​:

    cs 复制代码
    services.AddDbContext<AppDbContext>(options =>
        options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)
               .UseSqlServer(connectionString));
  2. ​使用AsNoTracking​​:

    cs 复制代码
    // 只读场景使用
    var users = context.Users.AsNoTracking().ToList();
  3. ​投影查询​​:

    cs 复制代码
    // 只查询需要的字段
    var userDtos = context.Users
        .Select(u => new UserDto { Id = u.Id, Name = u.Name })
        .ToList();

Dapper性能优化

  1. ​使用ExecuteScalar代替QueryFirstOrDefault​​:

    cs 复制代码
    // 获取单个值
    var count = connection.ExecuteScalar<int>("SELECT COUNT(*) FROM Users");
  2. ​使用动态类型​​:

    cs 复制代码
    // 当不需要强类型时
    var result = connection.Query("SELECT * FROM Users").FirstOrDefault();
  3. ​连接池配置​​:

    cs 复制代码
    // 在连接字符串中配置
    "Server=.;Database=MyApp;User Id=user;Password=pass;Max Pool Size=100;"

八、常见问题解决

EF Core常见问题

  1. ​N+1查询问题​​:

    • 使用IncludeThenInclude预加载
    • 使用Select投影查询
  2. ​性能下降​​:

    • 检查生成的SQL(使用日志)
    • 考虑禁用变更跟踪(AsNoTracking)
    • 优化数据库索引
  3. ​迁移冲突​​:

    • 使用dotnet ef migrations remove回滚
    • 手动合并迁移文件

Dapper常见问题

  1. ​SQL注入风险​​:

    • 始终使用参数化查询
    • 避免字符串拼接SQL
  2. ​连接泄漏​​:

    • 确保使用using语句
    • 实现IDisposable模式管理连接
  3. ​结果映射错误​​:

    • 检查列名与属性名匹配
    • 使用Query<T>时确保T有默认构造函数

九、工具与扩展

EF Core工具

  1. ​EF Core Power Tools​​:

    • 可视化查看数据库模型
    • 快速生成实体类
    • 执行数据库比较
  2. ​Entity Framework Core Profiler​​:

    • 分析EF Core生成的SQL
    • 性能监控

Dapper扩展

  1. ​Dapper.Contrib​​:

    • 添加简单的CRUD扩展方法
    cs 复制代码
    connection.Insert(user);
    connection.Update(user);
  2. ​Dapper.FluentMap​​:

    • 配置实体到表的映射
    cs 复制代码
    FluentMapper.Initialize(config =>
    {
        config.AddMap(new UserMap());
    });
  3. ​DapperQueryBuilder​​:

    • 构建安全动态SQL
    cs 复制代码
    var query = connection.QueryBuilder($"SELECT * FROM Users WHERE 1=1");
    if (name != null) query.Where("Name = @Name", new { Name = name });
    var users = query.Query<User>();

十、总结与建议

  1. ​EF Core适合​​:

    • 快速开发的企业应用
    • 需要数据库迁移的项目
    • 团队熟悉ORM的情况
  2. ​Dapper适合​​:

    • 高性能要求的微服务
    • 复杂SQL查询场景
    • 已有成熟SQL知识的项目
  3. ​混合使用策略​​:

    • 主框架使用EF Core
    • 性能关键部分使用Dapper
    cs 复制代码
    // 在EF Core项目中使用Dapper
    public class UserRepository : IUserRepository
    {
        private readonly AppDbContext _context;
        private readonly IDbConnection _dapperConnection;
        
        public UserRepository(AppDbContext context, IDbConnection dapperConnection)
        {
            _context = context;
            _dapperConnection = dapperConnection;
        }
        
        public User GetById(int id)
        {
            // 使用EF Core
            return _context.Users.Find(id);
        }
        
        public IEnumerable<User> GetActiveUsers()
        {
            // 使用Dapper执行复杂查询
            return _dapperConnection.Query<User>("SELECT * FROM Users WHERE IsActive = 1");
        }
    }

通过合理选择ORM框架并遵循最佳实践,可以显著提高.NET Core应用程序的开发效率和性能表现。

相关推荐
楠奕6 分钟前
python上测试neo4j库
数据库·python·neo4j
编程乐趣28 分钟前
基于C#开发的适合Windows开源文件管理器
开发语言·windows·c#
我言秋日胜春朝★1 小时前
【MySQL】表的CRUD
数据库·mysql
当代红领巾2 小时前
windows 下 oracle 数据库的备份与还原
数据库
新玉54012 小时前
SQL注入
数据库·sql·oracle
阿桨2 小时前
【Prometheus-OracleDB Exporter安装配置指南,开机自启】
数据库·oracle·centos·prometheus
赵渝强老师2 小时前
【赵渝强老师】使用TiDB的审计日志
数据库·tidb
code_shenbing3 小时前
C# 实现列式存储数据
开发语言·c#·存储
❀͜͡傀儡师3 小时前
基于Spring Boot 3.0、ShardingSphere、PostgreSQL或达梦数据库的分库分表
数据库·spring boot·postgresql