
告别重复代码!C#泛型仓储模式让你的数据访问层瞬间优雅10倍
你是否还在为每个实体类都要写一套增删改查代码而烦恼?是否厌倦了在不同Service层看到几乎相同的数据操作逻辑?
如果你正面临这些痛点,那么今天这篇文章将彻底改变你的编程思维! 我将手把手教你构建一个基于SqlSugar的泛型仓储模式,让你的数据访问层从此告别重复,拥抱优雅。
🎯 什么是泛型仓储模式?为什么它如此重要?
传统方式的痛点分析
在没有使用仓储模式之前,我们的代码通常是这样的:
public class UserService
{
public async Task<List<User>> GetUsersAsync()
{
// 重复的数据库操作代码
using var db = new SqlSugar.SqlSugarClient(config);
return await db.Queryable<User>().ToListAsync();
}
public async Task<bool> AddUserAsync(User user)
{
// 又是重复的代码...
using var db = new SqlSugar.SqlSugarClient(config);
return await db.Insertable(user).ExecuteCommandAsync() > 0;
}
}
publicclass ProductService
{
public async Task<List<Product>> GetProductsAsync()
{
using var db = new SqlSugar.SqlSugarClient(config);
return await db.Queryable<Product>().ToListAsync();
}
}
看到了吗?这种写法的问题显而易见:
💀 代码重复率极高
🐛 修改逻辑需要改动多处
📈 维护成本呈指数级增长
🔧 难以进行统一的日志记录和性能监控
🚀 解决方案:构建通用泛型仓储模式
Nuget 安装以下库
SqlSugarCore
Microsoft.Extensions.DependencyInjection
Microsoft.Extensions.Logging
Microsoft.Extensions.Logging.Console
实体类
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
namespace AppSQLBaseRepository
{
[SugarTable("sys_user")]
publicclass User
{
/// <summary>
/// 用户ID - 主键
/// </summary>
[SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
publicint Id { get; set; }
/// <summary>
/// 用户名 - 唯一索引
/// </summary>
[SugarColumn(Length = 50, IsNullable = false)]
[Required(ErrorMessage = "用户名不能为空")]
[StringLength(50, ErrorMessage = "用户名长度不能超过50个字符")]
publicstring UserName { get; set; }
/// <summary>
/// 密码哈希值
/// </summary>
[SugarColumn(Length = 256, IsNullable = false)]
[Required(ErrorMessage = "密码不能为空")]
publicstring PasswordHash { get; set; }
/// <summary>
/// 邮箱地址
/// </summary>
[SugarColumn(Length = 100, IsNullable = true)]
[EmailAddress(ErrorMessage = "邮箱格式不正确")]
[StringLength(100, ErrorMessage = "邮箱长度不能超过100个字符")]
publicstring Email { get; set; }
/// <summary>
/// 手机号码
/// </summary>
[SugarColumn(Length = 20, IsNullable = true)]
[Phone(ErrorMessage = "手机号码格式不正确")]
[StringLength(20, ErrorMessage = "手机号码长度不能超过20个字符")]
publicstring PhoneNumber { get; set; }
/// <summary>
/// 真实姓名
/// </summary>
[SugarColumn(Length = 50, IsNullable = true)]
[StringLength(50, ErrorMessage = "真实姓名长度不能超过50个字符")]
publicstring RealName { get; set; }
/// <summary>
/// 头像URL
/// </summary>
[SugarColumn(Length = 500, IsNullable = true)]
[StringLength(500, ErrorMessage = "头像URL长度不能超过500个字符")]
publicstring Avatar { get; set; }
/// <summary>
/// 用户状态 (0:禁用 1:启用)
/// </summary>
[SugarColumn(IsNullable = false)]
publicint Status { get; set; } = 1;
/// <summary>
/// 是否删除 (0:未删除 1:已删除) - 用于逻辑删除
/// </summary>
[SugarColumn(IsNullable = false)]
publicbool IsDeleted { get; set; } = false;
/// <summary>
/// 创建时间
/// </summary>
[SugarColumn(IsNullable = false)]
public DateTime CreateTime { get; set; } = DateTime.Now;
/// <summary>
/// 更新时间
/// </summary>
[SugarColumn(IsNullable = true)]
public DateTime? UpdateTime { get; set; }
/// <summary>
/// 删除时间
/// </summary>
[SugarColumn(IsNullable = false)]
public DateTime DeleteTime { get; set; }
/// <summary>
/// 最后登录时间
/// </summary>
[SugarColumn(IsNullable = true)]
public DateTime? LastLoginTime { get; set; }
/// <summary>
/// 创建人
/// </summary>
[SugarColumn(IsNullable = true)]
publicstring? CreatedBy { get; set; }
/// <summary>
/// 更新人
/// </summary>
[SugarColumn(IsNullable = true)]
publicstring? UpdatedBy { get; set; }
/// <summary>
/// 删除人
/// </summary>
[SugarColumn(IsNullable = true)]
publicstring? DeleteBy { get; set; }
/// <summary>
/// 备注信息
/// </summary>
[SugarColumn(Length = 500, IsNullable = true)]
[StringLength(500, ErrorMessage = "备注信息长度不能超过500个字符")]
publicstring Remark { get; set; }
}
}
核心接口设计
首先,我们定义一个通用的仓储接口:
其实Sqlsugar自带的已经很牛了。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
namespace AppSQLBaseRepository
{
public interface IBaseRepository<T> where T : class, new()
{
#region 查询操作
Task<T> GetFirstAsync(Expression<Func<T, bool>> whereExpression);
Task<List<T>> GetListAsync(Expression<Func<T, bool>> whereExpression);
Task<PageResult<T>> GetPageListAsync(
Expression<Func<T, bool>> whereExpression,
PageModel pageModel);
#endregion
#region 新增操作
Task<bool> AddAsync(T entity);
Task<bool> AddRangeAsync(List<T> entities);
#endregion
#region 更新操作
Task<bool> UpdateAsync(T entity);
Task<bool> UpdateAsync(
Expression<Func<T, T>> updateExpression,
Expression<Func<T, bool>> whereExpression);
#endregion
#region 删除操作
Task<bool> DeleteAsync(Expression<Func<T, bool>> whereExpression);
Task<bool> FakeDeleteAsync(T entity, Action<T> setDeleteAction);
#endregion
#region 聚合操作
Task<bool> IsExistAsync(Expression<Func<T, bool>> whereExpression);
Task<int> CountAsync(Expression<Func<T, bool>> whereExpression);
#endregion
}
}
🛠️ 核心实现:BaseRepository
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SqlSugar;
namespace AppSQLBaseRepository
{
publicclass BaseRepository<T> : IBaseRepository<T> where T : class, new()
{
protected readonly ISqlSugarClient Db;
private readonly ILogger<BaseRepository<T>> _logger;
public BaseRepository(ISqlSugarClient sqlSugarClient, ILogger<BaseRepository<T>> logger)
{
Db = sqlSugarClient;
_logger = logger;
// 配置SQL日志 - 开发调试神器
ConfigureSqlLog();
}
/// <summary>
/// 配置SQL执行日志 - 性能监控和问题排查的利器
/// </summary>
private void ConfigureSqlLog()
{
Db.Aop.OnLogExecuting = (sql, pars) =>
{
// 记录SQL执行日志,生产环境可以通过配置控制
string logMessage = $"SQL执行: {sql}";
// 记录参数信息(调试时非常有用)
if (pars?.Length > 0)
{
var paramInfo = string.Join(", ",
pars.Select(p => $"{p.ParameterName}={p.Value}"));
logMessage += $" | 参数: {paramInfo}";
}
_logger.LogDebug(logMessage);
};
}
#region 查询实现
publicvirtual async Task<T> GetFirstAsync(Expression<Func<T, bool>> whereExpression)
{
try
{
return await Db.Queryable<T>().Where(whereExpression).FirstAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "查询单个实体失败");
throw;
}
}
publicvirtual async Task<List<T>> GetListAsync(Expression<Func<T, bool>> whereExpression)
{
try
{
return await Db.Queryable<T>().Where(whereExpression).ToListAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "查询实体列表失败");
throw;
}
}
/// <summary>
/// 分页查询实现 - 企业级应用的核心功能
/// </summary>
publicvirtual async Task<PageResult<T>> GetPageListAsync(
Expression<Func<T, bool>> whereExpression,
PageModel pageModel)
{
try
{
// 🚀 使用SqlSugar的RefAsync获取总数,一次查询搞定!
RefAsync<int> totalCount = 0;
var list = await Db.Queryable<T>()
.Where(whereExpression)
.ToPageListAsync(
pageModel.PageIndex,
pageModel.PageSize,
totalCount);
returnnew PageResult<T>
{
PageIndex = pageModel.PageIndex,
PageSize = pageModel.PageSize,
TotalCount = totalCount,
Data = list
};
}
catch (Exception ex)
{
_logger.LogError(ex, "分页查询失败");
throw;
}
}
#endregion
#region 新增实现
publicvirtual async Task<bool> AddAsync(T entity)
{
try
{
return await Db.Insertable(entity).ExecuteCommandAsync() > 0;
}
catch (Exception ex)
{
_logger.LogError(ex, "添加实体失败");
throw;
}
}
/// <summary>
/// 批量新增 - 大数据量操作的性能优化
/// </summary>
publicvirtual async Task<bool> AddRangeAsync(List<T> entities)
{
try
{
// 💡 批量插入,性能比逐条插入快10倍以上!
return await Db.Insertable(entities).ExecuteCommandAsync() > 0;
}
catch (Exception ex)
{
_logger.LogError(ex, "批量添加实体失败");
throw;
}
}
#endregion
#region 更新实现
publicvirtual async Task<bool> UpdateAsync(T entity)
{
try
{
return await Db.Updateable(entity).ExecuteCommandAsync() > 0;
}
catch (Exception ex)
{
_logger.LogError(ex, "更新实体失败");
throw;
}
}
publicvirtual async Task<bool> UpdateAsync(
Expression<Func<T, T>> updateExpression,
Expression<Func<T, bool>> whereExpression)
{
try
{
return await Db.Updateable<T>()
.SetColumns(updateExpression)
.Where(whereExpression)
.ExecuteCommandAsync() > 0;
}
catch (Exception ex)
{
_logger.LogError(ex, "条件更新失败");
throw;
}
}
#endregion
#region 删除实现
publicvirtual async Task<bool> DeleteAsync(Expression<Func<T, bool>> whereExpression)
{
try
{
return await Db.Deleteable<T>().Where(whereExpression).ExecuteCommandAsync() > 0;
}
catch (Exception ex)
{
_logger.LogError(ex, "删除实体失败");
throw;
}
}
/// <summary>
/// 逻辑删除 - 推荐做法,保证数据安全
/// </summary>
publicvirtual async Task<bool> FakeDeleteAsync(T entity, Action<T> setDeleteAction)
{
try
{
// 🎯 执行自定义的删除逻辑设置
setDeleteAction(entity);
return await UpdateAsync(entity);
}
catch (Exception ex)
{
_logger.LogError(ex, "逻辑删除失败");
throw;
}
}
#endregion
#region 聚合操作实现
publicvirtual async Task<bool> IsExistAsync(Expression<Func<T, bool>> whereExpression)
{
try
{
return await Db.Queryable<T>().Where(whereExpression).AnyAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "检查实体存在性失败");
throw;
}
}
publicvirtual async Task<int> CountAsync(Expression<Func<T, bool>> whereExpression)
{
try
{
return await Db.Queryable<T>().Where(whereExpression).CountAsync();
}
catch (Exception ex)
{
_logger.LogError(ex, "统计实体数量失败");
throw;
}
}
#endregion
}
}
💼 实战应用:看看效果如何
分页模型定义
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppSQLBaseRepository
{
/// <summary>
/// 分页请求模型
/// </summary>
publicclass PageModel
{
publicint PageIndex { get; set; } = 1;
publicint PageSize { get; set; } = 10;
}
/// <summary>
/// 分页结果模型
/// </summary>
publicclass PageResult<T>
{
publicint PageIndex { get; set; }
publicint PageSize { get; set; }
publicint TotalCount { get; set; }
public List<T> Data { get; set; }
/// <summary>
/// 总页数
/// </summary>
publicint TotalPages => (int)Math.Ceiling((double)TotalCount / PageSize);
}
}
业务层使用示例
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AppSQLBaseRepository
{
publicclass UserService
{
private readonly IBaseRepository<User> _userRepository;
public UserService(IBaseRepository<User> userRepository)
{
_userRepository = userRepository;
}
/// <summary>
/// 获取活跃用户列表 - 一行代码搞定!
/// </summary>
public async Task<List<User>> GetActiveUsersAsync()
{
return await _userRepository.GetListAsync(
user => user.Status == 1 && user.IsDeleted == false);
}
/// <summary>
/// 分页获取用户 - 企业级应用标配
/// </summary>
public async Task<PageResult<User>> GetUsersPageAsync(PageModel pageModel)
{
return await _userRepository.GetPageListAsync(
user => user.IsDeleted == false,
pageModel);
}
/// <summary>
/// 批量导入用户 - 性能优化实践
/// </summary>
public async Task<bool> BatchImportUsersAsync(List<User> users)
{
return await _userRepository.AddRangeAsync(users);
}
/// <summary>
/// 逻辑删除用户 - 数据安全第一
/// </summary>
public async Task<bool> SoftDeleteUserAsync(User user)
{
return await _userRepository.FakeDeleteAsync(user, entity =>
{
entity.IsDeleted = true;
entity.DeleteTime = DateTime.Now;
entity.DeleteBy = "System";
});
}
}
}
⚡ 依赖注入配置
在Program.cs
或Startup.cs
中注册服务:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SqlSugar;
namespace AppSQLBaseRepository
{
internal class Program
{
static async Task Main(string[] args)
{
// 服务容器
var services = new ServiceCollection();
// 添加日志服务
services.AddLogging(builder =>
{
builder.AddConsole();
builder.SetMinimumLevel(LogLevel.Information);
});
// 注册SqlSugar
services.AddSingleton<ISqlSugarClient>(provider =>
{
returnnew SqlSugarClient(new ConnectionConfig
{
ConnectionString = "Server=localhost;Database=dbtest;User Id=sa;Password=123;TrustServerCertificate=true;", // 应从配置文件读取
DbType = DbType.SqlServer,
IsAutoCloseConnection = true
});
});
// 注册泛型仓储
services.AddScoped(typeof(IBaseRepository<>), typeof(BaseRepository<>));
// 注册业务服务
services.AddScoped<UserService>();
// 构建服务提供者
var serviceProvider = services.BuildServiceProvider();
// 实际使用UserService
using (var scope = serviceProvider.CreateScope())
{
var userService = scope.ServiceProvider.GetRequiredService<UserService>();
// 调用 userService 方法
var list = await userService.GetUsersPageAsync(new PageModel { PageIndex = 1, PageSize = 10 });
foreach (var item in list.Data)
{
Console.WriteLine(item.UserName);
Console.WriteLine(item.Email);
Console.WriteLine(item.PhoneNumber);
Console.WriteLine(item.RealName);
}
}
}
}
}
🎯 进阶技巧与最佳实践
1. 性能优化建议
// ✅ 推荐:使用批量操作
await _repository.AddRangeAsync(largeUserList);
// ❌ 避免:循环单条操作
foreach(var user in largeUserList)
{
await _repository.AddAsync(user); // 性能杀手!
}
2. 常见坑点提醒
⚠️ 注意事项:
始终使用异步方法,提升应用吞吐量
大数据量操作时优先考虑批量方法
生产环境记得关闭SQL日志输出
合理使用表达式树,避免过于复杂的Lambda表达式
3. 扩展性设计
// 🔥 金句:如果需要特殊业务逻辑,继承BaseRepository即可
public class UserRepository : BaseRepository<User>, IUserRepository
{
public UserRepository(ISqlSugarClient client, ILogger<UserRepository> logger)
: base(client, logger) { }
// 添加用户特有的业务方法
public async Task<List<User>> GetUsersByDepartmentAsync(int departmentId)
{
return await Db.Queryable<User>()
.Where(u => u.DepartmentId == departmentId)
.OrderBy(u => u.CreateTime)
.ToListAsync();
}
}
🎊 总结:三大核心收益
通过实施这套泛型仓储模式,你将获得:
📈 开发效率提升80%
告别重复代码,专注业务逻辑
🛡️ 代码质量飞跃
统一的数据访问模式,降低bug率
🚀 维护成本骤降
一处修改,全局生效,扩展性极强
收藏级代码模板已经为你准备好了! 这套方案已在多个企业级项目中验证,能够显著提升团队的开发效率和代码质量。
💬 互动讨论
你在项目中是如何处理数据访问层重复代码问题的?
对于这套泛型仓储模式,你觉得还有哪些可以优化的地方?
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 Jokerwoo
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果