using Cowain.Base.DBContext; using Microsoft.EntityFrameworkCore; using MySqlConnector; using System.Data; using System.Linq.Expressions; using Dapper; using Cowain.Base.IServices; namespace Cowain.Base.Services; public class BaseService : IBaseService { // 替换为 IDbContextFactory protected readonly IDbContextFactory _dbContextFactory; public BaseService(IDbContextFactory dbContextFactory) { _dbContextFactory = dbContextFactory; } /// /// 根据ID删除实体 /// public int Delete(int Id) where T : class { // 每次操作创建独立上下文,using 自动释放 using var dbContext = _dbContextFactory.CreateDbContext(); T? t = dbContext.Set().Find(Id); if (t == null) throw new KeyNotFoundException($"未找到类型 {typeof(T).Name},Id={Id}"); dbContext.Set().Remove(t); return dbContext.SaveChanges(); } /// /// 根据ID异步删除实体(支持取消) /// public async Task DeleteAsync(int Id, CancellationToken cancellationToken = default) where T : class { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); var t = await dbContext.Set().FindAsync(Id, cancellationToken).ConfigureAwait(false); if (t == null) throw new KeyNotFoundException($"未找到类型 {typeof(T).Name},Id={Id}"); dbContext.Set().Remove(t); return await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } /// /// 删除实体 /// public int Delete(T t) where T : class { ArgumentNullException.ThrowIfNull(t); using var dbContext = _dbContextFactory.CreateDbContext(); var entry = dbContext.Entry(t); if (entry.State == EntityState.Detached) { dbContext.Set().Attach(t); } dbContext.Set().Remove(t); return dbContext.SaveChanges(); } /// /// 删除实体(异步,支持取消) /// public async Task DeleteAsync(T t, CancellationToken cancellationToken = default) where T : class { ArgumentNullException.ThrowIfNull(t); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); var entry = dbContext.Entry(t); if (entry.State == EntityState.Detached) { dbContext.Set().Attach(t); } dbContext.Set().Remove(t); return await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } /// /// 批量读取实体 /// public List Find() where T : class { using var dbContext = _dbContextFactory.CreateDbContext(); return dbContext.Set().ToList(); } /// /// 异步、安全的批量读取(支持取消) /// public async Task> FindAsync(CancellationToken cancellationToken = default) where T : class { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); return await dbContext.Set().ToListAsync(cancellationToken).ConfigureAwait(false); } /// /// 根据ID查询实体 /// public T? Find(int id) where T : class { using var dbContext = _dbContextFactory.CreateDbContext(); return dbContext.Set().Find(id); } /// /// 根据ID异步查询实体(支持取消) /// public async Task FindAsync(int id, CancellationToken cancellationToken = default) where T : class { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); return await dbContext.Set().FindAsync(new object[] { id }, cancellationToken).ConfigureAwait(false); } /// /// 带表达式的异步查询(支持取消) /// public async Task FirstOrDefaultAsync(Expression> funcWhere, CancellationToken cancellationToken = default) where T : class { using var dbContext = _dbContextFactory.CreateDbContext(); return await dbContext.Set().Where(funcWhere).FirstOrDefaultAsync(cancellationToken); } /// /// 插入实体 /// public int Insert(T t) where T : class { ArgumentNullException.ThrowIfNull(t); using var dbContext = _dbContextFactory.CreateDbContext(); dbContext.Set().Add(t); return dbContext.SaveChanges(); } /// /// 异步插入实体 /// public async Task InsertAsync(T t, CancellationToken cancellationToken = default) where T : class { ArgumentNullException.ThrowIfNull(t); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); dbContext.Set().Add(t); return await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } /// /// 批量插入实体 /// public int Insert(IEnumerable tList) where T : class { using var dbContext = _dbContextFactory.CreateDbContext(); dbContext.Set().AddRange(tList); return dbContext.SaveChanges(); } /// /// 批量异步插入实体 /// public async Task InsertAsync(IEnumerable tList, CancellationToken cancellationToken = default) where T : class { await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); dbContext.Set().AddRange(tList); return await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } /// /// 带表达式的查询 /// public List Query(Expression>? funcWhere = null) where T : class { // 注意:Query 返回 IQueryable 时,上下文生命周期需由调用方管理,或改为立即执行(ToList/First 等) var dbContext = _dbContextFactory.CreateDbContext(); IQueryable query = dbContext.Set(); if (funcWhere is not null) { query = query.Where(funcWhere); } return query.ToList(); } /// /// 带表达式的异步查询(支持取消、空条件查全部) /// public async Task> QueryAsync( Expression>? funcWhere = null, // 设置默认值,调用更便捷 CancellationToken cancellationToken = default) where T : class { using var dbContext = _dbContextFactory.CreateDbContext(); IQueryable query = dbContext.Set(); if (funcWhere is not null) { query = query.Where(funcWhere); } return await query.ToListAsync(cancellationToken); } /// /// 基础版:返回实体列表+总条数(无投影) /// public async Task<(List Data, int TotalCount)> QueryAsync( Expression>? funcWhere = null, Expression>? orderBy = null, bool isAscending = true, int pageIndex = 1, int pageSize = 20, CancellationToken cancellationToken = default) where T : class { pageIndex = pageIndex < 1 ? 1 : pageIndex; pageSize = pageSize < 0 ? 0 : pageSize; using var dbContext = _dbContextFactory.CreateDbContext(); IQueryable query = dbContext.Set(); if (funcWhere is not null) query = query.Where(funcWhere); if (orderBy is not null) query = isAscending ? query.OrderBy(orderBy) : query.OrderByDescending(orderBy); if (pageSize > 0) { long totalCountLong = await query.LongCountAsync(cancellationToken); int totalCount = (int)Math.Min(totalCountLong, int.MaxValue); var data = await query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToListAsync(cancellationToken); return (data, totalCount); } else { var data = await query.ToListAsync(cancellationToken); return (data, data.Count); } } /// /// 增强版:支持投影(Select映射),直接返回ViewModel列表+总条数 /// /// 原实体类型 /// 排序字段类型 /// 目标ViewModel类型 /// 投影表达式(EF会解析为SQL的SELECT字段) public async Task<(List Data, int TotalCount)> QueryAsync( Expression> selectExpression, // 新增:投影映射表达式 Expression>? funcWhere = null, Expression>? orderBy = null, bool isAscending = true, int pageIndex = 1, int pageSize = 20, CancellationToken cancellationToken = default) where T : class { pageIndex = pageIndex < 1 ? 1 : pageIndex; pageSize = pageSize < 0 ? 0 : pageSize; using var dbContext = _dbContextFactory.CreateDbContext(); IQueryable query = dbContext.Set(); // 1. 过滤 if (funcWhere is not null) query = query.Where(funcWhere); // 2. 排序 if (orderBy is not null) query = isAscending ? query.OrderBy(orderBy) : query.OrderByDescending(orderBy); // 3. 先查总条数(注意:总条数要在投影前查,避免投影影响计数) long totalCountLong = await query.LongCountAsync(cancellationToken); int totalCount = (int)Math.Min(totalCountLong, int.MaxValue); // 4. 分页+投影(EF会转换为SQL:SELECT Id, Name, LayOutX, LayOutY FROM ... LIMIT ...) IQueryable viewModelQuery = query .Skip((pageIndex - 1) * pageSize) .Take(pageSize) .Select(selectExpression); // 内置投影,替代手动Select // 5. 转为List var data = await viewModelQuery.ToListAsync(cancellationToken); return (data, totalCount); } /// /// 更新实体 /// public int Update(T t) where T : class { ArgumentNullException.ThrowIfNull(t); using var dbContext = _dbContextFactory.CreateDbContext(); var entry = dbContext.Entry(t); if (entry.State == EntityState.Detached) { dbContext.Set().Attach(t); } dbContext.Entry(t).State = EntityState.Modified; return dbContext.SaveChanges(); } /// /// 异步更新实体(支持取消) /// public async Task UpdateAsync(T t, CancellationToken cancellationToken = default) where T : class { ArgumentNullException.ThrowIfNull(t); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); var entry = dbContext.Entry(t); if (entry.State == EntityState.Detached) { dbContext.Set().Attach(t); } dbContext.Entry(t).State = EntityState.Modified; return await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } /// /// 批量更新实体 /// public int Update(IEnumerable tList) where T : class { ArgumentNullException.ThrowIfNull(tList); var list = tList as IList ?? tList.ToList(); if (list.Count == 0) return 0; using var dbContext = _dbContextFactory.CreateDbContext(); dbContext.Set().UpdateRange(list); return dbContext.SaveChanges(); } /// /// 异步批量更新实体(支持取消) /// public async Task UpdateAsync(IEnumerable tList, CancellationToken cancellationToken = default) where T : class { ArgumentNullException.ThrowIfNull(tList); var list = tList as IList ?? tList.ToList(); if (list.Count == 0) return 0; await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); dbContext.Set().UpdateRange(list); return await dbContext.SaveChangesAsync(cancellationToken).ConfigureAwait(false); } /// /// 使用sql语句获取DataTable /// public DataTable GetDataTable(string sql, IEnumerable? parameters = null) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); // 从工厂创建上下文获取连接字符串 using var dbContext = _dbContextFactory.CreateDbContext(); using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); using var cmd = new MySqlCommand(sql, conn) { CommandType = CommandType.Text }; if (parameters != null) { foreach (var p in parameters) cmd.Parameters.Add(p); } using var adapter = new MySqlDataAdapter(cmd); var table = new DataTable(); adapter.Fill(table); return table; } /// /// 异步使用sql语句获取DataTable(支持取消) /// public async Task GetDataTableAsync(string sql, IEnumerable? parameters = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); await using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); await conn.OpenAsync(cancellationToken).ConfigureAwait(false); using var cmd = new MySqlCommand(sql, conn) { CommandType = CommandType.Text }; if (parameters != null) cmd.Parameters.AddRange(parameters.ToArray()); using var reader = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false); var table = new DataTable(); table.Load(reader); return table; } // ================= Dapper 辅助方法 ================= /// /// 使用 Dapper 查询并映射到 POCO(同步) /// public IEnumerable QueryByDapper(string sql, object? param = null) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); using var dbContext = _dbContextFactory.CreateDbContext(); using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); conn.Open(); return conn.Query(sql, param); } /// /// 使用 Dapper 查询并映射到 POCO(异步,支持 CancellationToken) /// public async Task> QueryByDapperAsync(string sql, object? param = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); await using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); await conn.OpenAsync(cancellationToken).ConfigureAwait(false); var command = new CommandDefinition(sql, param, cancellationToken: cancellationToken); var result = await conn.QueryAsync(command).ConfigureAwait(false); return result; } /// /// 使用 Dapper 查询单条记录(同步) /// public T? QueryFirstOrDefaultByDapper(string sql, object? param = null) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); using var dbContext = _dbContextFactory.CreateDbContext(); using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); conn.Open(); return conn.QueryFirstOrDefault(sql, param); } /// /// 使用 Dapper 查询单条记录(异步) /// public async Task QueryFirstOrDefaultByDapperAsync(string sql, object? param = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); await using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); await conn.OpenAsync(cancellationToken).ConfigureAwait(false); var command = new CommandDefinition(sql, param, cancellationToken: cancellationToken); return await conn.QueryFirstOrDefaultAsync(command).ConfigureAwait(false); } /// /// 使用 Dapper 执行非查询 SQL(同步),返回受影响行数 /// public int ExecuteByDapper(string sql, object? param = null) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); using var dbContext = _dbContextFactory.CreateDbContext(); using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); conn.Open(); return conn.Execute(sql, param); } /// /// 使用 Dapper 执行非查询 SQL(异步),返回受影响行数 /// public async Task ExecuteByDapperAsync(string sql, object? param = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); await using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); await conn.OpenAsync(cancellationToken).ConfigureAwait(false); var command = new CommandDefinition(sql, param, cancellationToken: cancellationToken); return await conn.ExecuteAsync(command).ConfigureAwait(false); } /// /// 使用 Dapper 执行 SQL 并返回 DataTable(异步,支持 CancellationToken) /// public async Task QueryToDataTableByDapperAsync(string sql, object? param = null, CancellationToken cancellationToken = default) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false); await using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); await conn.OpenAsync(cancellationToken).ConfigureAwait(false); var command = new CommandDefinition(sql, param, cancellationToken: cancellationToken, flags: CommandFlags.Buffered); await using var reader = await conn.ExecuteReaderAsync(command).ConfigureAwait(false); var table = new DataTable(); table.Load(reader); return table; } /// /// 使用 Dapper 执行 SQL 并返回 DataTable(同步) /// public DataTable QueryToDataTableByDapper(string sql, object? param = null) { if (string.IsNullOrWhiteSpace(sql)) throw new ArgumentException("sql 不能为空", nameof(sql)); using var dbContext = _dbContextFactory.CreateDbContext(); using var conn = new MySqlConnection(dbContext.Database.GetConnectionString()); conn.Open(); using var reader = conn.ExecuteReader(sql, param); var table = new DataTable(); table.Load(reader); return table; } }