LTY.SqlStroreHelper 1.0.8

dotnet add package LTY.SqlStroreHelper --version 1.0.8
                    
NuGet\Install-Package LTY.SqlStroreHelper -Version 1.0.8
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="LTY.SqlStroreHelper" Version="1.0.8" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="LTY.SqlStroreHelper" Version="1.0.8" />
                    
Directory.Packages.props
<PackageReference Include="LTY.SqlStroreHelper" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add LTY.SqlStroreHelper --version 1.0.8
                    
#r "nuget: LTY.SqlStroreHelper, 1.0.8"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package LTY.SqlStroreHelper@1.0.8
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=LTY.SqlStroreHelper&version=1.0.8
                    
Install as a Cake Addin
#tool nuget:?package=LTY.SqlStroreHelper&version=1.0.8
                    
Install as a Cake Tool

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 / ExecuteNonQueryAsync
  • ExecuteReaderAsync<T> / ExecuteReaderSingleAsync<T> / ExecuteScalarAsync<T>
  • ExecuteReaderManualAsync<T> / ExecuteScalarManualAsync<T>(手动映射)
  • ExecuteCacheReaderAsync<T> / ExecuteCacheReaderSingleAsync<T>(缓存映射)
  • ExecuteStoredProcedureAsync / ExecuteStoredProcedureAsync<T>
  • ExecuteStoredProcedureDataSetAsync / ExecuteStoredProcedureDataTableAsync
  • ExecuteStoredProcedureScalarAsync<T>
  • ExecuteStoredProcedureWithCacheAsync<TParams> / ExecuteStoredProcedureWithCacheAsync<T, TParams> / 字典重载
  • DiscoverSpParameters / GetSpParameterList / GetSpParameters(参数发现与缓存)
  • AssignParameterValuesFromEntity / AssignParameterValuesFromDataRow / AssignParameterValuesFromDict

DbContext 扩展方法(EF Core)

LTY.SqlStroreHelper.Services.EfRepositoryExtensions,对 DbContext 扩展,内部复用 DbConnection 扩展:

  • ExecuteStoredProcedureAsync / ExecuteStoredProcedureAsync<T> / ExecuteStoredProcedureDataSetAsync
  • ExecuteStoredProcedureWithCacheAsync<TParams> / ExecuteStoredProcedureWithCacheAsync<T, TParams> / 字典重载
  • ExecuteReaderAsync<T> / ExecuteReaderSingleAsync<T> / ExecuteScalarAsync<T> / ExecuteNonQueryAsync
  • ExecuteInTransactionAsync(自动事务生命周期)
  • 事务重载: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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.8 96 9/21/2026
1.0.7 90 9/14/2026
1.0.6 93 9/12/2026
1.0.5 90 9/12/2026
1.0.3 97 9/12/2026
1.0.2 90 9/12/2026
1.0.1 103 9/12/2026

统一命名空间为 LTY.SqlStroreHelper,修复编译错误,补充调用文档与示例。