Zq.SQLBuilder.Core 2.4.0

dotnet add package Zq.SQLBuilder.Core --version 2.4.0                
NuGet\Install-Package Zq.SQLBuilder.Core -Version 2.4.0                
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="Zq.SQLBuilder.Core" Version="2.4.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Zq.SQLBuilder.Core --version 2.4.0                
#r "nuget: Zq.SQLBuilder.Core, 2.4.0"                
#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.
// Install Zq.SQLBuilder.Core as a Cake Addin
#addin nuget:?package=Zq.SQLBuilder.Core&version=2.4.0

// Install Zq.SQLBuilder.Core as a Cake Tool
#tool nuget:?package=Zq.SQLBuilder.Core&version=2.4.0                

<p></p>

<p align="center"> <img src="https://zqlovejyc.gitee.io/zqutils-js/Images/SQL.png" height="80"/> </p>

<div align="center">

star fork GitHub stars GitHub forks GitHub license nuget

</div>

<div align="left">

.NET Standard 2.1、.NET 5 版本SQLBuilder,Expression表达式转换为SQL语句,支持SqlServer、MySql、Oracle、Sqlite、PostgreSql;基于Dapper实现了不同数据库对应的数据仓储Repository;

</div>

🌭 开源地址

🥥 框架扩展包

包类型 名称 版本 描述
nuget Zq.SQLBuilder.Core nuget SQLBuilder.Core 核心包
nuget Zq.SQLBuilder.Core.SkyWalking nuget SQLBuilder.Core SkyWalking 扩展包
nuget Zq.SQLBuilder.Core.ElasticApm nuget SQLBuilder.Core ElasticApm扩展包

🚀 快速入门

  • ➕ 新增
//新增
await _repository.InsertAsync(entity);

//批量新增
await _repository.InsertAsync(entities);

//新增
await SqlBuilder
        .Insert<MsdBoxEntity>(() =>
            entity)
        .ExecuteAsync(
            _repository);

//批量新增
await SqlBuilder
        .Insert<MsdBoxEntity>(() =>
            new[]
            {
                new UserInfo { Name = "张三", Sex = 2 },
                new UserInfo { Name = "张三", Sex = 2 }
            })
        .ExecuteAsync(
            _repository);

  • 🗑 删除
//删除
await _repository.DeleteAsync(entity);

//批量删除
await _repository.DeleteAsync(entitties);

//条件删除
await _repository.DeleteAsync<MsdBoxEntity>(x => x.Id == "1");

//删除
await SqlBuilder
        .Delete<MsdBoxEntity>()
        .Where(x =>
            x.Id == "1")
        .ExecuteAsync(
            _repository);

//主键删除
await SqlBuilder
        .Delete<MsdBoxEntity>()
        .WithKey("1")
        .ExecuteAsync(
            _repository);
  • ✏ 更新
//更新
await _repository.UpdateAsync(entity);

//批量更新
await _repository.UpdateAsync(entities);

//条件更新
await _repository.UpdateAsync<MsdBoxEntity>(x => x.Id == "1", () => entity);

//更新
await SqlBuilder
        .Update<MsdBoxEntity>(() =>
            entity,
            DatabaseType.MySql,
            isEnableFormat:true)
        .Where(x =>
            x.Id == "1")
        .ExecuteAsync(
            _repository);
  • 🔍 查询
//简单查询
await _repository.FindListAsync<MsdBoxEntity>(x => x.Id == "1");

//连接查询
await SqlBuilder
        .Select<UserInfo, UserInfo, Account, Student, Class, City, Country>((u, t, a, s, d, e, f) =>
            new { u.Id, UId = t.Id, a.Name, StudentName = s.Name, ClassName = d.Name, e.CityName, CountryName = f.Name })
        .Join<UserInfo>((x, t) =>
            x.Id == t.Id) //注意此处单表多次Join所以要指明具体表别名,否则都会读取第一个表别名
        .Join<Account>((x, y) =>
            x.Id == y.UserId)
        .LeftJoin<Account, Student>((x, y) =>
            x.Id == y.AccountId)
        .RightJoin<Student, Class>((x, y) =>
            x.Id == y.UserId)
        .InnerJoin<Class, City>((x, y) =>
            x.CityId == y.Id)
        .FullJoin<City, Country>((x, y) =>
            x.CountryId == y.Id)
        .Where(x =>
            x.Id != null)
        .ToListAsync(
            _repository);

//分页查询
var condition = LinqExtensions
                    .True<UserInfo, Account>()
                    .And((x, y) => 
                        x.Id == y.UserId)
                    .WhereIf(
                        !name.IsNullOrEmpty(), 
                        (x, y) => name.EndsWith("∞")
                        ? x.Name.Contains(name.Trim('∞'))
                        : x.Name == name);
var hasWhere = false;
await SqlBuilder
        .Select<UserInfo, Account>(
            (u, a) => new { u.Id, UserName = "u.Name" })
        .InnerJoin<Account>(
            condition)
        .WhereIf(
            !name.IsNullOrEmpty(),
            x => x.Email != null && 
            (!name.EndsWith("∞") ? x.Name.Contains(name.TrimEnd('∞', '*')) : x.Name == name),
            ref hasWhere)
        .WhereIf(
            !email.IsNullOrEmpty(),
            x => x.Email == email,
            ref hasWhere)
        .ToPageAsync(
            _repository.UseMasterOrSlave(false),
            input.OrderField,
            input.Ascending,
            input.PageSize,
            input.PageIndex);

//仓储分页查询
await _repository.FindListAsync(condition, input.OrderField, input.Ascending, input.PageSize, input.PageIndex);

//高级查询
Func<string[], string> @delegate = x => $"ks.{x[0]}{x[1]}{x[2]} WITH(NOLOCK)";

await SqlBuilder
        .Select<UserInfo, Account, Student, Class, City, Country>((u, a, s, d, e, f) =>
            new { u, a.Name, StudentName = s.Name, ClassName = d.Name, e.CityName, CountryName = f.Name },
            tableNameFunc: @delegate)
        .Join<Account>((x, y) =>
            x.Id == y.UserId,
            @delegate)
        .LeftJoin<Account, Student>((x, y) =>
            x.Id == y.AccountId,
            @delegate)
        .RightJoin<Class, Student>((x, y) =>
            y.Id == x.UserId,
            @delegate)
        .InnerJoin<Class, City>((x, y) =>
            x.CityId == y.Id,
            @delegate)
        .FullJoin<City, Country>((x, y) =>
            x.CountryId == y.Id,
            @delegate)
        .Where(u =>
            u.Id != null)
        .ToListAsync(
            _repository);

  • 🎫 队列
//预提交队列
_repository.AddQueue(async repo =>
    await repo.UpdateAsync<UserEntity>(
        x => x.Id == "1",
        () => new
        {
            Name = "test"
        }) > 0);

_repository.AddQueue(async repo =>
    await repo.DeleteAsync<UserEntity>(x =>
        x.Enabled == 1) > 0);

//统一提交队列,默认开启事务
var res = await _repository.SaveQueueAsync();

🌌 IOC注入

根据appsettions.json配置自动注入不同类型数据仓储,支持一主多从配置

//注入SQLBuilder仓储
services.AddSqlBuilder(Configuration, "Base", (sql, parameter) =>
{
    //写入文本日志
    if (WebHostEnvironment.IsDevelopment())
    {
        if (parameter is DynamicParameters dynamicParameters)
            _logger.LogInformation($@"SQL语句:{sql}  参数:{dynamicParameters
                .ParameterNames?
                .ToDictionary(k => k, v => dynamicParameters.Get<object>(v))
                .ToJson()}");
        else if (parameter is OracleDynamicParameters oracleDynamicParameters)
            _logger.LogInformation($@"SQL语句:{sql} 参数:{oracleDynamicParameters
                .OracleParameters
                .ToDictionary(k => k.ParameterName, v => v.Value)
                .ToJson()}");
        else
            _logger.LogInformation($"SQL语句:{sql}  参数:{parameter.ToJson()}");
    }

    //返回null,不对原始sql进行任何更改,此处可以修改待执行的sql语句
    return null;
});

⚙ 数据库配置

//appsettions.json
"ConnectionStrings": {
  "Base": [
    "Oracle",
    "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.100)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=name)));Persist Security Info=True;User ID=test;Password=123;",
    "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.101)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=name)));Persist Security Info=True;User ID=test;Password=123;",
    "Data Source=(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.1.102)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=name)));Persist Security Info=True;User ID=test;Password=123;",
  ],
  "Cap": [
    "MySql",
    "Server=127.0.0.1;Database=db;Uid=root;Pwd=123456;SslMode=None;"
  ],
  "Oracle": [ "Oracle", "数据库连接字符串" ],
  "MySql": [ "MySql", "数据库连接字符串" ],
  "Sqlserver": [ "SqlServer", "数据库连接字符串" ],
  "Sqlite": [ "Sqlite", "数据库连接字符串" ],
  "Pgsql": [ "PostgreSql", "数据库连接字符串" ]
}

📰 事务

//方式一
IRepository trans = null;
try
{
    //开启事务
    trans = await _repository.BeginTransactionAsync();

    //数据库写操作
    await trans.InsertAsync(entity);

    //提交事务
    await trans.CommitAsync();
}
catch (Exception)
{
    //回滚事务
    if(trans != null)
        await tran.RollbackAsync();
       
    throw;
}

//方式二
var res = await _repository.ExecuteTransactionAsync(async trans =>
{
    var retval = (await trans.InsertAsync(entity)) > 0;

    if (input.Action.EqualIgnoreCase(UnitAction.InDryBox))
        code = await _unitInfoService.InDryBoxAsync(dryBoxInput);
    else
        code = await _unitInfoService.OutDryBoxAsync(dryBoxInput);

    return code == ErrorCode.Successful && retval;
});

📯 仓储+切库

private readonly Func<string, IRepository> _handler;
private readonly IRepository _repository;

public MyService(Func<string, IRepository> hander)
{
    _handler = hander;

    //默认base数据仓储
    _repository = hander(null);
}

//base仓储
var baseRepository = _handler("Base");

//cap仓储
var capRepository = _handler("Cap");

🎣 读写分离

//方式一
_repository.Master = false;

//方式二
_repository.UseMasterOrSlave(master)

🔗 链路追踪

//注入SQLBuilder SkyWalking链路追踪
services.AddSqlBuilderSkyApm()

//使用SQLBuilder ElasticApm链路追踪
app.UseSqlBuilderElasticApm(Configuration)

🧪 测试文档

🍻 贡献代码

SQLBuilder.Core 遵循 Apache-2.0 开源协议,欢迎大家提交 PRIssue

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 is compatible.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (7)

Showing the top 5 NuGet packages that depend on Zq.SQLBuilder.Core:

Package Downloads
Zq.SQLBuilder.Core.ElasticApm

ElasticApm扩展,实现sql链路追踪;

Zq.SQLBuilder.Core.SkyWalking

SkyWalking扩展,实现sql链路追踪;

Zq.SQLBuilder.Core.Diagnostics

SqlBuilder自定义Diagnostics扩展,实现sql自定义追踪监控;

Ydhp.Lib.Dapper

Package Description

Peak.Lib.Dapper

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
2.4.0 1,292 2/19/2023
2.3.9 1,767 9/12/2022
2.3.8 1,887 5/15/2022
2.3.7 1,832 5/14/2022
2.3.6 1,797 5/7/2022
2.3.5 2,070 4/4/2022
2.3.4 1,936 3/29/2022
2.3.3 1,914 3/24/2022
2.3.2 1,915 3/21/2022
2.3.1 1,429 12/31/2021
2.3.0 1,147 12/30/2021
2.2.9 1,090 12/27/2021
2.2.8 1,487 11/9/2021
2.2.7 1,225 10/17/2021
2.2.6 1,210 9/17/2021
2.2.5 1,167 7/10/2021
2.2.4 1,112 6/25/2021
2.2.3 1,207 6/23/2021
2.2.2 1,150 6/15/2021
2.2.1 1,173 6/6/2021
2.2.0 1,045 6/1/2021
2.1.9 1,117 5/13/2021
2.1.8 1,137 4/15/2021
2.1.7 1,047 4/14/2021
2.1.6 1,155 4/8/2021
2.1.5 1,067 1/20/2021
2.1.4 680 1/14/2021
2.1.3 752 1/1/2021
2.1.2 937 11/15/2020
2.1.1 800 11/12/2020
2.1.0 723 11/11/2020
2.0.5 704 11/10/2020
2.0.4 735 11/9/2020
2.0.3 539 11/5/2020
2.0.2 528 11/5/2020
2.0.1 672 10/31/2020
2.0.0 583 10/30/2020
1.0.6.7 552 10/27/2020
1.0.6.6 597 10/23/2020
1.0.6.5 542 10/22/2020
1.0.6.4 540 10/16/2020
1.0.6.3 550 10/13/2020
1.0.6.2 571 10/13/2020
1.0.6.1 547 10/12/2020
1.0.6 595 9/30/2020
1.0.5.9 560 9/29/2020
1.0.5.8 749 9/19/2020
1.0.5.7 704 9/17/2020
1.0.5.6 851 8/14/2020
1.0.5.5 619 8/11/2020
1.0.5.4 660 8/11/2020
1.0.5.3 611 8/3/2020
1.0.5.2 645 8/1/2020
1.0.5.1 624 7/31/2020
1.0.5 576 7/24/2020
1.0.4.9 606 7/16/2020
1.0.4.8 687 6/10/2020
1.0.4.7 606 5/27/2020
1.0.4.6 593 5/9/2020
1.0.4.5 803 4/11/2020
1.0.4.4 645 4/10/2020
1.0.4.3 704 4/9/2020
1.0.4.2 645 4/2/2020
1.0.4.1 674 4/2/2020
1.0.4 737 3/31/2020
1.0.3.9 637 3/30/2020
1.0.3.8 663 3/29/2020
1.0.3.7 660 3/29/2020
1.0.3.6 716 3/23/2020
1.0.3.5 656 3/12/2020
1.0.3.4 737 12/30/2019
1.0.3.3 686 12/30/2019
1.0.3.2 720 12/5/2019
1.0.3.1 679 12/5/2019
1.0.3 691 10/8/2019
1.0.2.9 788 7/15/2019
1.0.2.8 637 7/13/2019
1.0.2.7 732 5/31/2019
1.0.2.6 706 5/24/2019
1.0.2.5 696 5/15/2019
1.0.2.2 730 4/26/2019
1.0.2.1 746 3/7/2019
1.0.2 926 9/27/2018
1.0.1.9 946 9/17/2018
1.0.1.7 900 9/14/2018
1.0.1.6 992 9/10/2018
1.0.1.5 971 9/10/2018
1.0.1.4 926 9/9/2018
1.0.1.3 1,023 9/5/2018
1.0.1.2 930 9/1/2018
1.0.1.1 950 9/1/2018
1.0.1 1,040 8/24/2018
1.0.0.9 1,008 8/24/2018
1.0.0.8 968 8/24/2018
1.0.0.7 1,001 8/10/2018
1.0.0.6 1,024 8/10/2018
1.0.0.5 1,072 8/9/2018
1.0.0.4 957 8/8/2018
1.0.0.3 862 8/8/2018
1.0.0.2 893 8/8/2018
1.0.0.1 891 8/8/2018
1.0.0 974 8/8/2018

1.新增Separate、Join、Format、MaxIndex、MinIndex、ForEach扩展方法;
2.优化权重轮询算法,优化权重大的节点不会霸占选择权;
3.优化ConcurrentDictionary采用Lazy方式线程安全的创建字典元素值;
4.适配net7.0平台;
5.升级nuget包;