LTY.SqlStroreHelper
1.0.8
dotnet add package LTY.SqlStroreHelper --version 1.0.8
NuGet\Install-Package LTY.SqlStroreHelper -Version 1.0.8
<PackageReference Include="LTY.SqlStroreHelper" Version="1.0.8" />
<PackageVersion Include="LTY.SqlStroreHelper" Version="1.0.8" />
<PackageReference Include="LTY.SqlStroreHelper" />
paket add LTY.SqlStroreHelper --version 1.0.8
#r "nuget: LTY.SqlStroreHelper, 1.0.8"
#:package LTY.SqlStroreHelper@1.0.8
#addin nuget:?package=LTY.SqlStroreHelper&version=1.0.8
#tool nuget:?package=LTY.SqlStroreHelper&version=1.0.8
LTY.SqlStroreHelper
基于 Microsoft.Data.SqlClient 的 SQL Server 数据访问工具库,提供仓储基类、DbConnection / DbContext 扩展方法、存储过程参数自动发现与缓存、DbDataReader 到实体的表达式树映射等能力,支持 .NET 8。
// Program.cs 多库注入连接的方法 builder.Services.AddKeyedSingleton<IDataReaderService>("Main", (sp, _) ⇒ new DataReaderService(builder.Configuration)); builder.Services.AddKeyedSingleton<IDataReaderService>("Backup", (sp, _) ⇒ new DataReaderService(builder.Configuration, "BackupDb"));
// Controller public class SyncController( [FromKeyedServices("Main")] IDataReaderService mainDb, [FromKeyedServices("Backup")] IDataReaderService backupDb) { public async Task<IActionResult> Sync() { var list = await mainDb.ExecuteReaderAsync<Customer>("SELECT * FROM Customers"); foreach (var c in list) await backupDb.ExecuteNonQueryAsync( "INSERT INTO Customers VALUES (@Name, @Phone)", c.Name, c.Phone); return Ok(); } }
这三个是 .NET DI 容器的 服务生命周期(Service Lifetime) 注册方式,核心区别是 实例存活多久、被创建几次、谁共享 。
一句话类比
方法 类比 实例数 AddTransient 一次性纸杯 —— 谁用谁拿新的,用完就扔 每次注入都 new AddScoped 同一个会议期间的矿泉水 —— 一场会议(一次 HTTP 请求)内大家共用一瓶,散会扔掉 每个请求 1 个 AddSingleton 办公室饮水机 —— 全公司(整个应用)共用一台,公司关门才撤 整个应用 1 个
可与 Dapper 互补使用
//笔记 //必须返回字符串 [Produces("text/plain")]
[Produces("application/xml")] [Produces("application/json")] [HttpGet("json")] public IEnumerable<WeatherForecast> json() { return GetWeatherForecast(); }
目录
安装
dotnet add package LTY.SqlStroreHelper
或 Packages.config / PackageReference:
<PackageReference Include="LTY.SqlStroreHelper" Version="1.0.0" />
依赖:Microsoft.Data.SqlClient、Microsoft.EntityFrameworkCore.Relational、Microsoft.Extensions.Configuration.Json、Newtonsoft.Json。
命名空间一览
统一根命名空间为 LTY.SqlStroreHelper,按职责划分子命名空间:
| 命名空间 | 说明 |
|---|---|
LTY.SqlStroreHelper.Data |
特性(Column / Ignore / Key)、DataReaderExtensions、StoredProcedureMapper、StoredProcedureParamCache、StoredProcedureResult |
LTY.SqlStroreHelper.Services |
RepositoryBase / RepositoryBase<T>、DbConnectionExtensions、EfRepositoryExtensions、DataReaderService / IDataReaderService、SQLDBOperator、MappingCache<T> |
LTY.SqlStroreHelper.Utils |
Converter(JSON 日期转换器)、Tools(MD5 工具) |
快速开始
using LTY.SqlStroreHelper.Data;
using LTY.SqlStroreHelper.Services;
using Microsoft.Data.SqlClient;
var conn = new SqlConnection("Server=.;Database=Demo;Trusted_Connection=True;TrustServerCertificate=True;");
// 1) SQL 查询 -> 实体列表
var list = await conn.ExecuteReaderAsync<User>("SELECT * FROM Users");
// 2) 执行存储过程并自动缓存参数(从实体赋值)
var result = await conn.ExecuteStoredProcedureWithCacheAsync<User, UserParam>(
"sp_GetUser", new UserParam { UserId = 1001 });
API 文档
仓储基类 RepositoryBase / RepositoryBase<T>
LTY.SqlStroreHelper.Services.RepositoryBase(实例方法封装)与泛型版本 RepositoryBase<T>(自动 CRUD)。
构造:RepositoryBase(IConfiguration) 或 RepositoryBase(string connectionString)。
| 方法 | 说明 |
|---|---|
ExecuteReaderAsync<T>(sql, params object[] parameters) |
SQL → 实体列表 |
ExecuteReaderSingleAsync<T>(sql, params object[] parameters) |
SQL → 单个实体 |
ExecuteScalarAsync<T>(sql, params object[] parameters) |
返回标量 |
ExecuteNonQueryAsync(sql, params object[] parameters) |
增删改,返回影响行数 |
ExecuteStoredProcedureAsync(procedureName, params SqlParameter[] parameters) |
执行存储过程(手动参数) |
ExecuteStoredProcedureAsync<T>(procedureName, params SqlParameter[] parameters) |
执行存储过程并映射 |
ExecuteStoredProcedureDataSetAsync(procedureName, params SqlParameter[] parameters) |
多结果集 → DataSet |
ExecuteStoredProcedureDataTableAsync(procedureName, params SqlParameter[] parameters) |
→ DataTable |
ExecuteStoredProcedureScalarAsync<T>(procedureName, params SqlParameter[] parameters) |
存储过程标量 |
ExecuteStoredProcedureWithCacheAsync<TParams>(procedureName, paramEntity) |
自动发现并缓存参数,从实体赋值 |
ExecuteStoredProcedureWithCacheAsync<T, TParams>(procedureName, paramEntity) |
同上并映射结果 |
ExecuteStoredProcedureWithCacheAsync(procedureName, Dictionary<string,object?>) |
从字典赋值 |
AssignParameterValuesFromEntity<T>(SqlParameter[], T) |
从实体给参数赋值 |
AssignParameterValuesFromDict(SqlParameter[], Dictionary<string,object?>) |
从字典给参数赋值 |
泛型 RepositoryBase<T> 额外提供:GetAllAsync()、GetByIdAsync(int)、InsertAsync(T)、UpdateAsync(T)、DeleteAsync(int),表名/列名分别由 [Table] / [Column] 特性控制。
DbConnection 扩展方法
LTY.SqlStroreHelper.Services.DbConnectionExtensions,对 DbConnection / DbConnection 实例扩展,方法签名与仓储基类对应(静态扩展形式):
ExecuteNonQuery/ExecuteNonQueryAsyncExecuteReaderAsync<T>/ExecuteReaderSingleAsync<T>/ExecuteScalarAsync<T>ExecuteReaderManualAsync<T>/ExecuteScalarManualAsync<T>(手动映射)ExecuteCacheReaderAsync<T>/ExecuteCacheReaderSingleAsync<T>(缓存映射)ExecuteStoredProcedureAsync/ExecuteStoredProcedureAsync<T>ExecuteStoredProcedureDataSetAsync/ExecuteStoredProcedureDataTableAsyncExecuteStoredProcedureScalarAsync<T>ExecuteStoredProcedureWithCacheAsync<TParams>/ExecuteStoredProcedureWithCacheAsync<T, TParams>/ 字典重载DiscoverSpParameters/GetSpParameterList/GetSpParameters(参数发现与缓存)AssignParameterValuesFromEntity/AssignParameterValuesFromDataRow/AssignParameterValuesFromDict
DbContext 扩展方法(EF Core)
LTY.SqlStroreHelper.Services.EfRepositoryExtensions,对 DbContext 扩展,内部复用 DbConnection 扩展:
ExecuteStoredProcedureAsync/ExecuteStoredProcedureAsync<T>/ExecuteStoredProcedureDataSetAsyncExecuteStoredProcedureWithCacheAsync<TParams>/ExecuteStoredProcedureWithCacheAsync<T, TParams>/ 字典重载ExecuteReaderAsync<T>/ExecuteReaderSingleAsync<T>/ExecuteScalarAsync<T>/ExecuteNonQueryAsyncExecuteInTransactionAsync(自动事务生命周期)- 事务重载:
ExecuteStoredProcedureAsync(transaction, ...)、ExecuteStoredProcedureAsync<T>(transaction, ...)、ExecuteNonQueryAsync(transaction, ...)、ExecuteReaderAsync<T>(transaction, ...)
数据读取服务 IDataReaderService
LTY.SqlStroreHelper.Services.IDataReaderService 与实现 DataReaderService,封装 SQL 与存储过程执行,支持自动事务管理。构造方式:DataReaderService(IConfiguration)。
核心方法:ExecuteReaderAsync<T>、ExecuteReaderSingleAsync<T>、ExecuteScalarAsync<T>、ExecuteNonQueryAsync、ExecuteStoredProcedureAsync(手动参数)/ ExecuteStoredProcedureFromEntityAsync(实体,FromEntity 后缀避免与 params object[] 重载歧义)/ 字典重载、ExecuteStoredProcedureDataSetAsync / ExecuteStoredProcedureDataSetFromEntityAsync、ExecuteStoredProcedureDataTableAsync / ExecuteStoredProcedureDataTableFromEntityAsync、ExecuteInTransactionAsync(含事务内查询 / 存储过程重载)。
SQLDBOperator 旧版操作类
LTY.SqlStroreHelper.Services.SQLDBOperator,同步 API 的旧版数据库操作类,适合迁移自老项目。
主要方法:Open / Close / BeginTransaction / CommitTransaction / RollbackTransaction,SetCmd / CreateCmd,ReturnDataReader / ReturnDataSet / ReturnDataTable,ReturnValue / ReturnValues,RunProc / RunProcScalar / RunProcReturnDatatable / RunProcReturnDataSet,ExecuteOutputArray / ExecuteArray,DiscoverSpParameters / GetSpParameterList,MakeInParam / MakeOutParam / MakeParam。静态构造函数从 appsettings.Production.json 读取 SqlServer / DataConnection 连接串。
实体映射 MappingCache / DataReaderExtensions
LTY.SqlStroreHelper.Services.MappingCache<T>:基于表达式树编译的映射器,支持[Column]重命名、[Ignore]跳过、自动过滤导航/集合属性、Nullable<T>与枚举。LTY.SqlStroreHelper.Data.DataReaderExtensions:ToListAsync<T>()/ToSingleAsync<T>(),列名匹配支持大小写不敏感、驼峰/下划线互转;ToJArrayAsync()/ToJsonStringAsync()直接将DbDataReader转为 JSON 数据结构(DBNull→null,byte[]→ Base64 字符串)。
存储过程映射 StoredProcedureMapper
LTY.SqlStroreHelper.Data.StoredProcedureMapper:
CreateParamsFromEntity<T>(T entity, char paramPrefix = '@'):扫描实体属性生成SqlParameter[],自动推断SqlDbType(含string的 Size、decimal的 Precision/Scale)。CreateOutputParam(name, SqlDbType, size):创建输出参数。CreateReturnParam():创建@RETURN_VALUE返回值参数。
特性 ColumnAttribute / IgnoreAttribute / KeyAttribute
LTY.SqlStroreHelper.Data:
[Column(name)]:指定属性对应的数据库列名/参数名。[Ignore]:忽略该属性的映射。[Key]:标记主键。
结果对象 StoredProcedureResult
LTY.SqlStroreHelper.Data.StoredProcedureResult:ReturnValue、OutputParameters(Dictionary<string,object?>)、RowsAffected。
StoredProcedureResult<T>:继承前者并增加 Data(单条)与 DataList(列表)。
工具类 Converter / Tools
LTY.SqlStroreHelper.Utils:
CustomDateTimeConverter/CustomDateConverter:Newtonsoft.Json 日期格式转换器(yyyy-MM-dd HH:mm:ss/yyyy-MM-dd)。Tools.GetCrypt(Stream)/Tools.GetCryptFromBytes(byte[]):MD5 计算。
调用示例
完整可运行示例见
samples/LTY.SqlStroreHelper.Samples项目。
1) 自定义仓储继承 RepositoryBase<T>
using LTY.SqlStroreHelper.Data;
using LTY.SqlStroreHelper.Services;
using Microsoft.Extensions.Configuration;
public class Customer
{
public int Id { get; set; }
public string CustomerName { get; set; } = string.Empty;
public string Phone { get; set; } = string.Empty;
public string? Address { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.Now;
}
public class CustomerRepository : RepositoryBase<Customer>
{
public CustomerRepository(IConfiguration cfg) : base(cfg) { }
public Task<List<Customer>> GetByNameAsync(string name) =>
ExecuteReaderAsync<Customer>(
"SELECT * FROM Customers WHERE CustomerName LIKE @Name",
new Microsoft.Data.SqlClient.SqlParameter("@Name", $"%{name}%"));
public Task<StoredProcedureResult<Customer>> GetDetailsAsync(int id)
{
var dict = new Dictionary<string, object?> { { "CustomerId", id } };
return ExecuteStoredProcedureWithCacheAsync<Customer>("sp_GetCustomerDetails", dict);
}
}
2) DbConnection 扩展方法 + 参数缓存
using LTY.SqlStroreHelper.Services;
await using var conn = new Microsoft.Data.SqlClient.SqlConnection(connectionString);
await conn.OpenAsync();
// 自动发现参数并缓存,从字典赋值
var result = await conn.ExecuteStoredProcedureWithCacheAsync<OrderItem>(
"sp_GetOrderItems", new Dictionary<string, object?> { { "OrderId", 88 } });
foreach (var item in result.DataList)
Console.WriteLine($"{item.ProductName} x {item.Qty}");
// 多结果集
DataSet ds = await conn.ExecuteStoredProcedureDataSetAsync("sp_GetOrderFull", new SqlParameter("@OrderId", 88));
3) EF Core DbContext 扩展
using LTY.SqlStroreHelper.Services;
public class OrderRepo
{
private readonly ShopDbContext _db;
public OrderRepo(ShopDbContext db) => _db = db;
public Task<List<Order>> TopNAsync(int n) =>
_db.ExecuteReaderAsync<Order>("SELECT TOP (@N) * FROM Orders ORDER BY Id DESC",
new SqlParameter("@N", n));
public Task ExecuteInTxAsync() =>
_db.ExecuteInTransactionAsync(async () =>
{
await _db.ExecuteNonQueryAsync("UPDATE Orders SET Status=1 WHERE Id=@Id", new SqlParameter("@Id", 5));
await _db.ExecuteStoredProcedureAsync("sp_Audit", new SqlParameter("@Type", "Ship"));
});
}
4) IDataReaderService(可注入)
IDataReaderService 是一个面向服务层的统一数据访问接口,实现类为 DataReaderService,通过 IConfiguration 注入(默认读取 DefaultConnection)。它的方法按「基础查询 / 事务 / 存储过程(手动参数·实体·字典)」三大类组织,下面逐一演示。
4.1 实例化
using LTY.SqlStroreHelper.Services;
using Microsoft.Extensions.Configuration;
var svc = new DataReaderService(config);
4.2 基础查询
// 查询 -> 列表
List<Customer> all = await svc.ExecuteReaderAsync<Customer>("SELECT * FROM Customers");
// 分页查询
var page = await svc.ExecuteReaderAsync<Customer>(
"SELECT * FROM Customers ORDER BY Id OFFSET @Offset ROWS FETCH NEXT @PageSize ROWS ONLY",
new SqlParameter("@Offset", 0),
new SqlParameter("@PageSize", 20));
// 查询 -> 单个对象(无数据返回 null)
Customer? one = await svc.ExecuteReaderSingleAsync<Customer>(
"SELECT * FROM Customers WHERE Id = @Id", new SqlParameter("@Id", 1));
// 标量值(值类型直接接收;引用类型用 ? 判空)
int count = await svc.ExecuteScalarAsync<int>("SELECT COUNT(*) FROM Customers");
decimal total = await svc.ExecuteScalarAsync<decimal>("SELECT SUM(Amount) FROM Orders WHERE CustomerId=@Id",
new SqlParameter("@Id", 1));
// 非查询(增删改),返回影响行数
int affected = await svc.ExecuteNonQueryAsync(
"UPDATE Customers SET Phone = @Phone WHERE Id = @Id",
new SqlParameter("@Phone", "13900000000"),
new SqlParameter("@Id", 1));
4.3 事务
ExecuteInTransactionAsync 自动管理连接开启、事务提交/回滚;在回调内拿到 IDbTransaction 后,可使用事务版的各重载方法。
// 有返回值的事务
bool ok = await svc.ExecuteInTransactionAsync(async (tx) =>
{
// 事务内执行非查询
await svc.ExecuteNonQueryAsync(tx,
"UPDATE Accounts SET Balance = Balance - 100 WHERE Id = @From",
new SqlParameter("@From", 1));
await svc.ExecuteNonQueryAsync(tx,
"UPDATE Accounts SET Balance = Balance + 100 WHERE Id = @To",
new SqlParameter("@To", 2));
// 事务内查询
var from = await svc.ExecuteReaderSingleAsync<Account>(tx,
"SELECT * FROM Accounts WHERE Id = @Id", new SqlParameter("@Id", 1));
// 事务内执行存储过程(直接传值,无返回值)
await svc.ExecuteStoredProcedureAsync(tx,
"sp_WriteTransferLog", 1, 2, 100m);
return from?.Balance >= 0; // 返回 false 不会回滚;抛异常才回滚
});
// 无返回值的事务
await svc.ExecuteInTransactionAsync(async (tx) =>
{
await svc.ExecuteNonQueryAsync(tx, "DELETE FROM Cart WHERE CustomerId = @Id",
new SqlParameter("@Id", 1));
// 事务内存储过程并映射结果(直接传值)
var items = await svc.ExecuteStoredProcedureAsync<CartItem>(tx, "sp_GetCart", 1);
}, IsolationLevel.Serializable);
回调内抛出异常会自动回滚;正常返回则自动提交。
4.4 存储过程 — 手动参数
支持直接传值(无需 SqlParameter 包裹)、SqlParameter、以及两者混用。直接传值时,框架会按存储过程参数声明顺序(仅 Input/InputOutput 方向)自动匹配占位符。
// 1) 直接传值(推荐,最简洁)— 无返回值,仅执行
await svc.ExecuteStoredProcedureAsync("sp_UpdateCustomer", 1, "张三");
// 映射到实体列表(直接传值)— 返回 List<T>
List<Customer> list = await svc.ExecuteStoredProcedureAsync<Customer>(
"sp_GetCustomersByLevel", "vip");
// 多结果集 -> DataSet(直接传值)
DataSet ds = await svc.ExecuteStoredProcedureDataSetAsync("sp_GetOrderFull", 88);
// 单结果集 -> DataTable(直接传值)
DataTable dt = await svc.ExecuteStoredProcedureDataTableAsync("sp_GetCustomers");
// 2) 仍兼容 SqlParameter 显式写法(需指定方向/类型时使用)
await svc.ExecuteStoredProcedureAsync(
"sp_UpdateCustomer",
new SqlParameter("@Id", 1),
new SqlParameter("@Name", "张三"));
// 3) 混用:SqlParameter + 裸值(SqlParameter 占用的参数名跳过,裸值按剩余顺序消费)
await svc.ExecuteStoredProcedureAsync("sp_UpdateCustomer",
new SqlParameter("@Id", 1), "张三");
返回类型:无泛型版返回
Task(仅执行);泛型版返回Task<List<T>>(结果列表)。DataSet/DataTable版不变。直接传值的匹配规则:框架通过
DeriveParameters已缓存存储过程的参数元数据;裸值按缓存中Input/InputOutput方向参数的声明顺序自动绑定到同名SqlParameter。Output/ReturnValue参数不会被裸值占用。
4.5 存储过程 — 实体参数
参数由框架自动发现并缓存,值按属性名匹配(支持 [Column] 重命名、驼峰/下划线互转)。
public class CreateCustomerParam
{
public string CustomerName { get; set; } = "";
public string Phone { get; set; } = "";
public string? Address { get; set; }
}
// 无返回(仅执行)
await svc.ExecuteStoredProcedureFromEntityAsync("sp_CreateCustomer", new CreateCustomerParam
{
CustomerName = "李四", Phone = "13800000000", Address = "上海"
});
// 映射结果 -> List<T>
List<Customer> r4 = await svc.ExecuteStoredProcedureFromEntityAsync<Customer, CreateCustomerParam>(
"sp_CreateCustomer", new CreateCustomerParam { CustomerName = "王五", Phone = "13700000000" });
// DataSet / DataTable
DataSet ds2 = await svc.ExecuteStoredProcedureDataSetFromEntityAsync("sp_GetReport", new CreateCustomerParam());
DataTable dt2 = await svc.ExecuteStoredProcedureDataTableFromEntityAsync("sp_GetReport", new CreateCustomerParam());
4.6 存储过程 — 字典参数
var dict = new Dictionary<string, object?>
{
{ "CustomerId", 1 },
{ "PageIndex", 1 },
{ "PageSize", 20 }
};
// 无返回(仅执行)
await svc.ExecuteStoredProcedureAsync("sp_GetCustomerDetails", dict);
// 映射结果 -> List<T>
List<Customer> r6 = await svc.ExecuteStoredProcedureAsync<Customer>("sp_GetCustomerDetails", dict);
DataSet ds3 = await svc.ExecuteStoredProcedureDataSetAsync("sp_GetCustomerDetails", dict);
DataTable dt3 = await svc.ExecuteStoredProcedureDataTableAsync("sp_GetCustomerDetails", dict);
三种存储过程调用方式均会自动发现并缓存参数:手动参数只负责覆盖值,参数元数据(类型、方向)由数据库
DeriveParameters获取并缓存;实体/字典方式按参数名自动赋值。
5) 实体特性映射
using LTY.SqlStroreHelper.Data;
using System.ComponentModel.DataAnnotations.Schema;
[Table("T_User")]
public class User
{
public int Id { get; set; }
[Column("user_name")]
public string UserName { get; set; } = string.Empty;
[Ignore]
public string TempField { get; set; } = string.Empty;
}
6) DbDataReader 直接转 JSON
using LTY.SqlStroreHelper.Data;
using Microsoft.Data.SqlClient;
await using var conn = new SqlConnection(connectionString);
await conn.OpenAsync();
using var command = conn.CreateCommand();
command.CommandText = "SELECT Id, Name, Score FROM Customers";
using var reader = await command.ExecuteReaderAsync();
// 方式一:返回 JArray(可直接操作的 JSON 数据结构)
Newtonsoft.Json.Linq.JArray jArray = await reader.ToJArrayAsync();
string name0 = jArray[0]["Name"]?.ToString() ?? "";
// 方式二:直接返回 JSON 字符串
string json = await reader.ToJsonStringAsync();
// 示例输出:[{"Id":1,"Name":"张三","Score":95.5},...]
DBNull自动转为null,byte[]自动转为 Base64 字符串。
appsettings 配置
RepositoryBase / DataReaderService 默认读取连接字符串名 DefaultConnection:
{
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database=Demo;Trusted_Connection=True;TrustServerCertificate=True;"
}
}
SQLDBOperator 静态构造读取 appsettings.Production.json 中的 ConnectionStrings:SqlServer / ConnectionStrings:DataConnection。
在 .NET 8 Web API / MVC 中注入使用
1. 安装 NuGet 包
dotnet add package LTY.SqlStroreHelper
2. appsettings.json 配置
{
"ConnectionStrings": {
"DefaultConnection": "Server=.;Database=Demo;Trusted_Connection=True;TrustServerCertificate=True;",
"BackupDb": "Server=.;Database=BackupDb;Trusted_Connection=True;TrustServerCertificate=True;"
},
"App": {
"DbSettings": {
"MainConn": "Server=.;Database=CustomDb;Trusted_Connection=True;TrustServerCertificate=True;"
}
}
}
3. Program.cs 注册服务
using LTY.SqlStroreHelper.Services;
var builder = WebApplication.CreateBuilder(args);
// === 方式 A:默认(从 ConnectionStrings:DefaultConnection 读取)
builder.Services.AddSingleton<IDataReaderService>(sp =>
new DataReaderService(builder.Configuration));
// === 方式 B:直接指定连接字符串
// builder.Services.AddSingleton<IDataReaderService>(_ =>
// new DataReaderService("Server=.;Database=Demo;Trusted_Connection=True;TrustServerCertificate=True;"));
// === 方式 C:从指定节点读取(如 ConnectionStrings:BackupDb)
// builder.Services.AddSingleton<IDataReaderService>(sp =>
// new DataReaderService(builder.Configuration, "BackupDb"));
// === 方式 D:从任意路径节点读取(如 App:DbSettings:MainConn)
// builder.Services.AddSingleton<IDataReaderService>(sp =>
// new DataReaderService(builder.Configuration, "App:DbSettings:MainConn"));
builder.Services.AddControllers();
var app = builder.Build();
app.MapControllers();
app.Run();
生命周期建议:
Singleton即可(内部 SqlConnection 是短连接,每次调用创建并释放;存储过程参数缓存也是线程安全的 ConcurrentDictionary)。若希望与请求生命周期绑定,也可用Scoped。
4. Controller 中使用
using LTY.SqlStroreHelper.Services;
[ApiController]
[Route("api/[controller]")]
public class CustomersController : ControllerBase
{
private readonly IDataReaderService _svc;
public CustomersController(IDataReaderService svc)
{
_svc = svc;
}
[HttpGet]
public async Task<ActionResult<List<Customer>>> GetAll()
=> await _svc.ExecuteReaderAsync<Customer>("SELECT * FROM Customers");
[HttpGet("{id}")]
public async Task<ActionResult<Customer?>> Get(int id)
=> await _svc.ExecuteReaderSingleAsync<Customer>(
"SELECT * FROM Customers WHERE Id=@Id", id);
[HttpPost]
public async Task<IActionResult> Create(Customer customer)
{
await _svc.ExecuteNonQueryAsync(
"INSERT INTO Customers (Name, Phone) VALUES (@Name, @Phone)",
customer.Name, customer.Phone);
return Ok();
}
[HttpGet("sp/{level}")]
public async Task<ActionResult<List<Customer>>> GetByLevel(string level)
=> await _svc.ExecuteStoredProcedureAsync<Customer>("sp_GetCustomersByLevel", level);
}
5. 运行时切换连接字符串
注入的实例可随时切换连接字符串(线程安全):
public class AdminController : ControllerBase
{
private readonly IDataReaderService _svc;
public AdminController(IDataReaderService svc) => _svc = svc;
[HttpPost("switch-to-backup")]
public IActionResult SwitchToBackup([FromServices] IConfiguration config)
{
_svc.UseConnectionStringFromConfig(config, "BackupDb");
return Ok(new { Current = _svc.CurrentConnectionString });
}
[HttpPost("switch-custom")]
public IActionResult SwitchCustom([FromBody] string connStr)
{
_svc.UseConnectionString(connStr);
return Ok();
}
}
6. 同时注册多个命名实例(多库场景)
// 主库(默认)
builder.Services.AddSingleton<IDataReaderService>(sp =>
new DataReaderService(builder.Configuration));
// 备库(通过工厂模式提供键值集合)
builder.Services.AddKeyedSingleton<IDataReaderService>("Backup",
(sp, _) => new DataReaderService(builder.Configuration, "BackupDb"));
// 使用时按键名解析
public class MultiDbController(IDataReaderService mainDb,
[FromKeyedServices("Backup")] IDataReaderService backupDb)
{
public async Task Sync()
{
var customers = await mainDb.ExecuteReaderAsync<Customer>("SELECT * FROM Customers");
// 写入备库
foreach (var c in customers)
await backupDb.ExecuteNonQueryAsync("INSERT INTO Customers VALUES (@Name, @Phone)",
c.Name, c.Phone);
}
}
版本
- 1.0.0:统一命名空间为
LTY.SqlStroreHelper,修复编译错误,补充调用文档与示例。
自动生成实体的 构造函数只依赖一个 Func<DbConnection> 连接工厂,所以配置连接 = 在 DI 里注册这个工厂
using Microsoft.Data.SqlClient; using System.Data.Common; using Dapper;
var builder = WebApplication.CreateBuilder(args);
// 注册连接工厂:每次调用 new 一个连接 builder.Services.AddTransient<Func<DbConnection>>(_ ⇒ () ⇒ new SqlConnection(builder.Configuration.GetConnectionString("Default")));
// 注册仓储 builder.Services.AddScoped<I档案药品Repository, 档案药品Repository>();
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Microsoft.Data.SqlClient (>= 7.0.2)
- Microsoft.EntityFrameworkCore (>= 8.0.0)
- Microsoft.EntityFrameworkCore.Relational (>= 8.0.0)
- Microsoft.Extensions.Configuration (>= 8.0.0)
- Microsoft.Extensions.Configuration.Json (>= 8.0.0)
- Newtonsoft.Json (>= 13.0.4)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
统一命名空间为 LTY.SqlStroreHelper,修复编译错误,补充调用文档与示例。