diff --git a/Lib/SimpleDapper.dll b/Lib/SimpleDapper.dll deleted file mode 100644 index 70f4aa69..00000000 Binary files a/Lib/SimpleDapper.dll and /dev/null differ diff --git a/Model/Tiobon.Web.pdm b/Model/Tiobon.Web.pdm index 1d196a98..f61b5428 100644 --- a/Model/Tiobon.Web.pdm +++ b/Model/Tiobon.Web.pdm @@ -1,5 +1,5 @@ - + @@ -105116,8 +105116,8 @@ Shadow=0 1630077158 -1713342688 -((-18861,2845), (-12775,6445)) +1713343323 +((-6725,2913), (-639,6513)) 0 16711680 16744448 diff --git a/Tiobon.Core.Api/Program.cs b/Tiobon.Core.Api/Program.cs index aa09e857..516b90a4 100644 --- a/Tiobon.Core.Api/Program.cs +++ b/Tiobon.Core.Api/Program.cs @@ -9,7 +9,7 @@ using Microsoft.IdentityModel.Logging; using Newtonsoft.Json.Converters; using Newtonsoft.Json.Serialization; using Serilog; -using SimpleDapper.Extensions; +using Tiobon.Core.Common.DB.Dapper.Extensions; using Tiobon.Core; using Tiobon.Core.Common.Core; using Tiobon.Core.Extensions; diff --git a/Tiobon.Core.Api/Tiobon.Core.Api.csproj b/Tiobon.Core.Api/Tiobon.Core.Api.csproj index 76503fb3..3a83b4f5 100644 --- a/Tiobon.Core.Api/Tiobon.Core.Api.csproj +++ b/Tiobon.Core.Api/Tiobon.Core.Api.csproj @@ -53,7 +53,6 @@ - @@ -140,12 +139,6 @@ - - - ..\Lib\SimpleDapper.dll - - - diff --git a/Tiobon.Core.Api/Tiobon.Core.xml b/Tiobon.Core.Api/Tiobon.Core.xml index c5a39a08..1af72fab 100644 --- a/Tiobon.Core.Api/Tiobon.Core.xml +++ b/Tiobon.Core.Api/Tiobon.Core.xml @@ -72,6 +72,83 @@ + + + 博客管理 + + + + + 构造函数 + + + + + + + 获取博客列表【无权限】 + + + + + + + + + + 获取博客详情 + + + + + + + 获取详情【无权限】 + + + + + + + 获取博客测试信息 v2版本 + + + + + + 添加博客【无权限】 + + + + + + + + + + + + + + 更新博客信息 + + + + + + + 删除博客 + + + + + + + apache jemeter 压力测试 + 更新接口 + + + 构造函数 diff --git a/Tiobon.Core.Common/DB/Dapper/BaseProvider/ServerMapPath/IDependency.cs b/Tiobon.Core.Common/DB/Dapper/BaseProvider/ServerMapPath/IDependency.cs new file mode 100644 index 00000000..fb05bf3d --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/BaseProvider/ServerMapPath/IDependency.cs @@ -0,0 +1,6 @@ +namespace Tiobon.Core.Common.DB.Dapper.BaseProvider.ServerMapPath +{ + public interface IDependency + { + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/BaseProvider/ServerMapPath/PathProvider.cs b/Tiobon.Core.Common/DB/Dapper/BaseProvider/ServerMapPath/PathProvider.cs new file mode 100644 index 00000000..a81ce8e1 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/BaseProvider/ServerMapPath/PathProvider.cs @@ -0,0 +1,50 @@ + +using Microsoft.AspNetCore.Hosting; +using System.IO; +using Tiobon.Core.Common.DB.Dapper.Extensions; + +namespace Tiobon.Core.Common.DB.Dapper.BaseProvider.ServerMapPath; + +public interface IPathProvider : IDependency +{ + string MapPath(string path); + string MapPath(string path, bool rootPath); + IWebHostEnvironment GetHostingEnvironment(); +} + +public class PathProvider : IPathProvider +{ + private IWebHostEnvironment _hostingEnvironment; + + public PathProvider(IWebHostEnvironment environment) + { + _hostingEnvironment = environment; + } + public IWebHostEnvironment GetHostingEnvironment() + { + return _hostingEnvironment; + } + + public string MapPath(string path) + { + return MapPath(path, false); + } + /// + /// + /// + /// + /// 获取wwwroot路径 + /// + public string MapPath(string path, bool rootPath) + { + if (rootPath) + { + if (_hostingEnvironment.WebRootPath == null) + { + _hostingEnvironment.WebRootPath = _hostingEnvironment.ContentRootPath + "/wwwroot".ReplacePath(); + } + return Path.Combine(_hostingEnvironment.WebRootPath, path).ReplacePath(); + } + return Path.Combine(_hostingEnvironment.ContentRootPath, path).ReplacePath(); + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Configuration/AppSetting.cs b/Tiobon.Core.Common/DB/Dapper/Configuration/AppSetting.cs new file mode 100644 index 00000000..72c66df5 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Configuration/AppSetting.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using System.Data.SqlClient; +using System.Linq; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Configuration.Json; +using Microsoft.Extensions.DependencyInjection; +using Tiobon.Core.Common.DB.Dapper.DBManager; +using Tiobon.Core.Common.DB.Dapper.Enums; + +namespace Tiobon.Core.Common.DB.Dapper; + +public static class AppSetting +{ + public static IConfiguration Configuration { get; private set; } + + public static string DbConnectionString { get; private set; } + public static string DBType { get; private set; } + + + private static ConnectionStrings _connection; + + + public static void Init() + { + Configuration = new ConfigurationBuilder() + .Add(new JsonConfigurationSource { Path = "appsettings.json", ReloadOnChange = true }) + .Build(); ; + + //var baseDirectory = AppContext.BaseDirectory; + //var provider = services.BuildServiceProvider(); + + + ////设置修改或删除时需要设置为默认用户信息的字段 + //CreateMember = provider.GetRequiredService>().Value ?? new CreateMember(); + //ModifyMember = provider.GetRequiredService>().Value ?? new ModifyMember(); + + #region 初始化数据库 + MainDb.CurrentDbConnId = app("MainDB"); + + var mainConnetctDb = BaseDBConfig.MutiConnectionString.allDbs.Find(x => x.ConnId == MainDb.CurrentDbConnId); + + Const.DBType.Name = DataBaseType.SqlServer.ToString(); + DBType = DataBaseType.SqlServer.ToString(); + + try + { + DbConnectionString = mainConnetctDb.Connection; + } + catch { } + if (string.IsNullOrEmpty(DbConnectionString)) + throw new Exception("未配置好数据库默认连接"); + + #region 检查服务是否可用 + + //bool mysql = Const.DBType.Name == DbCurrentType.MySql.ToString(); + //if (mysql) + //{ + + //} + bool mssql = Const.DBType.Name == DbCurrentType.MsSql.ToString(); + + if (mssql) + { + using var conn = new SqlConnection(_connection.DbConnectionString); + while (true) + { + + //if (Utility.IsPortOpen(conn.DataSource, 1433)) + //{ + // Logger.WriteLog("[数据库] 服务状态正常"); + // break; + //} + //else + //{ + // Logger.WriteLog("[数据库] 服务状态异常, 稍后重试"); + // System.Threading.Thread.Sleep(5000); + //} + + //conn.Open(); + //if (conn.State == ConnectionState.Open) + //{ + // conn.Close(); + // Logger.WriteLog("[数据库] 服务状态正常"); + // break; + //} + //else + //{ + // Logger.WriteLog("[数据库] 服务状态异常, 等待 5 秒后重试"); + // System.Threading.Thread.Sleep(5000); + //} + } + } + #endregion + + #endregion + + + } + // 多个节点name格式 :["key:key1"] + public static string GetSettingString(string key) + { + return Configuration[key]; + } + // 多个节点,通过.GetSection("key")["key1"]获取 + public static IConfigurationSection GetSection(string key) + { + return Configuration.GetSection(key); + } + + /// + /// 封装要操作的字符 + /// + /// 节点配置 + /// + public static string app(params string[] sections) + { + try + { + + if (sections.Any()) + { + return Configuration[string.Join(":", sections)]; + } + } + catch (Exception) { } + + return ""; + } + + /// + /// 递归获取配置信息数组 + /// + /// + /// + /// + public static List app(params string[] sections) + { + List list = new List(); + // 引用 Microsoft.Extensions.Configuration.Binder 包 + Configuration.Bind(string.Join(":", sections), list); + return list; + } +} + + +#region 数据库链接 +/// +/// 数据库链接 +/// +public class ConnectionStrings +{ + /// + /// 数据库类型 + /// + public string DBType { get; set; } + + /// + /// 数据库链接字符串 + /// + public string DbConnectionString { get; set; } +} +#endregion + diff --git a/Tiobon.Core.Common/DB/Dapper/Const/DataBaseType.cs b/Tiobon.Core.Common/DB/Dapper/Const/DataBaseType.cs new file mode 100644 index 00000000..ff974cde --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Const/DataBaseType.cs @@ -0,0 +1,6 @@ +namespace Tiobon.Core.Common.DB.Dapper.Const; + +public static class DBType +{ + public static string Name { get; set; } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Const/SqlDbTypeName.cs b/Tiobon.Core.Common/DB/Dapper/Const/SqlDbTypeName.cs new file mode 100644 index 00000000..29917734 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Const/SqlDbTypeName.cs @@ -0,0 +1,23 @@ +namespace Tiobon.Core.Common.DB.Dapper; + +public struct SqlDbTypeName +{ + public const string NVarChar = "nvarchar"; + public const string VarChar = "varchar"; + public const string NChar = "nchar"; + public const string Char = "char"; + public const string Text = "text"; + public const string Int = "int"; + public const string BigInt = "bigint"; + public const string DateTime = "datetime"; + public const string Date = "date"; + public const string SmallDateTime = "smalldatetime"; + public const string SmallDate = "smalldate"; + public const string Float = "float"; + public const string Decimal = "decimal"; + public const string Double = "double"; + public const string Bit = "bit"; + public const string Bool = "bool"; + public const string UniqueIdentifier = "uniqueidentifier"; + +} diff --git a/Tiobon.Core.Common/DB/Dapper/DBManager/BaseDBConfig.cs b/Tiobon.Core.Common/DB/Dapper/DBManager/BaseDBConfig.cs new file mode 100644 index 00000000..b5c17303 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/DBManager/BaseDBConfig.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using SqlSugar; + +namespace Tiobon.Core.Common.DB.Dapper.DBManager; +public class BaseDBConfig +{ + /* 之前的单库操作已经删除,如果想要之前的代码,可以查看我的GitHub的历史记录 + * 目前是多库操作,默认加载的是AppSetting.json设置为true的第一个db连接。 + */ + public static (List allDbs, List slaveDbs) MutiConnectionString => MutiInitConn(); + + private static string DifDBConnOfSecurity(params string[] conn) + { + foreach (var item in conn) + { + try + { + if (File.Exists(item)) + { + return File.ReadAllText(item).Trim(); + } + } + catch (System.Exception) + { + } + } + + return conn[conn.Length - 1]; + } + + + public static (List, List) MutiInitConn() + { + List listdatabase = AppSetting.app("DBS") + .Where(i => i.Enabled).ToList(); + foreach (var i in listdatabase) + { + SpecialDbString(i); + } + + List listdatabaseSimpleDB = new List(); //单库 + List listdatabaseSlaveDB = new List(); //从库 + + // 单库,且不开启读写分离,只保留一个 + if (!AppSetting.app(new string[] { "CQRSEnabled" }).ObjToBool() && !AppSetting.app(new string[] { "MutiDBEnabled" }).ObjToBool()) + { + if (listdatabase.Count == 1) + { + return (listdatabase, listdatabaseSlaveDB); + } + else + { + var dbFirst = listdatabase.FirstOrDefault(d => d.ConnId == AppSetting.app(new string[] { "MainDB" }).ObjToString()); + if (dbFirst == null) + { + dbFirst = listdatabase.FirstOrDefault(); + } + + listdatabaseSimpleDB.Add(dbFirst); + return (listdatabaseSimpleDB, listdatabaseSlaveDB); + } + } + + + // 读写分离,且必须是单库模式,获取从库 + if (AppSetting.app(new string[] { "CQRSEnabled" }).ObjToBool() && !AppSetting.app(new string[] { "MutiDBEnabled" }).ObjToBool()) + { + if (listdatabase.Count > 1) + { + listdatabaseSlaveDB = listdatabase.Where(d => d.ConnId != AppSetting.app(new string[] { "MainDB" }).ObjToString()).ToList(); + } + } + + + return (listdatabase, listdatabaseSlaveDB); + //} + } + + /// + /// 定制Db字符串 + /// 目的是保证安全:优先从本地txt文件获取,若没有文件则从AppSetting.json中获取 + /// + /// + /// + private static MutiDBOperate SpecialDbString(MutiDBOperate mutiDBOperate) + { + if (mutiDBOperate.DbType == DataBaseType.Sqlite) + { + mutiDBOperate.Connection = $"DataSource=" + Path.Combine(Environment.CurrentDirectory, mutiDBOperate.Connection); + } + else if (mutiDBOperate.DbType == DataBaseType.SqlServer) + { + mutiDBOperate.Connection = DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_SqlserverConn.txt", mutiDBOperate.Connection); + } + else if (mutiDBOperate.DbType == DataBaseType.MySql) + { + mutiDBOperate.Connection = DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_MySqlConn.txt", mutiDBOperate.Connection); + } + else if (mutiDBOperate.DbType == DataBaseType.Oracle) + { + mutiDBOperate.Connection = DifDBConnOfSecurity(@"D:\my-file\dbCountPsw1_OracleConn.txt", mutiDBOperate.Connection); + } + + return mutiDBOperate; + } + + +} + + +public enum DataBaseType +{ + MySql = 0, + SqlServer = 1, + Sqlite = 2, + Oracle = 3, + PostgreSQL = 4, + Dm = 5, + Kdbndp = 6, +} + +public class MutiDBOperate +{ + /// + /// 连接启用开关 + /// + public bool Enabled { get; set; } + + /// + /// 连接ID + /// + public string ConnId { get; set; } + + /// + /// 从库执行级别,越大越先执行 + /// + public int HitRate { get; set; } + + /// + /// 连接字符串 + /// + public string Connection { get; set; } + + /// + /// 数据库类型 + /// + public DataBaseType DbType { get; set; } +} \ No newline at end of file diff --git a/Tiobon.Core.Common/DB/Dapper/DBManager/DBConnectionAttribute.cs b/Tiobon.Core.Common/DB/Dapper/DBManager/DBConnectionAttribute.cs new file mode 100644 index 00000000..d011c0ef --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/DBManager/DBConnectionAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Tiobon.Core.Common.DB.Dapper.DBManager; + +public class DBConnectionAttribute : Attribute +{ + public string DBName { get; set; } +} diff --git a/Tiobon.Core.Common/DB/Dapper/DBManager/DBServerProvider.cs b/Tiobon.Core.Common/DB/Dapper/DBManager/DBServerProvider.cs new file mode 100644 index 00000000..87afbaf3 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/DBManager/DBServerProvider.cs @@ -0,0 +1,138 @@ +//using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using Tiobon.Core.Common.DB.Dapper.Const; +using Tiobon.Core.Common.DB.Dapper; +using Tiobon.Core.Common.DB.Dapper.Enums; +using Tiobon.Core.Common.DB.Dapper.Extensions; + +namespace Tiobon.Core.Common.DB.Dapper.DBManager; +public class DBServerProvider +{ + private static Dictionary ConnectionPool = new Dictionary(StringComparer.OrdinalIgnoreCase); + + public static string DefaultConnName = "defalut"; + + static DBServerProvider() + { + SetConnection(DefaultConnName, AppSetting.DbConnectionString); + } + public static void SetConnection(string key, string val) + { + if (ConnectionPool.ContainsKey(key)) + { + ConnectionPool[key] = val; + return; + } + ConnectionPool.Add(key, val); + } + /// + /// 设置默认数据库连接 + /// + /// + public static void SetDefaultConnection(string val) + { + SetConnection(DefaultConnName, val); + } + + public static string GetConnectionString(string key) + { + key = key ?? DefaultConnName; + if (ConnectionPool.ContainsKey(key)) + { + return ConnectionPool[key]; + } + return key; + } + /// + /// 获取默认数据库连接 + /// + /// + public static string GetConnectionString() + { + return GetConnectionString(DefaultConnName); + } + //private static bool _isMysql = DBType.Name == DbCurrentType.MySql.ToString(); + private static bool _isMysql = false; + public static IDbConnection GetDbConnection(string connString = null) + { + if (_isMysql) + { + return new MySql.Data.MySqlClient.MySqlConnection(connString ?? ConnectionPool[DefaultConnName]); + } + return new SqlConnection(connString ?? ConnectionPool[DefaultConnName]); + } + public static IDbConnection GetMyDbConnection(string connString = null) + { + //new MySql.Data.MySqlClient.MySqlConnection(connString); + string mySql = "Data Source=132.232.2.109;Database=mysql;User ID=xx;Password=xxx;pooling=true;CharSet=utf8;port=3306;sslmode=none"; + // MySqlConnector + return new MySql.Data.MySqlClient.MySqlConnection(mySql); + + } + //public static VOLContext DbContext + //{ + // get { return GetEFDbContext(); } + //} + //public static VOLContext GetEFDbContext() + //{ + // return GetEFDbContext(null); + //} + //public static VOLContext GetEFDbContext(string dbName) + //{ + // VOLContext beefContext = Utilities.HttpContext.Current.RequestServices.GetService(typeof(VOLContext)) as VOLContext; + // if (dbName != null) + // { + // if (!ConnectionPool.ContainsKey(dbName)) + // { + // throw new Exception("数据库连接名称错误"); + // } + // beefContext.Database.GetDbConnection().ConnectionString = ConnectionPool[dbName]; + // } + // return beefContext; + //} + + //public static void SetDbContextConnection(VOLContext beefContext, string dbName) + //{ + // if (!ConnectionPool.ContainsKey(dbName)) + // { + // throw new Exception("数据库连接名称错误"); + // } + // beefContext.Database.GetDbConnection().ConnectionString = ConnectionPool[dbName]; + //} + /// + /// 获取实体的数据库连接 + /// + /// + /// + /// + //public static void GetDbContextConnection(VOLContext defaultDbContext) + //{ + // //string connstr= defaultDbContext.Database.GetDbConnection().ConnectionString; + // // if (connstr != ConnectionPool[DefaultConnName]) + // // { + // // defaultDbContext.Database.GetDbConnection().ConnectionString = ConnectionPool[DefaultConnName]; + // // }; + //} + + public static ISqlDapper SqlDapper + { + get + { + return new SqlDapper(DefaultConnName); + } + } + public static ISqlDapper GetSqlDapper(string dbName = null) + { + return new SqlDapper(dbName ?? DefaultConnName); + } + public static ISqlDapper GetSqlDapper() + { + //获取实体真实的数据库连接池对象名,如果不存在则用默认数据连接池名 + string dbName = typeof(TEntity).GetTypeCustomValue(x => x.DBName) ?? DefaultConnName; + return GetSqlDapper(dbName); + } + +} diff --git a/Tiobon.Core.Common/DB/Dapper/Entity/EntityAttribute.cs b/Tiobon.Core.Common/DB/Dapper/Entity/EntityAttribute.cs new file mode 100644 index 00000000..af753017 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Entity/EntityAttribute.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tiobon.Core.Common.DB.Dapper.Entity +{ + public class EntityAttribute : Attribute + { + /// + /// 真实表名(数据库表名,若没有填写默认实体为表名) + /// + public string TableName { get; set; } + /// + /// 表中文名 + /// + public string TableCnName { get; set; } + /// + /// 子表 + /// + public Type[] DetailTable { get; set; } + /// + /// 子表中文名 + /// + public string DetailTableCnName { get; set; } + /// + /// 数据库 + /// + public string DBServer { get; set; } + + //是否开启用户数据权限,true=用户只能操作自己(及下级角色)创建的数据,如:查询、删除、修改等操作 + public bool CurrentUserPermission { get; set; } + + public Type ApiInput { get; set; } + public Type ApiOutput { get; set; } + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Enums/DbCurrentType.cs b/Tiobon.Core.Common/DB/Dapper/Enums/DbCurrentType.cs new file mode 100644 index 00000000..2e85259d --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Enums/DbCurrentType.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tiobon.Core.Common.DB.Dapper.Enums +{ + public enum DbCurrentType + { + MySql = 1, + MsSql = 2, + PgSql = 3 + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/AutofacManager/AutofacContainerModule.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/AutofacManager/AutofacContainerModule.cs new file mode 100644 index 00000000..067fdbf2 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/AutofacManager/AutofacContainerModule.cs @@ -0,0 +1,9 @@ +namespace Tiobon.Core.Common.DB.Dapper.Extensions.AutofacManager; + +public class AutofacContainerModule +{ + public static TService GetService() where TService:class + { + return typeof(TService).GetService() as TService; + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/EntityProperties.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/EntityProperties.cs new file mode 100644 index 00000000..a2ed785e --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/EntityProperties.cs @@ -0,0 +1,620 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using System.Text; +using Tiobon.Core.Common.DB.Dapper.Entity; + + +namespace Tiobon.Core.Common.DB.Dapper.Extensions; + +public static class EntityProperties +{ + + /// + /// 获取对象里指定成员名称 + /// + /// + /// 格式 Expression> exp = x => new { x.字段1, x.字段2 };或x=>x.Name + /// + public static string[] GetExpressionProperty(this Expression> properties) + { + if (properties == null) + return new string[] { }; + if (properties.Body is NewExpression) + return ((NewExpression)properties.Body).Members.Select(x => x.Name).ToArray(); + if (properties.Body is MemberExpression) + return new string[] { ((MemberExpression)properties.Body).Member.Name }; + if (properties.Body is UnaryExpression) + return new string[] { ((properties.Body as UnaryExpression).Operand as MemberExpression).Member.Name }; + throw new Exception("未实现的表达式"); + } + + public static Dictionary GetColumType(this PropertyInfo[] properties, bool containsKey) + { + Dictionary dictionary = new Dictionary(); + foreach (PropertyInfo property in properties) + { + //if (!containsKey && property.IsKey()) + //{ + // continue; + //} + var keyVal = GetColumnType(property, true); + dictionary.Add(keyVal.Key, keyVal.Value); + } + return dictionary; + } + + private static readonly Dictionary entityMapDbColumnType = new Dictionary() { + {typeof(int),SqlDbTypeName.Int }, + {typeof(int?),SqlDbTypeName.Int }, + {typeof(long),SqlDbTypeName.BigInt }, + {typeof(long?),SqlDbTypeName.BigInt }, + {typeof(decimal),"decimal(18, 5)" }, + {typeof(decimal?),"decimal(18, 5)" }, + {typeof(double),"decimal(18, 5)" }, + {typeof(double?),"decimal(18, 5)" }, + {typeof(float),"decimal(18, 5)" }, + {typeof(float?),"decimal(18, 5)" }, + {typeof(Guid),"UniqueIdentifier" }, + {typeof(Guid?),"UniqueIdentifier" }, + {typeof(byte),"tinyint" }, + {typeof(byte?),"tinyint" }, + {typeof(string),"nvarchar" } + }; + /// + /// 返回属性的字段及数据库类型 + /// + /// + /// 是否包括后字段具体长度:nvarchar(100) + /// + public static KeyValuePair GetColumnType(this PropertyInfo property, bool lenght = false) + { + string colType = ""; + object objAtrr = property.GetTypeCustomAttributes(typeof(ColumnAttribute), out bool asType); + if (asType) + { + colType = ((ColumnAttribute)objAtrr).TypeName.ToLower(); + if (!string.IsNullOrEmpty(colType)) + { + //不需要具体长度直接返回 + if (!lenght) + { + return new KeyValuePair(property.Name, colType); + } + if (colType == "decimal" || colType == "double" || colType == "float") + { + objAtrr = property.GetTypeCustomAttributes(typeof(DisplayFormatAttribute), out asType); + colType += "(" + (asType ? ((DisplayFormatAttribute)objAtrr).DataFormatString : "18,5") + ")"; + + } + ///如果是string,根据 varchar或nvarchar判断最大长度 + if (property.PropertyType.ToString() == "System.String") + { + colType = colType.Split("(")[0]; + objAtrr = property.GetTypeCustomAttributes(typeof(MaxLengthAttribute), out asType); + if (asType) + { + int length = ((MaxLengthAttribute)objAtrr).Length; + colType += "(" + (length < 1 || length > (colType.StartsWith("n") ? 8000 : 4000) ? "max" : length.ToString()) + ")"; + } + else + { + colType += "(max)"; + } + } + return new KeyValuePair(property.Name, colType); + } + } + if (entityMapDbColumnType.TryGetValue(property.PropertyType, out string value)) + { + colType = value; + } + else + { + colType = SqlDbTypeName.NVarChar; + } + if (lenght && colType == SqlDbTypeName.NVarChar) + { + colType = "nvarchar(max)"; + } + return new KeyValuePair(property.Name, colType); + } + + /// + ///要执行的sql语句如:通过EntityToSqlTempName.Temp_Insert0.ToString()字符串占位,生成的的sql语句会把EntityToSqlTempName.Temp_Insert0.ToString()替换成生成的sql临时表数据 + /// string sql = " ;DELETE FROM " + typeEntity.Name + " where " + typeEntity.GetKeyName() + + /// " in (select * from " + EntityToSqlTempName.Temp_Insert0.ToString() + ")"; + /// + /// + /// + /// 指定生成的数组值的类型 + /// + /// + public static string GetArraySql(this object[] array, FieldType fieldType, string sql) + { + if (array == null || array.Count() == 0) + { + return string.Empty; + } + string columnType = string.Empty; + List arrrayEntityList = array.Select(x => new ArrayEntity { column1 = x.ToString() }).ToList(); + return arrrayEntityList.GetEntitySql(false, sql, null, null, fieldType); + } + /// + /// 根据实体获取key的类型,用于update或del操作 + /// + /// + /// + public static FieldType GetFieldType(this Type typeEntity) + { + FieldType fieldType; + string columnType = typeEntity.GetProperties().Where(x => x.Name == typeEntity.GetKeyName()).ToList()[0].GetColumnType(false).Value; + switch (columnType) + { + case SqlDbTypeName.Int: fieldType = FieldType.Int; break; + case SqlDbTypeName.BigInt: fieldType = FieldType.BigInt; break; + case SqlDbTypeName.VarChar: fieldType = FieldType.VarChar; break; + case SqlDbTypeName.UniqueIdentifier: fieldType = FieldType.UniqueIdentifier; break; + default: fieldType = FieldType.NvarChar; break; + } + return fieldType; + } + public static string GetEntitySql(this IEnumerable entityList, + bool containsKey = false, + string sql = null, + Expression> ignoreFileds = null, + Expression> fixedColumns = null, + FieldType? fieldType = null + ) + { + + if (entityList == null || entityList.Count() == 0) return ""; + PropertyInfo[] propertyInfo = typeof(T).GetProperties().ToArray(); + if (propertyInfo.Count() == 0) + { + propertyInfo = entityList.ToArray()[0].GetType().GetGenericProperties().ToArray(); + } + propertyInfo = propertyInfo.GetGenericProperties().ToArray(); + + string[] arr = null; + if (fixedColumns != null) + { + arr = fixedColumns.GetExpressionToArray(); + PropertyInfo keyProperty = typeof(T).GetKeyProperty(); + propertyInfo = propertyInfo.Where(x => (containsKey && x.Name == keyProperty.Name) || arr.Contains(x.Name)).ToArray(); + } + if (ignoreFileds != null) + { + arr = ignoreFileds.GetExpressionToArray(); + propertyInfo = propertyInfo.Where(x => !arr.Contains(x.Name)).ToArray(); + } + + Dictionary dictProperties = propertyInfo.GetColumType(containsKey); + if (fieldType != null) + { + string realType = fieldType.ToString(); + if ((int)fieldType == 0 || (int)fieldType == 1) + { + realType += "(max)"; + } + dictProperties = new Dictionary { { dictProperties.Select(x => x.Key).ToList()[0], realType } }; + } + if (dictProperties.Keys.Count * entityList.Count() > 50 * 3000) + { + throw new Exception("写入数据太多,请分开写入。"); + } + + string cols = string.Join(",", dictProperties.Select(c => "[" + c.Key + "]" + " " + c.Value)); + StringBuilder declareTable = new StringBuilder(); + + string tempTablbe = "#" + EntityToSqlTempName.TempInsert.ToString(); + + declareTable.Append("CREATE TABLE " + tempTablbe + " (" + cols + ")"); + declareTable.Append("\r\n"); + + //参数总数量 + int parCount = (dictProperties.Count) * (entityList.Count()); + int takeCount = 0; + int maxParsCount = 2050; + if (parCount > maxParsCount) + { + //如果参数总数量超过2100,设置每次分批循环写入表的大小 + takeCount = maxParsCount / dictProperties.Count; + } + + int count = 0; + StringBuilder stringLeft = new StringBuilder(); + StringBuilder stringCenter = new StringBuilder(); + StringBuilder stringRight = new StringBuilder(); + + int index = 0; + foreach (T entity in entityList) + { + //每1000行需要分批写入(数据库限制每批至多写入1000行数据) + if (index == 0 || index >= 1000 || takeCount - index == 0) + { + if (stringLeft.Length > 0) + { + declareTable.AppendLine( + stringLeft.Remove(stringLeft.Length - 2, 2).Append("',").ToString() + + stringCenter.Remove(stringCenter.Length - 1, 1).Append("',").ToString() + + stringRight.Remove(stringRight.Length - 1, 1).ToString()); + + stringLeft.Clear(); stringCenter.Clear(); stringRight.Clear(); + } + + stringLeft.AppendLine("exec sp_executesql N'SET NOCOUNT ON;"); + stringCenter.Append("N'"); + + index = 0; count = 0; + } + stringLeft.Append(index == 0 ? "; INSERT INTO " + tempTablbe + " values (" : " "); + index++; + foreach (PropertyInfo property in propertyInfo) + { + //if (!containsKey && property.IsKey()) { continue; } + string par = "@v" + count; + stringLeft.Append(par + ","); + stringCenter.Append(par + " " + dictProperties[property.Name] + ","); + object val = property.GetValue(entity); + if (val == null) + { + stringRight.Append(par + "=NUll,"); + } + else + { + stringRight.Append(par + "='" + val.ToString().Replace("'", "''''") + "',"); + } + count++; + } + stringLeft.Remove(stringLeft.Length - 1, 1); + stringLeft.Append("),("); + } + + if (stringLeft.Length > 0) + { + declareTable.AppendLine( + stringLeft.Remove(stringLeft.Length - 2, 2).Append("',").ToString() + + stringCenter.Remove(stringCenter.Length - 1, 1).Append("',").ToString() + + stringRight.Remove(stringRight.Length - 1, 1).ToString()); + + stringLeft.Clear(); stringCenter.Clear(); stringRight.Clear(); + } + if (!string.IsNullOrEmpty(sql)) + { + sql = sql.Replace(EntityToSqlTempName.TempInsert.ToString(), tempTablbe); + declareTable.AppendLine(sql); + } + else + { + declareTable.AppendLine(" SELECT " + (string.Join(",", fixedColumns?.GetExpressionToArray() ?? new string[] { "*" })) + " FROM " + tempTablbe); + } + + + if (tempTablbe.Substring(0, 1) == "#") + { + declareTable.AppendLine("; drop table " + tempTablbe); + } + return declareTable.ToString(); + } + public static string GetKeyName(this Type typeinfo) + { + return typeinfo.GetProperties().GetKeyName(); + } + public static string GetKeyName(this PropertyInfo[] properties) + { + return properties.GetKeyName(false); + } + /// + /// 获取key列名 + /// + /// + /// true获取key对应类型,false返回对象Key的名称 + /// + public static string GetKeyName(this PropertyInfo[] properties, bool keyType) + { + string keyName = string.Empty; + foreach (PropertyInfo propertyInfo in properties) + { + if (!propertyInfo.IsKey()) + continue; + if (!keyType) + return propertyInfo.Name; + var attributes = propertyInfo.GetCustomAttributes(typeof(ColumnAttribute), false); + //如果没有ColumnAttribute的需要单独再验证,下面只验证有属性的 + if (attributes.Length > 0) + return ((ColumnAttribute)attributes[0]).TypeName.ToLower(); + else + return GetColumType(new PropertyInfo[] { propertyInfo }, true)[propertyInfo.Name]; + } + return keyName; + } + + /// + /// 获取主键字段 + /// + /// + /// + public static PropertyInfo GetKeyProperty(this Type entity) + { + return entity.GetProperties().GetKeyProperty(); + } + public static PropertyInfo GetKeyProperty(this PropertyInfo[] properties) + { + return properties.Where(c => c.IsKey()).FirstOrDefault(); + } + public static bool IsKey(this PropertyInfo propertyInfo) + { + object[] keyAttributes = propertyInfo.GetCustomAttributes(typeof(KeyAttribute), false); + if (keyAttributes.Length > 0) + return true; + return false; + } + + /// + /// 判断是否包含某个属性: + /// 如 [Editable(true)] + // public string MO { get; set; }包含Editable + /// + /// + /// + /// + public static bool ContainsCustomAttributes(this PropertyInfo propertyInfo, Type type) + { + propertyInfo.GetTypeCustomAttributes(type, out bool contains); + return contains; + } + + /// + /// 获取PropertyInfo指定属性 + /// + /// + /// + /// + public static object GetTypeCustomAttributes(this PropertyInfo propertyInfo, Type type, out bool asType) + { + object[] attributes = propertyInfo.GetCustomAttributes(type, false); + if (attributes.Length == 0) + { + asType = false; + return new string[0]; + } + asType = true; + return attributes[0]; + } + + /// + /// 验证数据库字段类型与值是否正确, + /// + /// propertyInfo为当字段,当前字段必须有ColumnAttribute属性, + /// 如字段:标识为数据库int类型[Column(TypeName="int")] public int Id { get; set; } + /// 如果是小数float或Decimal必须对propertyInfo字段加DisplayFormatAttribute属性 + /// + /// + /// IEnumerable<(bool, string, object)> bool成否校验成功,string校验失败信息,object,当前校验的值 + public static IEnumerable<(bool, string, object)> ValidationValueForDbType(this PropertyInfo propertyInfo, params object[] values) + { + string dbTypeName = propertyInfo.GetTypeCustomValue(c => c.TypeName); + foreach (object value in values) + { + yield return dbTypeName.ValidationVal(value, propertyInfo); + } + } + + + private static readonly Dictionary ProperWithDbType = new Dictionary() { + { typeof(string),SqlDbTypeName.NVarChar }, + { typeof(DateTime),SqlDbTypeName.DateTime}, + {typeof(long),SqlDbTypeName.BigInt }, + {typeof(int),SqlDbTypeName.Int}, + { typeof(decimal),SqlDbTypeName.Decimal }, + { typeof(float),SqlDbTypeName.Float }, + { typeof(double),SqlDbTypeName.Double }, + { typeof(byte),SqlDbTypeName.Int },//类型待完 + { typeof(Guid),SqlDbTypeName.UniqueIdentifier} + }; + public static string GetProperWithDbType(this PropertyInfo propertyInfo) + { + bool result = ProperWithDbType.TryGetValue(propertyInfo.PropertyType, out string value); + if (result) + { + return value; + } + return SqlDbTypeName.NVarChar; + } + + /// + /// 验证数据库字段类型与值是否正确, + /// + /// 数据库字段类型(如varchar,nvarchar,decimal,不要带后面长度如:varchar(50)) + /// 值 + /// 要验证的类的属性,若不为null,则会判断字符串的长度是否正确 + /// (bool, string, object)bool成否校验成功,string校验失败信息,object,当前校验的值 + public static (bool, string, object) ValidationVal(this string dbType, object value, PropertyInfo propertyInfo = null) + { + if (string.IsNullOrEmpty(dbType)) + { + dbType = propertyInfo != null ? propertyInfo.GetProperWithDbType() : SqlDbTypeName.NVarChar; + } + dbType = dbType.ToLower(); + string val = value?.ToString(); + //验证长度 + string reslutMsg = string.Empty; + if (dbType == SqlDbTypeName.Int || dbType == SqlDbTypeName.BigInt) + { + if (!value.IsInt()) + reslutMsg = "只能为有效整数"; + } + else if (dbType == SqlDbTypeName.DateTime + || dbType == SqlDbTypeName.Date + || dbType == SqlDbTypeName.SmallDateTime + || dbType == SqlDbTypeName.SmallDate + ) + { + if (!value.IsDate()) + reslutMsg = "必须为日期格式"; + } + else if (dbType == SqlDbTypeName.Float || dbType == SqlDbTypeName.Decimal || dbType == SqlDbTypeName.Double) + { + string formatString = string.Empty; + if (propertyInfo != null) + formatString = propertyInfo.GetTypeCustomValue(x => x.DataFormatString); + //if (string.IsNullOrEmpty(formatString)) + // throw new Exception("请对字段" + propertyInfo?.Name + "添加DisplayFormat属性标识"); + + if (!val.IsNumber(formatString)) + { + string[] arr = (formatString ?? "10,0").Split(','); + reslutMsg = $"整数{arr[0]}最多位,小数最多{arr[1]}位"; + } + } + else if (dbType == SqlDbTypeName.UniqueIdentifier) + { + if (!val.IsGuid()) + { + reslutMsg = propertyInfo.Name + "Guid不正确"; + } + } + else if (propertyInfo != null + && (dbType == SqlDbTypeName.VarChar + || dbType == SqlDbTypeName.NVarChar + || dbType == SqlDbTypeName.NChar + || dbType == SqlDbTypeName.Char + || dbType == SqlDbTypeName.Text)) + { + + //默认nvarchar(max) 、text 长度不能超过20000 + if (val.Length > 20000) + { + reslutMsg = $"字符长度最多【20000】"; + } + else + { + int length = propertyInfo.GetTypeCustomValue(x => new { x.Length }).GetInt(); + if (length == 0) { return (true, null, null); } + //判断双字节与单字段 + else if (length < 8000 && + ((dbType.Substring(0, 1) != "n" + && Encoding.UTF8.GetBytes(val.ToCharArray()).Length > length) + || val.Length > length) + ) + { + reslutMsg = $"最多只能【{length}】个字符。"; + } + } + } + if (!string.IsNullOrEmpty(reslutMsg) && propertyInfo != null) + { + reslutMsg = propertyInfo.GetDisplayName() + reslutMsg; + } + return (reslutMsg == "" ? true : false, reslutMsg, value); + } + + public static string GetDisplayName(this PropertyInfo property) + { + string displayName = property.GetTypeCustomValue(x => new { x.Name }); + if (string.IsNullOrEmpty(displayName)) + { + return property.Name; + } + return displayName; + } + + /// + /// 获取属性的指定属性 + /// + /// + /// + /// + public static object GetTypeCustomAttributes(this MemberInfo member, Type type) + { + object[] obj = member.GetCustomAttributes(type, false); + if (obj.Length == 0) return null; + return obj[0]; + } + + /// + /// 获取类的多个指定属性的值 + /// + /// 当前类 + /// 指定的类 + /// 指定属性的值 格式 Expression> exp = x => new { x.字段1, x.字段2 }; + /// 返回的是字段+value + public static Dictionary GetTypeCustomValues(this MemberInfo member, Expression> expression) + { + var attr = member.GetTypeCustomAttributes(typeof(TEntity)); + if (attr == null) + { + return null; + } + + string[] propertyName = expression.GetExpressionProperty(); + Dictionary propertyKeyValues = new Dictionary(); + + foreach (PropertyInfo property in attr.GetType().GetProperties()) + { + if (propertyName.Contains(property.Name)) + { + propertyKeyValues[property.Name] = (property.GetValue(attr) ?? string.Empty).ToString(); + } + } + return propertyKeyValues; + } + + /// + /// 获取类的单个指定属性的值(只会返回第一个属性的值) + /// + /// 当前类 + /// 指定的类 + /// 指定属性的值 格式 Expression> exp = x => new { x.字段1, x.字段2 }; + /// + public static string GetTypeCustomValue(this MemberInfo member, Expression> expression) + { + var propertyKeyValues = member.GetTypeCustomValues(expression); + if (propertyKeyValues == null || propertyKeyValues.Count == 0) + { + return null; + } + return propertyKeyValues.First().Value ?? ""; + } + /// + /// 获取表带有EntityAttribute属性的真实表名 + /// + /// + /// + public static string GetEntityTableName(this Type type) + { + Attribute attribute = type.GetCustomAttribute(typeof(EntityAttribute)); + if (attribute != null && attribute is EntityAttribute) + { + return (attribute as EntityAttribute).TableName ?? type.Name; + } + return type.Name; + } + + +} + +public class ArrayEntity +{ + public string column1 { get; set; } +} + +public enum FieldType +{ + VarChar = 0, + NvarChar, + Int, + BigInt, + UniqueIdentifier +} + +public enum EntityToSqlTempName +{ + TempInsert = 0 +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/GenericExtension.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/GenericExtension.cs new file mode 100644 index 00000000..c07435f2 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/GenericExtension.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; + +namespace Tiobon.Core.Common.DB.Dapper.Extensions; + +/// +/// 泛型扩展 +/// +public static class GenericExtension +{ + + public static DataTable ToDataTable(this IEnumerable source, Expression> columns = null, bool contianKey = true) + { + DataTable dtReturn = new DataTable(); + if (source == null) return dtReturn; + + PropertyInfo[] oProps = typeof(T).GetProperties() + .Where(x => x.PropertyType.Name != "List`1").ToArray(); + if (columns != null) + { + string[] columnArray = columns.GetExpressionToArray(); + oProps = oProps.Where(x => columnArray.Contains(x.Name)).ToArray(); + } + //移除自增主键 + PropertyInfo keyType = oProps.GetKeyProperty();// oProps.GetKeyProperty()?.PropertyType; + if (!contianKey && keyType != null && (keyType.PropertyType == typeof(int) || keyType.PropertyType == typeof(long))) + { + oProps = oProps.Where(x => x.Name != keyType.Name).ToArray(); + } + + foreach (var pi in oProps) + { + var colType = pi.PropertyType; + + if ((colType.IsGenericType) && (colType.GetGenericTypeDefinition() == typeof(Nullable<>))) + { + colType = colType.GetGenericArguments()[0]; + } + + dtReturn.Columns.Add(new DataColumn(pi.Name, colType)); + } + foreach (var rec in source) + { + var dr = dtReturn.NewRow(); + foreach (var pi in oProps) + { + dr[pi.Name] = pi.GetValue(rec, null) == null + ? DBNull.Value + : pi.GetValue + (rec, null); + } + dtReturn.Rows.Add(dr); + } + return dtReturn; + } + +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/LambdaExtensions.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/LambdaExtensions.cs new file mode 100644 index 00000000..e9d1a82b --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/LambdaExtensions.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Reflection; +using Tiobon.Core.Common.DB.Dapper.Enums; + +namespace Tiobon.Core.Common.DB.Dapper.Extensions +{ + public static class LambdaExtensions + { + /// + /// 获取对象表达式指定属性的值 + /// 如获取:Out_Scheduling对象的ID或基他字段 + /// + /// + /// 格式 Expression>sch=x=>new {x.v1,x.v2} or x=>x.v1 解析里面的值返回为数组 + /// + public static string[] GetExpressionToArray(this Expression> expression) + { + string[] propertyNames = null; + if (expression.Body is MemberExpression) + { + propertyNames = new string[] { ((MemberExpression)expression.Body).Member.Name }; + } + else + { + propertyNames = expression.GetExpressionProperty().Distinct().ToArray(); + } + return propertyNames; + } + + /// + /// 属性判断待完 + /// + /// + /// + public static IEnumerable GetGenericProperties(this Type type) + { + return type.GetProperties().GetGenericProperties(); + } + /// + /// 属性判断待完 + /// + /// + /// + public static IEnumerable GetGenericProperties(this IEnumerable properties) + { + return properties.Where(x => !x.PropertyType.IsGenericType && x.PropertyType.GetInterface("IList") == null || x.PropertyType.GetInterface("IEnumerable", false) == null); + } + } + + public class ParameterRebinder : ExpressionVisitor + { + + private readonly Dictionary map; + public ParameterRebinder(Dictionary map) + { + this.map = map ?? new Dictionary(); + } + + public static Expression ReplaceParameters(Dictionary map, Expression exp) + { + return new ParameterRebinder(map).Visit(exp); + } + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/MethodInfoExtensions.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/MethodInfoExtensions.cs new file mode 100644 index 00000000..b889e425 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/MethodInfoExtensions.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; + +namespace Tiobon.Core.Common.DB.Dapper.Extensions; + +public static class MethodInfoExtensions +{ + public static string GetFullName(this MethodInfo method) + { + if (method.DeclaringType == null) + { + return $@"{method.Name}"; + } + + return $"{method.DeclaringType.FullName}.{method.Name}"; + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/ServerExtension.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/ServerExtension.cs new file mode 100644 index 00000000..88b32212 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/ServerExtension.cs @@ -0,0 +1,31 @@ +using Tiobon.Core.Common.DB.Dapper.BaseProvider.ServerMapPath; +using System; +using System.Collections.Generic; +using System.Text; +using Tiobon.Core.Common.DB.Dapper.Extensions.AutofacManager; + +namespace Tiobon.Core.Common.DB.Dapper.Extensions +{ + public static class ServerExtension + { + /// + /// 返回的路径后面不带/,拼接时需要自己加上/ + /// + /// + /// + public static string MapPath(this string path) + { + return MapPath(path, false); + } + /// + /// + /// + /// + /// 获取wwwroot路径 + /// + public static string MapPath(this string path,bool rootPath) + { + return AutofacContainerModule.GetService().MapPath(path,rootPath); + } + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/ServiceProviderManagerExtension.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/ServiceProviderManagerExtension.cs new file mode 100644 index 00000000..f4bd9706 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/ServiceProviderManagerExtension.cs @@ -0,0 +1,18 @@ +using Tiobon.Core.Common.DB.Dapper.Extensions; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Text; + +namespace Tiobon.Core.Common.DB.Dapper.Extensions +{ + public static class ServiceProviderManagerExtension + { + public static object GetService(this Type serviceType) + { + // HttpContext.Current.RequestServices.GetRequiredService(serviceType); + return Utilities.HttpContext.Current.RequestServices.GetService(serviceType); + } + + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/SimpleDapperSetup.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/SimpleDapperSetup.cs new file mode 100644 index 00000000..62389df2 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/SimpleDapperSetup.cs @@ -0,0 +1,14 @@ +using Microsoft.Extensions.DependencyInjection; + +namespace Tiobon.Core.Common.DB.Dapper.Extensions; + +/// +/// Tiobon.Core.Common.DB.Dapper 启动服务 +/// +public static class SimpleDapperSetup +{ + public static void AddSimpleDapperSetup(this IServiceCollection services) + { + AppSetting.Init(); + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Extensions/StringExtension.cs b/Tiobon.Core.Common/DB/Dapper/Extensions/StringExtension.cs new file mode 100644 index 00000000..ff87aae4 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Extensions/StringExtension.cs @@ -0,0 +1,117 @@ +using System; +using System.Runtime.InteropServices; +using System.Text.RegularExpressions; +using Tiobon.Core.Common.DB.Dapper.Const; +using Tiobon.Core.Common.DB.Dapper.Enums; + +namespace Tiobon.Core.Common.DB.Dapper.Extensions +{ + public static class StringExtension + { + public static bool _windows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + public static string ReplacePath(this string path) + { + if (string.IsNullOrEmpty(path)) + return ""; + if (_windows) + return path.Replace("/", "\\"); + return path.Replace("\\", "/"); + + } + + public static bool GetGuid(this string guid, out Guid outId) + { + Guid emptyId = Guid.Empty; + return Guid.TryParse(guid, out outId); + } + + public static bool IsGuid(this string guid) + { + Guid newId; + return guid.GetGuid(out newId); + } + + public static bool IsInt(this object obj) + { + if (obj == null) + return false; + bool reslut = Int32.TryParse(obj.ToString(), out int _number); + return reslut; + + } + public static bool IsDate(this object str) + { + return str.IsDate(out _); + } + public static bool IsDate(this object str, out DateTime dateTime) + { + dateTime = DateTime.Now; + if (str == null || str.ToString() == "") + { + return false; + } + return DateTime.TryParse(str.ToString(), out dateTime); + } + /// + /// 根据传入格式判断是否为小数 + /// + /// + /// 18,5 + /// + public static bool IsNumber(this string str, string formatString) + { + if (string.IsNullOrEmpty(str)) + return false; + int precision = 32; + int scale = 5; + try + { + if (string.IsNullOrEmpty(formatString)) + { + precision = 10; + scale = 2; + } + else + { + string[] numbers = formatString.Split(','); + precision = Convert.ToInt32(numbers[0]); + scale = numbers.Length == 0 ? 2 : Convert.ToInt32(numbers[1]); + } + } + catch { }; + return IsNumber(str, precision, scale); + } + /**/ + /// + /// 判断一个字符串是否为合法数字(指定整数位数和小数位数) + /// + /// 字符串 + /// 整数位数 + /// 小数位数 + /// + public static bool IsNumber(this string str, int precision, int scale) + { + if ((precision == 0) && (scale == 0)) + { + return false; + } + string pattern = @"(^\d{1," + precision + "}"; + if (scale > 0) + { + pattern += @"\.\d{0," + scale + "}$)|" + pattern; + } + pattern += "$)"; + return Regex.IsMatch(str, pattern); + } + + + public static int GetInt(this object obj) + { + if (obj == null) + return 0; + int.TryParse(obj.ToString(), out int _number); + return _number; + + } + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/ISqlDapper.cs b/Tiobon.Core.Common/DB/Dapper/ISqlDapper.cs new file mode 100644 index 00000000..e7ccd710 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/ISqlDapper.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq.Expressions; +using System.Threading.Tasks; +using Dapper; + +namespace Tiobon.Core.Common.DB.Dapper; + +public interface ISqlDapper +{ + /// + /// var p = new object(); + // p.Add("@a", 11); + //p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output); + //p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); + // /// + IDbConnection Connection { get; } + /// + /// + /// + /// + /// + List QueryList(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false) where T : class; + Task> QueryListAsync(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false, int? commandTimeout = null) where T : class; + T QueryFirst(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false) where T : class; + Task QueryFirstAsync(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false, int? commandTimeout = null) where T : class; + object ExecuteScalar(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false); + Task ExecuteScalarAsync(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false); + + int ExcuteNonQuery(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false); + IDataReader ExecuteReader(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false); + SqlMapper.GridReader QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false); + (List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false); + (List, List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false); + + DataTable GetDataTable(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false); + Task GetDataTableAsync(string cmd, object param = null, IDbTransaction transaction = null, CommandType? commandType = null, int? commandTimeout = null); + + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + int Add(T entity, Expression> updateFileds = null, bool beginTransaction = false); + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + int AddRange(IEnumerable entities, Expression> updateFileds = null, bool beginTransaction = false); + + + /// + /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开 + /// + /// + /// 实体必须带主键 + /// 指定更新的字段x=new {x.a,x.b} + /// 是否开启事务 + /// + int Update(T entity, Expression> updateFileds = null, bool beginTransaction = false); + + /// + /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开 + /// + /// + /// 实体必须带主键 + /// 指定更新的字段x=new {x.a,x.b} + /// 是否开启事务 + /// + int UpdateRange(IEnumerable entities, Expression> updateFileds = null, bool beginTransaction = false); + + int DelWithKey(object[] keys); + int DelWithKey(object[] keys, bool beginTransaction = false); + /// + /// sqlserver批量写入 + /// 使用时DataTable table表字段顺序要和数据库字段顺序一致 + /// + /// mysql批量写入 + /// + /// + /// + /// 默认当前下载路径 + /// 默认$"{DateTime.Now.ToString("yyyyMMddHHmmss")}.csv" + /// + int BulkInsert(DataTable table, string tableName, SqlBulkCopyOptions? sqlBulkCopyOptions = null, string fileName = null, string tmpPath = null); + /// + /// + /// + /// + /// + /// + /// 所包含的列 + /// + /// + /// + /// + int BulkInsert(List entities, string tableName = null, + Expression> columns = null, + SqlBulkCopyOptions? sqlBulkCopyOptions = null); + + T Execute(Func func, bool beginTransaction = false, bool disposeConn = true); + + int ExecuteDML(string cmd, object param = null, CommandType? commandType = null, IDbTransaction dbTransaction = null); + Task ExecuteDMLAsync(string cmd, object param = null, CommandType? commandType = null, IDbTransaction dbTransaction = null); + + IDbTransaction GetNewTransaction(); + + void CommitTransaction(IDbTransaction dbTransaction); + void RollbackTransaction(IDbTransaction dbTransaction); + DataTable GetTransDataTable(string cmd, object param = null, CommandType? commandType = null, IDbTransaction dbTransaction = null); + T QueryTransFirst(string cmd, object param = null, CommandType? commandType = null, IDbTransaction dbTransaction = null) where T : class; +} \ No newline at end of file diff --git a/Tiobon.Core.Common/DB/Dapper/ITransDapper.cs b/Tiobon.Core.Common/DB/Dapper/ITransDapper.cs new file mode 100644 index 00000000..949a2037 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/ITransDapper.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq.Expressions; +using Dapper; + +namespace Tiobon.Core.Common.DB.Dapper; + +public interface ITransDapper +{ + + void BeginTransaction(Func action, Action error, bool disposeConn = true); + + /// + /// var p = new object(); + // p.Add("@a", 11); + //p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output); + //p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); + // /// + /// + /// + /// + /// + /// + List QueryList(string cmd, object param, CommandType? commandType = null) where T : class; + T QueryFirst(string cmd, object param, CommandType? commandType = null) where T : class; + object ExecuteScalar(string cmd, object param, CommandType? commandType = null); + + int ExcuteNonQuery(string cmd, object param, CommandType? commandType = null); + IDataReader ExecuteReader(string cmd, object param, CommandType? commandType = null); + SqlMapper.GridReader QueryMultiple(string cmd, object param, CommandType? commandType = null); + (List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null); + (List, List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null); + + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + int Add(T entity, Expression> updateFileds = null); + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + int AddRange(IEnumerable entities, Expression> updateFileds = null); + + + /// + /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开 + /// + /// + /// 实体必须带主键 + /// 指定更新的字段x=new {x.a,x.b} + /// 是否开启事务 + /// + int Update(T entity, Expression> updateFileds = null); + + /// + /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开 + /// + /// + /// 实体必须带主键 + /// 指定更新的字段x=new {x.a,x.b} + /// 是否开启事务 + /// + int UpdateRange(IEnumerable entities, Expression> updateFileds = null); + + int DelWithKey(params object[] keys); + /// + /// sqlserver批量写入 + /// 使用时DataTable table表字段顺序要和数据库字段顺序一致 + /// + /// mysql批量写入 + /// + /// + /// + /// 默认当前下载路径 + /// 默认$"{DateTime.Now.ToString("yyyyMMddHHmmss")}.csv" + /// + int BulkInsert(DataTable table, string tableName, SqlBulkCopyOptions? sqlBulkCopyOptions = null, string fileName = null, string tmpPath = null); + /// + /// + /// + /// + /// + /// + /// 所包含的列 + /// + /// + /// + /// + int BulkInsert(List entities, string tableName = null, + Expression> columns = null, + SqlBulkCopyOptions? sqlBulkCopyOptions = null); + + DataTable GetDataTable(string cmd, object param, CommandType? commandType = null); +} \ No newline at end of file diff --git a/Tiobon.Core.Common/DB/Dapper/SimpleDapper.csproj b/Tiobon.Core.Common/DB/Dapper/SimpleDapper.csproj new file mode 100644 index 00000000..9a7ca487 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/SimpleDapper.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + True + + + + + + + + false + + + + + + + + + + + + + + + + diff --git a/Tiobon.Core.Common/DB/Dapper/SqlDapper.cs b/Tiobon.Core.Common/DB/Dapper/SqlDapper.cs new file mode 100644 index 00000000..3859404f --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/SqlDapper.cs @@ -0,0 +1,665 @@ + +using Dapper; +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq; +using System.Linq.Expressions; +using System.Text; +using Tiobon.Core.Common.DB.Dapper.Const; +using Tiobon.Core.Common.DB.Dapper.DBManager; +using Tiobon.Core.Common.DB.Dapper.Enums; +using Tiobon.Core.Common.DB.Dapper.Extensions; +using Tiobon.Core.Common.DB.Dapper.Utilities; +using System.Threading.Tasks; + +namespace Tiobon.Core.Common.DB.Dapper; + +public class SqlDapper : ISqlDapper +{ + private string _connectionString; + private IDbConnection _connection { get; set; } + public IDbConnection Connection + { + get + { + if (_connection == null || _connection.State == ConnectionState.Closed) + { + _connection = DBServerProvider.GetDbConnection(_connectionString); + } + return _connection; + } + } + public SqlDapper() + { + _connectionString = DBServerProvider.GetConnectionString(); + } + /// + /// string mySql = "Data Source=132.232.2.109;Database=mysql;User + /// ID=root;Password=mysql;pooling=true;CharSet=utf8;port=3306;sslmode=none"; + /// this.conn = new MySql.Data.MySqlClient.MySqlConnection(mySql); + /// + /// + public SqlDapper(string connKeyName) + { + _connectionString = DBServerProvider.GetConnectionString(connKeyName); + } + + /// + /// var p = new object(); + // p.Add("@a", 11); + //p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output); + //p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); + // /// + /// + /// + /// + /// + /// + public List QueryList(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class + { + return Execute((conn, dbTransaction) => + { + return conn.Query(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text).ToList(); + }, beginTransaction); + } + + public async Task> QueryListAsync(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false, int? commandTimeout = null) where T : class + { + return await Execute(async (conn, dbTransaction) => + { + return (await conn.QueryAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text)).ToList(); + }, beginTransaction); + } + + + public T QueryFirst(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false) where T : class + { + List list = QueryList(cmd, param, commandType: commandType ?? CommandType.Text, beginTransaction: beginTransaction).ToList(); + return list.Count == 0 ? null : list[0]; + } + public async Task QueryFirstAsync(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false, int? commandTimeout = null) where T : class + { + var data = await QueryListAsync(cmd, param, commandType, beginTransaction, commandTimeout); + List list = data.ToList(); + return !list.Any() ? null : list[0]; + } + + public object ExecuteScalar(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) + { + try + { + return Execute((conn, dbTransaction) => + { + return conn.ExecuteScalar(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }, beginTransaction); + } + catch (Exception) + { + throw; + } + } + + public async Task ExecuteScalarAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) + { + try + { + return await Execute(async (conn, dbTransaction) => + { + return await conn.ExecuteScalarAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }, beginTransaction); + } + catch (Exception) + { + throw; + } + } + + public int ExcuteNonQuery(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) + { + return Execute((conn, dbTransaction) => + { + return conn.Execute(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }, beginTransaction); + } + public IDataReader ExecuteReader(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) + { + return Execute((conn, dbTransaction) => + { + return conn.ExecuteReader(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }, beginTransaction, false); + } + public SqlMapper.GridReader QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) + { + return Execute((conn, dbTransaction) => + { + return conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }, beginTransaction, false); + } + + /// + /// 获取output值 param.Get("@b"); + /// + /// + /// + /// + /// + /// + /// + public (List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) + { + using (SqlMapper.GridReader reader = QueryMultiple(cmd, param, commandType, beginTransaction)) + { + return (reader.Read().ToList(), reader.Read().ToList()); + } + } + + public (List, List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) + { + using (SqlMapper.GridReader reader = QueryMultiple(cmd, param, commandType, beginTransaction)) + { + return (reader.Read().ToList(), reader.Read().ToList(), reader.Read().ToList()); + } + } + + + public T Execute(Func func, bool beginTransaction = false, bool disposeConn = true) + { + IDbTransaction dbTransaction = null; + + if (beginTransaction) + { + Connection.Open(); + dbTransaction = Connection.BeginTransaction(); + } + try + { + T reslutT = func(Connection, dbTransaction); + dbTransaction?.Commit(); + return reslutT; + } + catch (Exception) + { + dbTransaction?.Rollback(); + Connection.Dispose(); + throw; + } + finally + { + if (disposeConn) + { + Connection.Dispose(); + } + } + } + + public async Task ExecuteAsync(Func> funcAsync, bool beginTransaction = false, bool disposeConn = true) + { + IDbTransaction dbTransaction = null; + + if (beginTransaction) + { + Connection.Open(); + dbTransaction = Connection.BeginTransaction(); + } + try + { + T reslutT = await funcAsync(Connection, dbTransaction); + dbTransaction?.Commit(); + return reslutT; + } + catch (Exception) + { + dbTransaction?.Rollback(); + Connection.Dispose(); + throw; + } + finally + { + if (disposeConn) + { + Connection.Dispose(); + } + } + } + + public int ExecuteDML(string cmd, object param, CommandType? commandType = null, IDbTransaction dbTransaction = null) + { + return ExecuteDML((conn, dbTransaction) => + { + return conn.Execute(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }, dbTransaction, false); + } + + public async Task ExecuteDMLAsync(string cmd, object param, CommandType? commandType = null, IDbTransaction dbTransaction = null) + { + return await ExecuteDML(async (conn, dbTransaction) => + { + return await conn.ExecuteAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }, dbTransaction, false); + } + + public IDataReader ExecuteDMLReader(string cmd, object param, CommandType? commandType = null, IDbTransaction dbTransaction = null) + { + return ExecuteDML((conn, dbTransaction) => + { + return conn.ExecuteReader(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }, dbTransaction, false); + } + + + /// + /// 执行数据库 + /// + /// + /// + /// + /// + /// + public T ExecuteDML(Func func, IDbTransaction dbTransaction = null, bool disposeConn = false) + { + if (dbTransaction == null) + { + try + { + T reslutT = func(Connection, dbTransaction); + dbTransaction?.Commit(); + return reslutT; + } + catch (Exception) + { + dbTransaction?.Rollback(); + Connection.Dispose(); + throw; + } + finally + { + if (disposeConn) + Connection.Dispose(); + } + } + else + { + + //Connection.Open(); + + try + { + if (_connection == null) + _connection = dbTransaction.Connection; + T reslutT = func(Connection, dbTransaction); + return reslutT; + } + catch (Exception) + { + Connection.Dispose(); + throw; + } + finally + { + if (disposeConn) + Connection.Dispose(); + } + } + + } + + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + public int Add(T entity, Expression> updateFileds = null, bool beginTransaction = false) + { + return AddRange(new T[] { entity }, updateFileds, beginTransaction); + } + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + public int AddRange(IEnumerable entities, Expression> addFileds = null, bool beginTransaction = true) + { + Type entityType = typeof(T); + var key = entityType.GetKeyProperty(); + if (key == null) + { + throw new Exception("实体必须包括主键才能批量更新"); + } + string[] columns; + + //指定插入的字段 + if (addFileds != null) + { + columns = addFileds.GetExpressionToArray(); + } + else + { + var properties = entityType.GetGenericProperties(); + if (key.PropertyType != typeof(Guid)) + { + properties = properties.Where(x => x.Name != key.Name).ToArray(); + } + columns = properties.Select(x => x.Name).ToArray(); + } + string sql = null; + bool mysql = DBType.Name == DbCurrentType.MySql.ToString(); + if (mysql) + { + //mysql批量写入待优化 + sql = $"insert into {entityType.GetEntityTableName()}({string.Join(",", columns)})" + + $"values(@{string.Join(",@", columns)});"; + } + else + { + //sqlserver通过临时表批量写入 + sql = $"insert into {entityType.GetEntityTableName()}({string.Join(",", columns)})" + + $"select * from {EntityToSqlTempName.TempInsert};"; + sql = entities.GetEntitySql(entityType == typeof(Guid), sql, null, addFileds, null); + } + return Execute((conn, dbTransaction) => + { + return conn.Execute(sql, mysql ? entities.ToList() : null); + }, beginTransaction); + } + + + /// + /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开 + /// + /// + /// 实体必须带主键 + /// 指定更新的字段x=new {x.a,x.b} + /// 是否开启事务 + /// + public int Update(T entity, Expression> updateFileds = null, bool beginTransaction = true) + { + return UpdateRange(new T[] { entity }, updateFileds, beginTransaction); + } + + /// + ///(根据主键批量更新实体) sqlserver使用的临时表参数化批量更新,mysql待优化 + /// + /// + /// 实体必须带主键 + /// 批定更新字段 + /// + /// + public int UpdateRange(IEnumerable entities, Expression> updateFileds = null, bool beginTransaction = true) + { + Type entityType = typeof(T); + var key = entityType.GetKeyProperty(); + if (key == null) + { + throw new Exception("实体必须包括主键才能批量更新"); + } + + var properties = entityType.GetGenericProperties() + .Where(x => x.Name != key.Name); + if (updateFileds != null) + { + properties = properties.Where(x => updateFileds.GetExpressionToArray().Contains(x.Name)); + } + + if (DBType.Name == DbCurrentType.MySql.ToString()) + { + List paramsList = new List(); + foreach (var item in properties) + { + paramsList.Add(item.Name + "=@" + item.Name); + } + string sqltext = $@"UPDATE {entityType.GetEntityTableName()} SET {string.Join(",", paramsList)} WHERE {entityType.GetKeyName()} = @{entityType.GetKeyName()} ;"; + + return ExcuteNonQuery(sqltext, entities, CommandType.Text, true); + // throw new Exception("mysql批量更新未实现"); + } + string fileds = string.Join(",", properties.Select(x => $" a.{x.Name}=b.{x.Name}").ToArray()); + string sql = $"update a set {fileds} from {entityType.GetEntityTableName()} as a inner join {EntityToSqlTempName.TempInsert.ToString()} as b on a.{key.Name}=b.{key.Name}"; + sql = entities.ToList().GetEntitySql(true, sql, null, updateFileds, null); + return ExcuteNonQuery(sql, null, CommandType.Text, true); + } + + public int DelWithKey(object[] keys, bool beginTransaction = false) + { + Type entityType = typeof(T); + var keyProperty = entityType.GetKeyProperty(); + if (keyProperty == null || keys == null || keys.Length == 0) return 0; + + IEnumerable<(bool, string, object)> validation = keyProperty.ValidationValueForDbType(keys); + if (validation.Any(x => !x.Item1)) + { + throw new Exception($"主键类型【{validation.Where(x => !x.Item1).Select(s => s.Item3).FirstOrDefault()}】不正确"); + } + string tKey = entityType.GetKeyProperty().Name; + FieldType fieldType = entityType.GetFieldType(); + string joinKeys = fieldType == FieldType.Int || fieldType == FieldType.BigInt + ? string.Join(",", keys) + : $"'{string.Join("','", keys)}'"; + + string sql = $"DELETE FROM {entityType.GetEntityTableName()} where {tKey} in ({joinKeys});"; + return (int)ExecuteScalar(sql, null); + } + /// + /// 使用key批量删除 + /// + /// + /// + /// + public int DelWithKey(object[] keys) + { + return DelWithKey(keys, false); + } + + #region 批量插入 + /// + /// 通过Bulk批量插入 + /// + /// + /// + /// + /// + /// + private int MSSqlBulkInsert(DataTable table, string tableName, SqlBulkCopyOptions sqlBulkCopyOptions = SqlBulkCopyOptions.UseInternalTransaction, string dbKeyName = null) + { + if (!string.IsNullOrEmpty(dbKeyName)) + { + Connection.ConnectionString = DBServerProvider.GetConnectionString(dbKeyName); + } + using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(Connection.ConnectionString, sqlBulkCopyOptions)) + { + sqlBulkCopy.DestinationTableName = tableName; + sqlBulkCopy.BatchSize = table.Rows.Count; + for (int i = 0; i < table.Columns.Count; i++) + { + sqlBulkCopy.ColumnMappings.Add(table.Columns[i].ColumnName, table.Columns[i].ColumnName); + } + sqlBulkCopy.WriteToServer(table); + return table.Rows.Count; + } + } + public int BulkInsert(List entities, string tableName = null, + Expression> columns = null, + SqlBulkCopyOptions? sqlBulkCopyOptions = null) + { + DataTable table = entities.ToDataTable(columns, false); + return BulkInsert(table, tableName ?? typeof(T).GetEntityTableName(), sqlBulkCopyOptions); + } + public int BulkInsert(DataTable table, string tableName, SqlBulkCopyOptions? sqlBulkCopyOptions = null, string fileName = null, string tmpPath = null) + { + if (!string.IsNullOrEmpty(tmpPath)) + { + tmpPath = tmpPath.ReplacePath(); + } + if (Connection.GetType().Name == "MySqlConnection") + return MySqlBulkInsert(table, tableName, fileName, tmpPath); + return MSSqlBulkInsert(table, tableName, sqlBulkCopyOptions ?? SqlBulkCopyOptions.KeepIdentity); + } + #endregion + + #region 大批量数据插入,返回成功插入行数 + /// + ///大批量数据插入,返回成功插入行数 + /// + /// 数据库连接字符串 + /// 数据表 + /// 返回成功插入行数 + private int MySqlBulkInsert(DataTable table, string tableName, string fileName = null, string tmpPath = null) + { + if (table.Rows.Count == 0) + return 0; + tmpPath = tmpPath ?? FileHelper.GetCurrentDownLoadPath(); + fileName = fileName ?? $"{DateTime.Now.ToString("yyyyMMddHHmmss")}.csv"; + int insertCount = 0; + string csv = DataTableToCsv(table); + FileHelper.WriteFile(tmpPath, fileName, csv); + string path = tmpPath + fileName; + try + { + if (Connection.State == ConnectionState.Closed) + Connection.Open(); + using (IDbTransaction tran = Connection.BeginTransaction()) + { + MySqlBulkLoader bulk = new MySqlBulkLoader(Connection as MySqlConnection) + { + FieldTerminator = ",", + FieldQuotationCharacter = '"', + EscapeCharacter = '"', + LineTerminator = "\r\n", + FileName = path.ReplacePath(), + NumberOfLinesToSkip = 0, + TableName = tableName, + }; + bulk.Columns.AddRange(table.Columns.Cast().Select(colum => colum.ColumnName).ToList()); + insertCount = bulk.Load(); + tran.Commit(); + } + } + catch (Exception) { throw; } + finally + { + Connection?.Dispose(); + Connection?.Close(); + } + return insertCount; + // File.Delete(path); + } + #endregion + + #region 将DataTable转换为标准的CSV + /// + ///将DataTable转换为标准的CSV + /// + /// 数据表 + /// 返回标准的CSV + private string DataTableToCsv(DataTable table) + { + //以半角逗号(即,)作分隔符,列为空也要表达其存在。 + //列内容如存在半角逗号(即,)则用半角引号(即"")将该字段值包含起来。 + //列内容如存在半角引号(即")则应替换成半角双引号("")转义,并用半角引号(即"")将该字段值包含起来。 + StringBuilder sb = new StringBuilder(); + DataColumn colum; + Type typeString = typeof(string); + Type typeDate = typeof(DateTime); + + foreach (DataRow row in table.Rows) + { + for (int i = 0; i < table.Columns.Count; i++) + { + colum = table.Columns[i]; + if (i != 0) sb.Append(","); + if (colum.DataType == typeString && row[colum].ToString().Contains(",")) + { + sb.Append("\"" + row[colum].ToString().Replace("\"", "\"\"") + "\""); + } + else if (colum.DataType == typeDate) + { + //centos系统里把datatable里的日期转换成了10/18/18 3:26:15 PM格式 + bool b = DateTime.TryParse(row[colum].ToString(), out DateTime dt); + sb.Append(b ? dt.ToString("yyyy-MM-dd HH:mm:ss") : ""); + } + else sb.Append(row[colum].ToString()); + } + sb.AppendLine(); + } + + return sb.ToString(); + } + #endregion + + #region 返回DataTable + /// + /// 返回DataTable + /// + /// + /// + /// + /// + /// + public DataTable GetDataTable(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) + { + DataTable table = new DataTable("MyTable"); + var reader = ExecuteReader(cmd, param, commandType, beginTransaction); + table.Load(reader); + return table; + } + + public DataTable GetTransDataTable(string cmd, object param, CommandType? commandType = null, IDbTransaction dbTransaction = null) + { + DataTable table = new DataTable("MyTable"); + var reader = ExecuteDMLReader(cmd, param, commandType, dbTransaction); + table.Load(reader); + return table; + } + + public async Task GetDataTableAsync(string cmd, object param = null, IDbTransaction transaction = null, CommandType? commandType = null, int? commandTimeout = null) + { + DataTable table = new DataTable("MyTable"); + var reader = await Connection.ExecuteReaderAsync(cmd, param, transaction, commandTimeout, commandType: commandType ?? CommandType.Text); ; + table.Load(reader); + return table; + } + #endregion + + #region Transaction + public IDbTransaction GetNewTransaction() + { + Connection.Open(); + IDbTransaction trans = Connection.BeginTransaction(); + return trans; + } + + public void CommitTransaction(IDbTransaction dbTransaction) + { + + dbTransaction?.Commit(); + } + + public void RollbackTransaction(IDbTransaction dbTransaction) + { + dbTransaction?.Rollback(); + } + #endregion Transaction + + #region 查询按实体返回 + public List QueryTransList(string cmd, object param, CommandType? commandType = null, IDbTransaction dbTransaction = null) where T : class + { + return ExecuteDML((conn, dbTransaction) => + { + return conn.Query(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text).ToList(); + }, dbTransaction, false); + } + public T QueryTransFirst(string cmd, object param, CommandType? commandType = null, IDbTransaction dbTransaction = null) where T : class + { + List list = QueryTransList(cmd, param, commandType: commandType ?? CommandType.Text, dbTransaction: dbTransaction).ToList(); + return list.Count == 0 ? null : list[0]; + } + #endregion +} diff --git a/Tiobon.Core.Common/DB/Dapper/TransDapper.cs b/Tiobon.Core.Common/DB/Dapper/TransDapper.cs new file mode 100644 index 00000000..bb1f5ec1 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/TransDapper.cs @@ -0,0 +1,495 @@ + +using Dapper; +using Tiobon.Core.Common.DB.Dapper.Const; +using Tiobon.Core.Common.DB.Dapper.DBManager; +using Tiobon.Core.Common.DB.Dapper.Enums; +using Tiobon.Core.Common.DB.Dapper.Extensions; +using Tiobon.Core.Common.DB.Dapper.Utilities; +using MySql.Data.MySqlClient; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations.Schema; +using System.Data; +using System.Data.SqlClient; +using System.Dynamic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + + +namespace Tiobon.Core.Common.DB.Dapper; + +public class TransDapper : ITransDapper +{ + private string _connectionString; + private IDbConnection _connection { get; set; } + public IDbConnection Connection + { + get + { + if (_connection == null || _connection.State == ConnectionState.Closed) + _connection = DBServerProvider.GetDbConnection(_connectionString); + return _connection; + } + } + + + public TransDapper() + { + _connectionString = DBServerProvider.GetConnectionString(); + } + /// + /// string mySql = "Data Source=132.232.2.109;Database=mysql;User + /// ID=root;Password=mysql;pooling=true;CharSet=utf8;port=3306;sslmode=none"; + /// this.conn = new MySql.Data.MySqlClient.MySqlConnection(mySql); + /// + /// + public TransDapper(string connKeyName) + { + _connectionString = DBServerProvider.GetConnectionString(connKeyName); + } + + + private bool _transaction { get; set; } + + /// + /// 增加Dapper事务处理 + /// + /// + public void BeginTransaction(Func action, Action error, bool disposeConn = true) + { + _transaction = true; + try + { + Connection.Open(); + dbTransaction = Connection.BeginTransaction(); + bool result = action(this); + if (result) + { + dbTransaction?.Commit(); + } + else + { + dbTransaction?.Rollback(); + } + } + catch (Exception ex) + { + dbTransaction?.Rollback(); + error(ex); + } + finally + { + if (!_transaction) + { + if (disposeConn) + { + Connection.Dispose(); + } + dbTransaction?.Dispose(); + } + dbTransaction?.Dispose(); + _transaction = false; + } + } + + /// + /// var p = new object(); + // p.Add("@a", 11); + //p.Add("@b", dbType: DbType.Int32, direction: ParameterDirection.Output); + //p.Add("@c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue); + // /// + /// + /// + /// + /// + /// + public List QueryList(string cmd, object param, CommandType? commandType = null) where T : class + { + return Execute((conn) => + { + return conn.Query(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text).ToList(); + }); + } + public T QueryFirst(string cmd, object param, CommandType? commandType = null) where T : class + { + List list = QueryList(cmd, param, commandType: commandType ?? CommandType.Text).ToList(); + return list.Count == 0 ? null : list[0]; + } + public object ExecuteScalar(string cmd, object param, CommandType? commandType = null) + { + return Execute((conn) => + { + return conn.ExecuteScalar(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }); + } + + public int ExcuteNonQuery(string cmd, object param, CommandType? commandType = null) + { + return Execute((conn) => + { + return conn.Execute(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }); + } + public IDataReader ExecuteReader(string cmd, object param, CommandType? commandType = null) + { + return Execute((conn) => + { + return conn.ExecuteReader(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }); + } + public SqlMapper.GridReader QueryMultiple(string cmd, object param, CommandType? commandType = null) + { + return Execute((conn) => + { + return conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text); + }); + } + + /// + /// 获取output值 param.Get("@b"); + /// + /// + /// + /// + /// + /// + /// + public (List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null) + { + using (SqlMapper.GridReader reader = QueryMultiple(cmd, param, commandType)) + { + return (reader.Read().ToList(), reader.Read().ToList()); + } + } + + public (List, List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null) + { + using (SqlMapper.GridReader reader = QueryMultiple(cmd, param, commandType)) + { + return (reader.Read().ToList(), reader.Read().ToList(), reader.Read().ToList()); + } + } + IDbTransaction dbTransaction = null; + + private T Execute(Func func) + { + if (dbTransaction == null) throw new Exception("该方法用于事务,请使用DBHelper.Instance"); + try + { + T reslutT = func(Connection); + return reslutT; + } + catch (Exception ex) + { + throw; + } + } + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + public int Add(T entity, Expression> updateFileds = null) + { + return AddRange(new T[] { entity }, updateFileds); + } + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + public int AddRange(IEnumerable entities, Expression> addFileds = null) + { + Type entityType = typeof(T); + var key = entityType.GetKeyProperty(); + if (key == null) + throw new Exception("实体必须包括主键才能批量更新!"); + + string[] columns; + + //指定插入的字段 + if (addFileds != null) + columns = addFileds.GetExpressionToArray(); + + else + { + var properties = entityType.GetGenericProperties().Where(x => !x.ContainsCustomAttributes(typeof(NotMappedAttribute))); + //&& !string.IsNullOrEmpty(entityType.GetProperty(x.Name).GetValue(entities.FirstOrDefault())?.ToString())); + //var value = entityType.GetProperty(property.Name).GetValue(mainEntity)?.ToString(); + //if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value)) + //{ + // dbInsert.AddValue(key, value); + //} + //if (key.PropertyType != typeof(Guid)) + //{ + // properties = properties.Where(x => x.Name != key.Name).ToArray(); + //} + // 排除插入的为空的字段,避免影响数据库中的默认值 + //columns = properties.Select(x => x.Name).ToArray(); + columns = properties.Where(x => + { + foreach (var entitie in entities) + { + var data = typeof(T).GetProperty(x.Name).GetValue(entitie); + if (data != null) + return true; + } + return false; + }).Select(x => x.Name).ToArray(); + } + string sql = null; + if (DBType.Name == DbCurrentType.MySql.ToString()) + { + //mysql批量写入待优化 + sql = $"insert into {entityType.GetEntityTableName()}({string.Join(",", columns)})" + + $"values(@{string.Join(",@", columns)});"; + } + else if (DBType.Name == DbCurrentType.PgSql.ToString()) + { + //todo pgsql批量写入 待检查是否正确 + sql = $"insert into {entityType.GetEntityTableName()}({"\"" + string.Join("\",\"", columns) + "\""})" + + $"values(@{string.Join(",@", columns)});"; + } + else + { + //sqlserver通过临时表批量写入 + sql = $"insert into {entityType.GetEntityTableName()}({string.Join(",", columns)})" + + $"select {string.Join(",", columns)} from {EntityToSqlTempName.TempInsert};"; + //sql = entities.GetEntitySql(entityType == typeof(Guid), sql, null, addFileds, null); + sql = entities.GetEntitySql(true, sql, null, addFileds, null); + } + return Execute((conn) => + { + //todo pgsql待实现 + return conn.Execute(sql, DBType.Name == DbCurrentType.MySql.ToString() || DBType.Name == DbCurrentType.PgSql.ToString() ? entities.ToList() : null, dbTransaction); + }); + } + + + /// + /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开 + /// + /// + /// 实体必须带主键 + /// 指定更新的字段x=new {x.a,x.b} + /// 是否开启事务 + /// + public int Update(T entity, Expression> updateFileds = null) + { + return UpdateRange(new T[] { entity }, updateFileds); + } + + /// + ///(根据主键批量更新实体) sqlserver使用的临时表参数化批量更新,mysql待优化 + /// + /// + /// 实体必须带主键 + /// 批定更新字段 + /// + /// + public int UpdateRange(IEnumerable entities, Expression> updateFileds = null) + { + Type entityType = typeof(T); + var key = entityType.GetKeyProperty(); + if (key == null) + throw new Exception("实体必须包括主键才能批量更新"); + + var properties = entityType.GetGenericProperties().Where(x => x.Name != key.Name && !x.ContainsCustomAttributes(typeof(NotMappedAttribute))); + if (updateFileds != null) + properties = properties.Where(x => updateFileds.GetExpressionToArray().Contains(x.Name)); + + if (DBType.Name == DbCurrentType.MySql.ToString()) + { + List paramsList = new List(); + foreach (var item in properties) + { + paramsList.Add(item.Name + "=@" + item.Name); + } + string sqltext = $@"UPDATE {entityType.GetEntityTableName()} SET {string.Join(",", paramsList)} WHERE {entityType.GetKeyName()} = @{entityType.GetKeyName()} ;"; + + return ExcuteNonQuery(sqltext, entities, CommandType.Text); + // throw new Exception("mysql批量更新未实现"); + } + string fileds = string.Join(",", properties.Select(x => $" a.{x.Name}=b.{x.Name}").ToArray()); + string sql = $"update a set {fileds} from {entityType.GetEntityTableName()} as a inner join {EntityToSqlTempName.TempInsert.ToString()} as b on a.{key.Name}=b.{key.Name}"; + sql = entities.ToList().GetEntitySql(true, sql, null, updateFileds, null); + return ExcuteNonQuery(sql, null, CommandType.Text); + } + + public int DelWithKey(params object[] keys) + { + Type entityType = typeof(T); + var keyProperty = entityType.GetKeyProperty(); + if (keyProperty == null || keys == null || keys.Length == 0) return 0; + + IEnumerable<(bool, string, object)> validation = keyProperty.ValidationValueForDbType(keys); + if (validation.Any(x => !x.Item1)) + throw new Exception($"主键类型【{validation.Where(x => !x.Item1).Select(s => s.Item3).FirstOrDefault()}】不正确"); + + string tKey = entityType.GetKeyProperty().Name; + FieldType fieldType = entityType.GetFieldType(); + string joinKeys = fieldType == FieldType.Int || fieldType == FieldType.BigInt + ? string.Join(",", keys) + : $"'{string.Join("','", keys)}'"; + + string sql = $"DELETE FROM {entityType.GetEntityTableName()} where {tKey} in ({joinKeys});"; + return ExcuteNonQuery(sql, null); + } + + /// + /// 通过Bulk批量插入 + /// + /// + /// + /// + /// + /// + private int MSSqlBulkInsert(DataTable table, string tableName, SqlBulkCopyOptions sqlBulkCopyOptions = SqlBulkCopyOptions.UseInternalTransaction, string dbKeyName = null) + { + if (!string.IsNullOrEmpty(dbKeyName)) + { + Connection.ConnectionString = DBServerProvider.GetConnectionString(dbKeyName); + } + using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(Connection.ConnectionString, sqlBulkCopyOptions)) + { + sqlBulkCopy.DestinationTableName = tableName; + sqlBulkCopy.BatchSize = table.Rows.Count; + for (int i = 0; i < table.Columns.Count; i++) + { + sqlBulkCopy.ColumnMappings.Add(table.Columns[i].ColumnName, table.Columns[i].ColumnName); + } + sqlBulkCopy.WriteToServer(table); + return table.Rows.Count; + } + } + public int BulkInsert(List entities, string tableName = null, + Expression> columns = null, + SqlBulkCopyOptions? sqlBulkCopyOptions = null) + { + DataTable table = entities.ToDataTable(columns, false); + return BulkInsert(table, tableName ?? typeof(T).GetEntityTableName(), sqlBulkCopyOptions); + } + public int BulkInsert(DataTable table, string tableName, SqlBulkCopyOptions? sqlBulkCopyOptions = null, string fileName = null, string tmpPath = null) + { + if (!string.IsNullOrEmpty(tmpPath)) + { + tmpPath = tmpPath.ReplacePath(); + } + if (Connection.GetType().Name == "MySqlConnection") + return MySqlBulkInsert(table, tableName, fileName, tmpPath); + else if (Connection.GetType().Name == "NpgsqlConnection") + { + //todo pgsql待实现 + throw new Exception("Pgsql的批量插入没实现,可以先把日志start注释跑起来"); + } + return MSSqlBulkInsert(table, tableName, sqlBulkCopyOptions ?? SqlBulkCopyOptions.KeepIdentity); + } + + /// + ///大批量数据插入,返回成功插入行数 + /// + /// 数据库连接字符串 + /// 数据表 + /// 返回成功插入行数 + private int MySqlBulkInsert(DataTable table, string tableName, string fileName = null, string tmpPath = null) + { + if (table.Rows.Count == 0) + return 0; + tmpPath = tmpPath ?? FileHelper.GetCurrentDownLoadPath(); + fileName = fileName ?? $"{DateTime.Now.ToString("yyyyMMddHHmmss")}.csv"; + int insertCount = 0; + string csv = DataTableToCsv(table); + FileHelper.WriteFile(tmpPath, fileName, csv); + string path = tmpPath + fileName; + try + { + if (Connection.State == ConnectionState.Closed) + Connection.Open(); + using (IDbTransaction tran = Connection.BeginTransaction()) + { + MySqlBulkLoader bulk = new MySqlBulkLoader(Connection as MySqlConnection) + { + FieldTerminator = ",", + FieldQuotationCharacter = '"', + EscapeCharacter = '"', + LineTerminator = "\r\n", + FileName = path.ReplacePath(), + NumberOfLinesToSkip = 0, + TableName = tableName, + }; + bulk.Columns.AddRange(table.Columns.Cast().Select(colum => colum.ColumnName).ToList()); + insertCount = bulk.Load(); + tran.Commit(); + } + } + catch (Exception ex) + { + throw; + } + finally + { + Connection?.Dispose(); + Connection?.Close(); + } + return insertCount; + // File.Delete(path); + } + /// + ///将DataTable转换为标准的CSV + /// + /// 数据表 + /// 返回标准的CSV + private string DataTableToCsv(DataTable table) + { + //以半角逗号(即,)作分隔符,列为空也要表达其存在。 + //列内容如存在半角逗号(即,)则用半角引号(即"")将该字段值包含起来。 + //列内容如存在半角引号(即")则应替换成半角双引号("")转义,并用半角引号(即"")将该字段值包含起来。 + StringBuilder sb = new StringBuilder(); + DataColumn colum; + Type typeString = typeof(string); + Type typeDate = typeof(DateTime); + + foreach (DataRow row in table.Rows) + { + for (int i = 0; i < table.Columns.Count; i++) + { + colum = table.Columns[i]; + if (i != 0) sb.Append(","); + if (colum.DataType == typeString && row[colum].ToString().Contains(",")) + sb.Append("\"" + row[colum].ToString().Replace("\"", "\"\"") + "\""); + else if (colum.DataType == typeDate) + { + //centos系统里把datatable里的日期转换成了10/18/18 3:26:15 PM格式 + bool b = DateTime.TryParse(row[colum].ToString(), out DateTime dt); + sb.Append(b ? dt.ToString("yyyy-MM-dd HH:mm:ss") : ""); + } + else sb.Append(row[colum].ToString()); + } + sb.AppendLine(); + } + + return sb.ToString(); + } + + /// + /// 返回DataTable + /// + /// + /// + /// + /// + public DataTable GetDataTable(string cmd, object param, CommandType? commandType = null) + { + DataTable table = new DataTable("MyTable"); + var reader = ExecuteReader(cmd, param, commandType); + table.Load(reader); + return table; + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Utilities/DbAccess.cs b/Tiobon.Core.Common/DB/Dapper/Utilities/DbAccess.cs new file mode 100644 index 00000000..e5254a6b --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Utilities/DbAccess.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Linq.Expressions; +using System.Text; +using System.Threading.Tasks; +using Tiobon.Core.Common.DB.Dapper.Const; +using Tiobon.Core.Common.DB.Dapper.DBManager; +using Tiobon.Core.Common.DB.Dapper.Enums; + +namespace Tiobon.Core.Common.DB.Dapper; + +public class DbAccess +{ + public static ISqlDapper Instance + { + get + { + return DBServerProvider.SqlDapper; + } + } + + + public static bool MySql + { + get + { + bool result = false; + if (DBType.Name == DbCurrentType.MySql.ToString()) + { + result = true; + } + return result; + } + } + + #region 获取SQL插入语句 + /// + /// 获取SQL插入语句 + /// + /// 表名 + /// 列名 + /// 列值 + /// SQL插入语句 + public StringBuilder GetInsertSql(string tableName, string columnName, string columnValue) + { + try + { + DbInsert di = null; + string sql = null; + StringBuilder sqls = new StringBuilder(); + DbSelect ds = new DbSelect(tableName + " A", "A"); + ds.IsInitDefaultValue = false; + ds.Where("A." + columnName, "=", columnValue); + DataTable dt = Instance.GetDataTable(ds.GetSql(), null); + for (int i = 0; i < dt.Rows.Count; i++) + { + di = new DbInsert(tableName, "GetInsertSql"); + di.IsInitDefaultValue = false; + for (int j = 0; j < dt.Columns.Count; j++) + { + di.Values(dt.Columns[j].ColumnName, dt.Rows[i][dt.Columns[j].ColumnName].ToString()); + } + sql = di.GetSql(); + sqls.Append(sql + ";\n"); + } + return sqls; + } + catch (Exception) { throw; } + } + + #endregion + + #region 数据库名称 + /// + /// 数据库名称 + /// + public static string DatabaseName + { + get + { + return Instance.Connection.Database; + } + } + + #endregion + + + public static DataTable GetDataTable(string sql, object param = null, CommandType? commandType = null, bool beginTransaction = false) => Instance.GetDataTable(sql, param, commandType, beginTransaction); + public static async Task GetDataTableAsync(string cmd, object param = null, IDbTransaction transaction = null, CommandType? commandType = null, int? commandTimeout = null) => await Instance.GetDataTableAsync(cmd, param, transaction, commandType, commandTimeout); + + public static List QueryList(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class => Instance.QueryList(cmd, param, commandType, beginTransaction); + + public static async Task> QueryListAsync(string cmd, object param = null, bool beginTransaction = false, CommandType? commandType = null, int? commandTimeout = null) where T : class => await Instance.QueryListAsync(cmd, param, commandType, beginTransaction, commandTimeout); + + public static T QueryFirst(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false) where T : class => Instance.QueryFirst(cmd, param, commandType, beginTransaction); + public static async Task QueryFirstAsync(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false, int? commandTimeout = null) where T : class => await Instance.QueryFirstAsync(cmd, param, commandType, beginTransaction, commandTimeout); + + public static object ExecuteScalar(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false) => Instance.ExecuteScalar(cmd, param, commandType, beginTransaction); + + public static async Task ExecuteScalarAsync(string cmd, object param = null, CommandType? commandType = null, bool beginTransaction = false) => await Instance.ExecuteScalarAsync(cmd, param, commandType, beginTransaction); + public static int ExcuteNonQuery(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) => Instance.ExcuteNonQuery(cmd, param, commandType, beginTransaction); + public static (List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) => Instance.QueryMultiple(cmd, param, commandType, beginTransaction); + + public static (List, List, List) QueryMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) => Instance.QueryMultiple(cmd, param, commandType, beginTransaction); + + public static int ExecuteDML(string cmd, object param, CommandType? commandType = null, IDbTransaction dbTransaction = null) => Instance.ExecuteDML(cmd, param, commandType, dbTransaction); + + public static async Task ExecuteDMLAsync(string cmd, object param, CommandType? commandType = null, IDbTransaction dbTransaction = null) => await Instance.ExecuteDMLAsync(cmd, param, commandType, dbTransaction); + + public static int Add(T entity, Expression> updateFileds = null, bool beginTransaction = false) + { + return Instance.Add(entity, updateFileds, beginTransaction); + } + /// + /// + /// + /// + /// + /// 指定插入的字段 + /// 是否开启事务 + /// + public static int AddRange(IEnumerable entities, Expression> addFileds = null, bool beginTransaction = true) + { + return Instance.AddRange(entities, addFileds, beginTransaction); + } + + public static int Update(T entity, Expression> updateFileds = null, bool beginTransaction = true) + { + return Instance.Update(entity, updateFileds, beginTransaction); + } + + /// + ///(根据主键批量更新实体) sqlserver使用的临时表参数化批量更新,mysql待优化 + /// + /// + /// 实体必须带主键 + /// 批定更新字段 + /// + /// + public static int UpdateRange(IEnumerable entities, Expression> updateFileds = null, bool beginTransaction = true) + { + return Instance.UpdateRange(entities, updateFileds, beginTransaction); + } + + public static int BulkInsert(DataTable table, string tableName, SqlBulkCopyOptions? sqlBulkCopyOptions = null, string fileName = null, string tmpPath = null) + { + return Instance.BulkInsert(table, tableName, sqlBulkCopyOptions, fileName, tmpPath); + } + +} + diff --git a/Tiobon.Core.Common/DB/Dapper/Utilities/FileHelper.cs b/Tiobon.Core.Common/DB/Dapper/Utilities/FileHelper.cs new file mode 100644 index 00000000..f265d81c --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Utilities/FileHelper.cs @@ -0,0 +1,83 @@ +using System; +using System.IO; +using System.Text; +using Tiobon.Core.Common.DB.Dapper.Extensions; + +namespace Tiobon.Core.Common.DB.Dapper.Utilities; +public class FileHelper : IDisposable +{ + public static string GetCurrentDownLoadPath() + { + return ("Download\\").MapPath(); + } + + #region 取得文件后缀名 + /// + /// + /// + /// 路径 + /// 文件名 + /// 写入的内容 + /// 是否将内容添加到未尾,默认不添加 + public static void WriteFile(string path, string fileName, string content, bool appendToLast = false) + { + try + { + path = path.ReplacePath(); + fileName = fileName.ReplacePath(); + if (!Directory.Exists(path))//如果不存在就创建file文件夹 + Directory.CreateDirectory(path); + + using (FileStream stream = File.Open(path + fileName, FileMode.OpenOrCreate, FileAccess.Write)) + { + byte[] by = Encoding.Default.GetBytes($"-- {DateTime.Now:yyyy-MM-dd HH:mm:ss}" + "\r\n" + content); + if (appendToLast) + { + stream.Position = stream.Length; + } + else + { + stream.SetLength(0); + } + stream.Write(by, 0, by.Length); + } + } + catch (Exception Ex) + { + string error = Ex.Message; + } + } + #endregion + + + private bool _alreadyDispose = false; + + #region 构造函数 + public FileHelper() + { + // + // TODO: 在此处添加构造函数逻辑 + // + } + ~FileHelper() + { + Dispose(); + } + + protected virtual void Dispose(bool isDisposing) + { + if (_alreadyDispose) return; + _alreadyDispose = true; + } + #endregion + + #region IDisposable 成员 + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + #endregion +} diff --git a/Tiobon.Core.Common/DB/Dapper/Utilities/HttpContext.cs b/Tiobon.Core.Common/DB/Dapper/Utilities/HttpContext.cs new file mode 100644 index 00000000..c17ef6e2 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Utilities/HttpContext.cs @@ -0,0 +1,15 @@ +using Microsoft.AspNetCore.Http; + +namespace Tiobon.Core.Common.DB.Dapper.Utilities; + +public static class HttpContext +{ + private static IHttpContextAccessor _accessor; + + public static Microsoft.AspNetCore.Http.HttpContext Current => _accessor.HttpContext; + + internal static void Configure(IHttpContextAccessor accessor) + { + _accessor = accessor; + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Utilities/StringHelper.cs b/Tiobon.Core.Common/DB/Dapper/Utilities/StringHelper.cs new file mode 100644 index 00000000..bea94565 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Utilities/StringHelper.cs @@ -0,0 +1,15 @@ +using System; + +namespace Tiobon.Core.Common.DB.Dapper.Utilities; +public class StringHelper +{ + public static string Id + { + get + { + Guid id = Guid.NewGuid(); + return id.ToString(); + //return GuidRandomGenerator.Instance.Generate(); + } + } +} diff --git a/Tiobon.Core.Common/DB/Dapper/Utilities/UtilConvert.cs b/Tiobon.Core.Common/DB/Dapper/Utilities/UtilConvert.cs new file mode 100644 index 00000000..c94a5929 --- /dev/null +++ b/Tiobon.Core.Common/DB/Dapper/Utilities/UtilConvert.cs @@ -0,0 +1,33 @@ +using System; +namespace Tiobon.Core.Common.DB.Dapper; + +/// +/// +/// +public static class UtilConvert +{ + /// + /// + /// + /// + /// + public static string ObjToString(this object thisValue) + { + if (thisValue != null) return thisValue.ToString().Trim(); + return ""; + } + /// + /// + /// + /// + /// + public static bool ObjToBool(this object thisValue) + { + bool reval = false; + if (thisValue != null && thisValue != DBNull.Value && bool.TryParse(thisValue.ToString(), out reval)) + { + return reval; + } + return reval; + } +} diff --git a/Tiobon.Core.Common/DB/DbSql/DbInsert.cs b/Tiobon.Core.Common/DB/DbSql/DbInsert.cs index a48593a6..2bf925e3 100644 --- a/Tiobon.Core.Common/DB/DbSql/DbInsert.cs +++ b/Tiobon.Core.Common/DB/DbSql/DbInsert.cs @@ -84,6 +84,13 @@ namespace Tiobon.Core.Common FormatValue(fieldName.ToUpper(), s); } + public void Values(string fieldName, string value) + { + string s = "N'{0}'"; + s = string.Format(s, value); + + FormatValue(fieldName.ToUpper(), s); + } public void Values(string fieldName, Guid value) { string value1 = value.ToString(); @@ -263,7 +270,7 @@ namespace Tiobon.Core.Common //create_by var createBy = UserContext.Current.User_Id; - Values("CreatedBy", createBy); + Values("CreatedBy", createBy); //create_date DateTime createDate = DateTime.Now; diff --git a/Tiobon.Core.Common/Seed/FrameSeed.cs b/Tiobon.Core.Common/Seed/FrameSeed.cs index aac820ba..d022baf9 100644 --- a/Tiobon.Core.Common/Seed/FrameSeed.cs +++ b/Tiobon.Core.Common/Seed/FrameSeed.cs @@ -1,4 +1,4 @@ -using SimpleDapper; +using Tiobon.Core.Common.DB.Dapper; using SqlSugar; using System.Text; diff --git a/Tiobon.Core.Common/Tiobon.Core.Common.csproj b/Tiobon.Core.Common/Tiobon.Core.Common.csproj index 5839e741..e8d06175 100644 --- a/Tiobon.Core.Common/Tiobon.Core.Common.csproj +++ b/Tiobon.Core.Common/Tiobon.Core.Common.csproj @@ -9,11 +9,14 @@ + + + @@ -22,6 +25,7 @@ + @@ -32,6 +36,7 @@ + @@ -49,10 +54,4 @@ - - - ..\Lib\SimpleDapper.dll - - - diff --git a/Tiobon.Core.Tests/Common_Test/DbAccess_Should.cs b/Tiobon.Core.Tests/Common_Test/DbAccess_Should.cs index 75d9404e..2061b010 100644 --- a/Tiobon.Core.Tests/Common_Test/DbAccess_Should.cs +++ b/Tiobon.Core.Tests/Common_Test/DbAccess_Should.cs @@ -1,5 +1,5 @@ using System.Data; -using SimpleDapper; +using Tiobon.Core.Common.DB.Dapper; using Tiobon.Core.Model.Models; using Xunit; diff --git a/Tiobon.Core.Tests/Tiobon.Core.Tests.csproj b/Tiobon.Core.Tests/Tiobon.Core.Tests.csproj index 053d455e..d6d38e07 100644 --- a/Tiobon.Core.Tests/Tiobon.Core.Tests.csproj +++ b/Tiobon.Core.Tests/Tiobon.Core.Tests.csproj @@ -32,12 +32,6 @@ - - - ..\Lib\SimpleDapper.dll - - - Always