【愚公系列】2023年03月 MES生产制造执行系统-002.Dapper和EFCode的使用


前言

1.Dapper

Dapper是由Stack Overflow背后的团队创建的micro-ORM。Dapper 是 .NET 的简单对象映射器,在速度方面拥有 Micro ORM 之王的称号,几乎与使用原始 ADO.NET 数据读取器一样快。ORM是一个对象关系映射器,负责数据库和编程语言之间的映射。

  • Dapper 是一个流行的开源 .NET 对象关系映射 (ORM) 库。
  • 通过将对象映射到数据库中的表,可以轻松地处理应用程序中的数据。
  • Dapper 快速、可靠且经过充分测试,多年来一直被一些世界上最大的公司用于生产。
  • 它非常易于使用,并具有许多功能,使其成为数据访问的强大工具。

Dapper 比实体框架更快,用于 CRUD 操作(查询和保存),因为它很简单。与 EF Core 不同,它不必增加所有复杂性,例如跟踪值、编写低效的 SQL 查询以及支持延迟加载和默认所有继承等功能。

Dapper官网地址:https://dapper-tutorial.net/

在这里插入图片描述

Dapper文档地址:https://dapper-tutorial.net/dapper

在这里插入图片描述

2.EF

EFCode是一个适用于.NET开发的开源ORM框架。它使开发人员能够通过领域对象来处理数据,而无需关注存储此数据的基础数据库。使用实体框架,开发人员在处理数据时可以在更高的抽象级别上工作,并且与传统应用程序相比,可以使用更少的代码创建和维护面向数据的应用程序。

EFCode官方文档:https://learn.microsoft.com/zh-cn/ef/core/

在这里插入图片描述

一、Dapper和EFCode的使用的使用

1.数据库相关服务注入

接上文讲解数据库相关服务注入

//返回数据库连接字符串
string connectionString = DBServerProvider.GetConnectionString(null);

if (DBType.Name == DbCurrentType.MySql.ToString())
{
    //2020.03.31增加dapper对mysql字段Guid映射
    SqlMapper.AddTypeHandler(new DapperParseGuidTypeHandler());
    SqlMapper.RemoveTypeMap(typeof(Guid?));

    //services.AddDbContext<SysDbContext>();
    //mysql8.x的版本使用Pomelo.EntityFrameworkCore.MySql 3.1会产生异常,需要在字符串连接上添加allowPublicKeyRetrieval=true
    services.AddDbContextPool<SysDbContext>(optionsBuilder => { optionsBuilder.UseMySql(connectionString); }, 64);
    services.AddDbContextPool<ServiceDbContext>(optionsBuilder => { optionsBuilder.UseMySql(connectionString); }, 64);
    services.AddDbContextPool<ReportDbContext>(optionsBuilder => { optionsBuilder.UseMySql(connectionString); }, 64);
}
else if (DBType.Name == DbCurrentType.PgSql.ToString())
{
    services.AddDbContextPool<SysDbContext>(optionsBuilder => { optionsBuilder.UseNpgsql(connectionString); }, 64);
    services.AddDbContextPool<ServiceDbContext>(optionsBuilder => { optionsBuilder.UseNpgsql(connectionString); }, 64);
    services.AddDbContextPool<ReportDbContext>(optionsBuilder => { optionsBuilder.UseNpgsql(connectionString); }, 64);
}
else
{
    services.AddDbContextPool<SysDbContext>(optionsBuilder => { optionsBuilder.UseSqlServer(connectionString); }, 64);
    services.AddDbContextPool<ServiceDbContext>(optionsBuilder => { optionsBuilder.UseSqlServer(connectionString); }, 64);
    services.AddDbContextPool<ReportDbContext>(optionsBuilder => { optionsBuilder.UseSqlServer(connectionString); }, 64);
}
//启用缓存
if (AppSetting.UseRedis)
{
    builder.RegisterType<RedisCacheService>().As<ICacheService>().SingleInstance();
}
else
{
    builder.RegisterType<MemoryCacheService>().As<ICacheService>().SingleInstance();
}

在这里插入图片描述

1.1 DBServerProvider

DBServerProvider作用主要是关联三个数据库连接:

  • 业务库
  • 报表库
  • 系统数据库

DBServerProvider提供的功能比较多,还包含Dapper客户端返回

public class DBServerProvider
{
    private static readonly string _netcoredevserver = "netcoredevserver";
    private static readonly string _report = "report";
    private static Dictionary<string, string> ConnectionPool = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
    { 
        //配置业务数据库连接  
        {_netcoredevserver, AppSetting.GetSettingString("ServiceConnectingString")},
        //配置报表数据库连接
        {_report, AppSetting.GetSettingString("ReportConnectingString")}
        //系统库不用配置了,已经在appsetting.json中配置过了
      };

    private static readonly string DefaultConnName = "default"; 

    static DBServerProvider()
    {
        SetConnection(DefaultConnName, AppSetting.DbConnectionString);
    }
    public static void SetConnection(string key, string val)
    {
        ConnectionPool[key] = val;
    }
    /// <summary>
    /// 设置默认数据库连接
    /// </summary>
    /// <param name="val"></param>
    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;
    }
    /// <summary>
    /// 获取默认数据库连接
    /// </summary>
    /// <returns></returns>
    public static string GetConnectionString()
    {
        return GetConnectionString(DefaultConnName);
    }
    public static IDbConnection GetDbConnection(string connString = null)
    {
        if (connString == null)
        {
            connString = ConnectionPool[DefaultConnName];
        }
        if (DBType.Name == DbCurrentType.MySql.ToString())
        {
            return new MySql.Data.MySqlClient.MySqlConnection(connString);
        }
        if (DBType.Name == DbCurrentType.PgSql.ToString())
        {
            return new NpgsqlConnection(connString);
        }
        return new SqlConnection(connString);
    }


    /// <summary>
    /// 扩展dapper 获取MSSQL数据库DbConnection,默认系统获取配置文件的DBType数据库类型,
    /// </summary>
    /// <param name="connString">如果connString为null 执行重载GetDbConnection(string connString = null)</param>
    /// <param name="dapperType">指定连接数据库的类型:MySql/MsSql/PgSql</param>
    /// <returns></returns>
    public static IDbConnection GetDbConnection(string connString = null, DbCurrentType dbCurrentType = DbCurrentType.Default)
    {
        //默认获取DbConnection
        if (connString.IsNullOrEmpty() || DbCurrentType.Default == dbCurrentType)
        {
            return GetDbConnection(connString);
        }
        if (dbCurrentType == DbCurrentType.MySql)
        {
            return new MySql.Data.MySqlClient.MySqlConnection(connString);
        }
        if (dbCurrentType == DbCurrentType.PgSql)
        {
            return new NpgsqlConnection(connString);
        }
        return new SqlConnection(connString);

    }

    /// <summary>
    /// 获取系统库(2020.08.22)
    /// </summary>
    public static SysDbContext SysDbContext
    {
        get { return Utilities.HttpContext.Current.GetService<SysDbContext>(); ; }
    }

    /// <summary>
    /// 获取系统库(2020.08.22)
    /// </summary>
    public static SysDbContext DbContext
    {
        get { return GetEFDbContext(); }
    }
    /// <summary>
    /// 获取系统库(2020.08.22)
    /// </summary>
    public static SysDbContext GetEFDbContext()
    {
        return SysDbContext;
    }

    /// <summary>
    /// 获取业务库(2020.08.22)
    /// </summary>
    public static ServiceDbContext ServiceDbContext
    {
        get { return Utilities.HttpContext.Current.GetService<ServiceDbContext>(); ; }
    }

    /// <summary>
    /// 获取报表库(2020.08.22)
    /// </summary>
    public static ReportDbContext ReportDbContext
    {
        get { return Utilities.HttpContext.Current.GetService<ReportDbContext>(); ; }
    }


    /// <summary>
    /// 获取调用系统库的Dapper(2020.08.22)
    /// </summary>
    public static ISqlDapper SqlDapper
    {
        get
        {
            return new SqlDapper(DefaultConnName);
        }
    }

    /// <summary>
    /// 获取连接报表库的dapper(2020.08.22)
    /// </summary>
    public static ISqlDapper SqlDapperReport
    {
        get
        {
            return new SqlDapper(ReportConnectingString);
        }
    }

    /// <summary>
    /// 获取连接业务库的dapper(2020.08.22)
    /// </summary>
    public static ISqlDapper SqlDapperService
    {
        get
        {
            return new SqlDapper(ServiceConnectingString);
        }
    }

    /// <summary>
    /// 获取当前用户所属的业务库,需要添加存储用户所属数据库的字段(2020.08.22)
    /// </summary>
    public static ISqlDapper SqlDapperUserCurrentService
    {
        get
        {
            return new SqlDapper(ServiceUserCurrnetConnectingString);
        }
    }

    /// <summary>
    /// 默认获取连接系统库的dapper(2020.08.22)
    /// </summary>
    public static ISqlDapper GetSqlDapper(string dbName = null)
    {
        return new SqlDapper(dbName ?? DefaultConnName);
    }


    //(2020.08.22)
    public static ISqlDapper GetSqlDapper<TEntity>()
    {
        Type baseType = typeof(TEntity).BaseType;
        string dbName = null;
        if (baseType == typeof(SysEntity))
        {
            dbName = SysConnectingString;
        }
        else if (baseType == typeof(ServiceEntity))
        {
            dbName = ServiceConnectingString;
        }
        else if (baseType == typeof(ReportEntity))
        {
            dbName = ServiceConnectingString;
        }
        //获取实体真实的数据库连接池对象名,如果不存在则用默认数据连接池名
        //string dbName = typeof(TEntity).GetTypeCustomValue<DBConnectionAttribute>(x => x.DBName) ?? DefaultConnName;
        return GetSqlDapper(dbName);
    }

    /// <summary>
    /// 获取报表数据库的字符串连接(2020.08.22)
    /// </summary>
    public static string ReportConnectingString
    {
        //netcoredevserver为ConnectionPool字典中的key,如果字典中的key改变了,这里也要改变
        get { return GetDbConnectionString(_report); }
    }

    /// <summary>
    /// 获取业务库的字符串连接(2020.08.22)
    /// </summary>
    public static string ServiceConnectingString
    {
        //netcoredevserver为ConnectionPool字典中的key,如果字典中的key改变了,这里也要改变
        get { return GetDbConnectionString(_netcoredevserver); }
    }

    /// <summary>
    /// 获取业务库的字符串连接(2020.08.22)
    /// 获取当前用户所属的数据库连接,需要添加存储用户所属数据库的字段(2020.08.22)
    /// </summary>
    public static string ServiceUserCurrnetConnectingString
    {
        get
        {
            //UserContext.Current.DbName用户所属性数据库。需要自己添加字段
            // return ConnectionPool[UserContext.Current.DbName];
            return ServiceConnectingString;
        }
    }


    /// <summary>
    /// 获取系统库的字符串连接(2020.08.22)
    /// </summary>
    public static string SysConnectingString
    {
        get { return GetDbConnectionString(DefaultConnName); }
    }

    /// <summary>
    /// key为ConnectionPool初始化的所有数据库连接(2020.08.22)
    /// </summary>
    /// <param name="key"></param>
    /// <returns></returns>
    public static string GetDbConnectionString(string key)
    {
        if (ConnectionPool.TryGetValue(key, out string connString))
        {
            return connString;
        }
        throw new Exception($"未配置[{key}]的数据库连接");
    }
    public static string GetContextName(string DBServer)
    {
        //  业务库
        if (DBServer == typeof(ServiceDbContext).Name)
        {
            return typeof(ServiceEntity).Name;
        }//报表库
        else if (DBServer == typeof(ReportDbContext).Name)
        {
            return typeof(ReportEntity).Name;
        }
        else//系统库
        {
            return typeof(SysEntity).Name;
        }
    }


}

在这里插入图片描述

1.2 Dapper的使用

Dapper的封装代码如下:

public interface ISqlDapper
{
    /// <summary>
    ///  超时时间(秒)2021.05.05
    /// </summary>
    /// <param name="timeout"></param>
    /// <returns></returns>
    ISqlDapper SetTimout(int timeout);
    void BeginTransaction(Func<ISqlDapper, bool> action, Action<Exception> error);
    List<T> QueryList<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    Task<IEnumerable<T>> QueryListAsync<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    T QueryFirst<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class;

    Task<T> QueryFirstAsync<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class;

    Task<dynamic> QueryDynamicFirstAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    dynamic QueryDynamicFirst(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    Task<dynamic> QueryDynamicListAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    List<dynamic> QueryDynamicList(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);


    object ExecuteScalar(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);


    Task<object> ExecuteScalarAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    int ExcuteNonQuery(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    Task<int> ExcuteNonQueryAsync(string cmd, object param, 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);

    Task<(IEnumerable<T1>, IEnumerable<T2>)> QueryMultipleAsync<T1, T2>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    (List<T1>, List<T2>) QueryMultiple<T1, T2>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>)> QueryMultipleAsync<T1, T2, T3>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    (List<T1>, List<T2>, List<T3>) QueryMultiple<T1, T2, T3>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);


    Task<(IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    (List<dynamic>, List<dynamic>) QueryDynamicMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);


    Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>)> QueryMultipleAsync<T1, T2, T3, T4>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    (List<T1>, List<T2>, List<T3>, List<T4>) QueryMultiple<T1, T2, T3, T4>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);


    Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>, IEnumerable<T5>)> QueryMultipleAsync<T1, T2, T3, T4, T5>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) QueryMultiple<T1, T2, T3, T4, T5>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);


    Task<(IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync2(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    (List<dynamic>, List<dynamic>) QueryDynamicMultiple2(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    Task<(IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync3(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);

    (List<dynamic>, List<dynamic>, List<dynamic>) QueryDynamicMultiple3(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);


    Task<(IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync5(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);
    (List<dynamic>, List<dynamic>, List<dynamic>, List<dynamic>, List<dynamic>) QueryDynamicMultiple5(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false);


    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="updateFileds">指定插入的字段</param>
    /// <param name="beginTransaction">是否开启事务</param>
    /// <returns></returns>
    int Add<T>(T entity, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="updateFileds">指定插入的字段</param>
    /// <param name="beginTransaction">是否开启事务</param>
    /// <returns></returns>
    int AddRange<T>(IEnumerable<T> entities, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);


    /// <summary>
    /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity">实体必须带主键</param>
    /// <param name="updateFileds">指定更新的字段x=new {x.a,x.b}</param>
    /// <param name="beginTransaction">是否开启事务</param>
    /// <returns></returns>
    int Update<T>(T entity, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);

    /// <summary>
    /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity">实体必须带主键</param>
    /// <param name="updateFileds">指定更新的字段x=new {x.a,x.b}</param>
    /// <param name="beginTransaction">是否开启事务</param>
    /// <returns></returns>
    int UpdateRange<T>(IEnumerable<T> entities, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false);

    int DelWithKey<T>(params object[] keys);
    int DelWithKey<T>(bool beginTransaction = false, params object[] keys);
    /// <summary>
    ///  sqlserver批量写入
    /// 使用时DataTable table表字段顺序要和数据库字段顺序一致
    /// <summary>
    /// mysql批量写入
    /// </summary>
    /// <param name="table"></param>
    /// <param name="tableName"></param>
    /// <param name="tmpPath">默认当前下载路径</param>
    /// <param name="fileName">默认$"{DateTime.Now.ToString("yyyyMMddHHmmss")}.csv"</param>
    /// <returns></returns>
    int BulkInsert(DataTable table, string tableName, SqlBulkCopyOptions? sqlBulkCopyOptions = null, string fileName = null, string tmpPath = null);
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="tableName"></param>
    /// <param name="columns">所包含的列</param>
    /// <param name="sqlBulkCopyOptions"></param>
    /// <param name="fileName"></param>
    /// <param name="tmpPath"></param>
    /// <returns></returns>
    int BulkInsert<T>(List<T> entities, string tableName = null,
        Expression<Func<T, object>> columns = null,
        SqlBulkCopyOptions? sqlBulkCopyOptions = null);
}

在这里插入图片描述

public class SqlDapper : ISqlDapper
{
    private string _connectionString;
    private int? commandTimeout = null;
    private DbCurrentType _dbCurrentType;
    public SqlDapper()
    {
        _connectionString = DBServerProvider.GetConnectionString();
    }
    public SqlDapper(string connKeyName, DbCurrentType dbCurrentType)
    {
        _dbCurrentType = dbCurrentType;
        _connectionString = DBServerProvider.GetConnectionString(connKeyName);
    }
    public SqlDapper(string connKeyName)
    {
        _connectionString = DBServerProvider.GetConnectionString(connKeyName);
    }

    private bool _transaction { get; set; }

    private IDbConnection _transactionConnection = null;

    /// <summary>
    /// 超时时间(秒)
    /// </summary>
    /// <param name="timeout"></param>
    /// <returns></returns>
    public ISqlDapper SetTimout(int timeout)
    {
        this.commandTimeout = timeout;
        return this;
    }


    private T Execute<T>(Func<IDbConnection, IDbTransaction, T> func, bool beginTransaction = false)
    {
        if (_transaction)
        {
            return func(_transactionConnection, dbTransaction);
        }
        if (beginTransaction)
        {
            return ExecuteTransaction(func);
        }
        using (var connection = DBServerProvider.GetDbConnection(_connectionString, _dbCurrentType))
        {
            return func(connection, dbTransaction);
        }
    }

    private T ExecuteTransaction<T>(Func<IDbConnection, IDbTransaction, T> func)
    {
        using (_transactionConnection = DBServerProvider.GetDbConnection(_connectionString, _dbCurrentType))
        {
            try
            {
                _transactionConnection.Open();
                dbTransaction = _transactionConnection.BeginTransaction();
                T reslutT = func(_transactionConnection, dbTransaction);
                dbTransaction.Commit();
                return reslutT;
            }
            catch (Exception ex)
            {
                dbTransaction?.Rollback();
                throw ex;
            }
            finally
            {
                dbTransaction?.Dispose();
            }
        }
    }

    private async Task<T> ExecuteAsync<T>(Func<IDbConnection, IDbTransaction, Task<T>> funcAsync, bool beginTransaction = false)
    {
        if (_transaction)
        {
            return await funcAsync(_transactionConnection, dbTransaction);
        }
        if (beginTransaction)
        {
            return await ExecuteTransactionAsync(funcAsync);
        }
        using (var connection = DBServerProvider.GetDbConnection(_connectionString))
        {
            T reslutT = await funcAsync(connection, dbTransaction);
            if (!_transaction && dbTransaction != null)
            {
                dbTransaction.Commit();
            }
            return reslutT;
        }
    }

    private async Task<T> ExecuteTransactionAsync<T>(Func<IDbConnection, IDbTransaction, Task<T>> funcAsync)
    {
        using (var connection = DBServerProvider.GetDbConnection(_connectionString))
        {
            try
            {
                connection.Open();
                dbTransaction = connection.BeginTransaction();
                T reslutT = await funcAsync(connection, dbTransaction);
                if (!_transaction && dbTransaction != null)
                {
                    dbTransaction.Commit();
                }
                return reslutT;
            }
            catch (Exception ex)
            {
                dbTransaction?.Rollback();
                throw ex;
            }
        }
    }

    /// <summary>
    /// 2020.06.15增加Dapper事务处理
    /// <param name="action"></param>
    /// <param name="error"></param>
    public void BeginTransaction(Func<ISqlDapper, bool> action, Action<Exception> error)
    {
        _transaction = true;
        using (var connection = DBServerProvider.GetDbConnection(_connectionString, _dbCurrentType))
        {
            try
            {
                _transactionConnection = connection;
                _transactionConnection.Open();
                dbTransaction = _transactionConnection.BeginTransaction();
                bool result = action(this);
                if (result)
                {
                    dbTransaction?.Commit();
                }
                else
                {
                    dbTransaction?.Rollback();
                }
            }
            catch (Exception ex)
            {
                dbTransaction?.Rollback();
                error(ex);
            }
            finally
            {
                _transaction = false;
                dbTransaction?.Dispose();
            }
        }
    }

    /// <summary>
    /// 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);
    //        /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="cmd"></param>
    /// <param name="param"></param>
    /// <param name="commandType"></param>
    /// <returns></returns>
    public List<T> QueryList<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            return conn.Query<T>(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout).ToList();
        }, beginTransaction);
    }
    public async Task<IEnumerable<T>> QueryListAsync<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            return await conn.QueryAsync<T>(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }

    public async Task<T> QueryFirstAsync<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            return await conn.QueryFirstOrDefaultAsync<T>(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }


    public T QueryFirst<T>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false) where T : class
    {
        return Execute((conn, dbTransaction) =>
        {
            return conn.QueryFirstOrDefault<T>(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }

    public async Task<dynamic> QueryDynamicFirstAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            return await conn.QueryFirstOrDefaultAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }

    public dynamic QueryDynamicFirst(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            return conn.QueryFirstOrDefault(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }

    public async Task<dynamic> QueryDynamicListAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            return await conn.QueryAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }

    public List<dynamic> QueryDynamicList(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            return conn.Query(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout).ToList();
        }, beginTransaction);
    }


    public async Task<object> ExecuteScalarAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            return await conn.ExecuteScalarAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }

    public object ExecuteScalar(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            return conn.ExecuteScalar(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }

    public async Task<int> ExcuteNonQueryAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            return await conn.ExecuteAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }

    public int ExcuteNonQuery(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute<int>((conn, dbTransaction) =>
        {
            return conn.Execute(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }
    public IDataReader ExecuteReader(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute<IDataReader>((conn, dbTransaction) =>
        {
            return conn.ExecuteReader(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout);
        }, beginTransaction);
    }


    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, commandTimeout: commandTimeout);
        }, beginTransaction);
    }


    public async Task<(IEnumerable<T1>, IEnumerable<T2>)> QueryMultipleAsync<T1, T2>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = await conn.QueryMultipleAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (await reader.ReadAsync<T1>(), await reader.ReadAsync<T2>());
            }
        }, beginTransaction);
    }

    /// <summary>
    /// 获取output值 param.Get<int>("@b");
    /// </summary>
    /// <typeparam name="T1"></typeparam>
    /// <param name="cmd"></param>
    /// <param name="param"></param>
    /// <param name="commandType"></param>
    /// <param name="dbTransaction"></param>
    /// <returns></returns>
    public (List<T1>, List<T2>) QueryMultiple<T1, T2>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (reader.Read<T1>().ToList(), reader.Read<T2>().ToList());
            }
        }, beginTransaction);
    }

    public async Task<(IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = await conn.QueryMultipleAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (await reader.ReadAsync(), await reader.ReadAsync());
            }
        }, beginTransaction);
    }

    public (List<dynamic>, List<dynamic>) QueryDynamicMultiple(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (reader.Read().ToList(), reader.Read().ToList());
            }
        }, beginTransaction);
    }


    public async Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>)> QueryMultipleAsync<T1, T2, T3>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = await conn.QueryMultipleAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (await reader.ReadAsync<T1>(), await reader.ReadAsync<T2>(), await reader.ReadAsync<T3>());
            }
        }, beginTransaction);
    }


    public (List<T1>, List<T2>, List<T3>) QueryMultiple<T1, T2, T3>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (reader.Read<T1>().ToList(), reader.Read<T2>().ToList(), reader.Read<T3>().ToList());
            }
        }, beginTransaction);
    }

    public async Task<(IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync2(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = await conn.QueryMultipleAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (
                await reader.ReadAsync<dynamic>(),
                await reader.ReadAsync<dynamic>()
                );
            }
        }, beginTransaction);
    }

    public (List<dynamic>, List<dynamic>) QueryDynamicMultiple2(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (
                    reader.Read<dynamic>().ToList(),
                    reader.Read<dynamic>().ToList()
                );
            }
        }, beginTransaction);
    }

    public async Task<(IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync3(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = await conn.QueryMultipleAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (
                await reader.ReadAsync<dynamic>(),
                await reader.ReadAsync<dynamic>(),
                await reader.ReadAsync<dynamic>()
                );
            }
        }, beginTransaction);
    }


    public (List<dynamic>, List<dynamic>, List<dynamic>) QueryDynamicMultiple3(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (reader.Read<dynamic>().ToList(),
                reader.Read<dynamic>().ToList(),
                reader.Read<dynamic>().ToList()
                );
            }
        }, beginTransaction);
    }


    public async Task<(IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>, IEnumerable<dynamic>)> QueryDynamicMultipleAsync5(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = await conn.QueryMultipleAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (
                await reader.ReadAsync<dynamic>(),
                await reader.ReadAsync<dynamic>(),
                await reader.ReadAsync<dynamic>(),
                await reader.ReadAsync<dynamic>(),
                await reader.ReadAsync<dynamic>()
                );
            }
        }, beginTransaction);
    }

    public (List<dynamic>, List<dynamic>, List<dynamic>, List<dynamic>, List<dynamic>) QueryDynamicMultiple5(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (reader.Read<dynamic>().ToList(),
                reader.Read<dynamic>().ToList(),
                reader.Read<dynamic>().ToList(),
                reader.Read<dynamic>().ToList(),
                reader.Read<dynamic>().ToList()
                );
            }
        }, beginTransaction);
    }

    public async Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>)> QueryMultipleAsync<T1, T2, T3, T4>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = await conn.QueryMultipleAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (await reader.ReadAsync<T1>(),
                await reader.ReadAsync<T2>(),
                await reader.ReadAsync<T3>(),
                await reader.ReadAsync<T4>()
                );
            }
        }, beginTransaction);
    }

    public (List<T1>, List<T2>, List<T3>, List<T4>) QueryMultiple<T1, T2, T3, T4>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (reader.Read<T1>().ToList(),
                reader.Read<T2>().ToList(),
                reader.Read<T3>().ToList(),
                reader.Read<T4>().ToList()
                );
            }
        }, beginTransaction);
    }


    public async Task<(IEnumerable<T1>, IEnumerable<T2>, IEnumerable<T3>, IEnumerable<T4>, IEnumerable<T5>)> QueryMultipleAsync<T1, T2, T3, T4, T5>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return await ExecuteAsync(async (conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = await conn.QueryMultipleAsync(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (await reader.ReadAsync<T1>(),
                await reader.ReadAsync<T2>(),
                await reader.ReadAsync<T3>(),
                await reader.ReadAsync<T4>(),
                await reader.ReadAsync<T5>()
                );
            }
        }, beginTransaction);
    }

    public (List<T1>, List<T2>, List<T3>, List<T4>, List<T5>) QueryMultiple<T1, T2, T3, T4, T5>(string cmd, object param, CommandType? commandType = null, bool beginTransaction = false)
    {
        return Execute((conn, dbTransaction) =>
        {
            using (SqlMapper.GridReader reader = conn.QueryMultiple(cmd, param, dbTransaction, commandType: commandType ?? CommandType.Text, commandTimeout: commandTimeout))
            {
                return (reader.Read<T1>().ToList(),
                reader.Read<T2>().ToList(),
                reader.Read<T3>().ToList(),
                reader.Read<T4>().ToList(),
                reader.Read<T5>().ToList()
                );
            }
        }, beginTransaction);
    }
    IDbTransaction dbTransaction = null;



    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity"></param>
    /// <param name="addFileds">指定插入的字段</param>
    /// <param name="beginTransaction">是否开启事务</param>
    /// <returns></returns>
    public int Add<T>(T entity, Expression<Func<T, object>> addFileds = null, bool beginTransaction = false)
    {
        return AddRange<T>(new T[] { entity }, addFileds, beginTransaction);
    }
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities"></param>
    /// <param name="addFileds">指定插入的字段</param>
    /// <param name="beginTransaction">是否开启事务</param>
    /// <returns></returns>
    public int AddRange<T>(IEnumerable<T> entities, Expression<Func<T, object>> 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;
        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};";
            //2020.11.21修复sqlserver批量写入主键类型判断错误
            sql = entities.GetEntitySql(key.PropertyType == typeof(Guid), sql, null, addFileds, null);
        }
        return Execute<int>((conn, dbTransaction) =>
        {
            //todo pgsql待实现
            return conn.Execute(sql, (DBType.Name == DbCurrentType.MySql.ToString() || DBType.Name == DbCurrentType.PgSql.ToString()) ? entities.ToList() : null, dbTransaction);
        }, beginTransaction);
    }


    /// <summary>
    /// sqlserver使用的临时表参数化批量更新,mysql批量更新待发开
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entity">实体必须带主键</param>
    /// <param name="updateFileds">指定更新的字段x=new {x.a,x.b}</param>
    /// <param name="beginTransaction">是否开启事务</param>
    /// <returns></returns>
    public int Update<T>(T entity, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false)
    {
        return UpdateRange<T>(new T[] { entity }, updateFileds, beginTransaction);
    }

    /// <summary>
    ///(根据主键批量更新实体) sqlserver使用的临时表参数化批量更新,mysql待优化
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="entities">实体必须带主键</param>
    /// <param name="updateFileds">批定更新字段</param>
    /// <param name="beginTransaction"></param>
    /// <returns></returns>
    public int UpdateRange<T>(IEnumerable<T> entities, Expression<Func<T, object>> updateFileds = null, bool beginTransaction = false)
    {
        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<string> paramsList = new List<string>();
            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, beginTransaction);
            // 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, beginTransaction);
    }

    public int DelWithKey<T>(bool beginTransaction = false, 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;
        // 2020.08.06增加pgsql删除功能
        if (DBType.Name == DbCurrentType.PgSql.ToString())
        {
            sql = $"DELETE FROM \"public\".\"{entityType.GetEntityTableName()}\" where \"{tKey}\" in ({joinKeys});";
        }
        else
        {
            sql = $"DELETE FROM {entityType.GetEntityTableName() } where {tKey} in ({joinKeys});";
        }

        return ExcuteNonQuery(sql, null);
    }
    /// <summary>
    /// 使用key批量删除
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="keys"></param>
    /// <returns></returns>
    public int DelWithKey<T>(params object[] keys)
    {
        return DelWithKey<T>(false, keys);
    }
    /// <summary>
    /// 通过Bulk批量插入
    /// </summary>
    /// <param name="table"></param>
    /// <param name="tableName"></param>
    /// <param name="sqlBulkCopyOptions"></param>
    /// <param name="dbKeyName"></param>
    /// <returns></returns>
    private int MSSqlBulkInsert(DataTable table, string tableName, SqlBulkCopyOptions sqlBulkCopyOptions = SqlBulkCopyOptions.UseInternalTransaction, string dbKeyName = null)
    {
        using (var Connection = DBServerProvider.GetDbConnection(_connectionString, _dbCurrentType))
        {
            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<T>(List<T> entities, string tableName = null,
        Expression<Func<T, object>> 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 (DBType.Name == "MySql")
        {
            return MySqlBulkInsert(table, tableName, fileName, tmpPath);
        }

        if (DBType.Name == "PgSql")
        {
            PGSqlBulkInsert(table, tableName);
            return table.Rows.Count;
        }
        return MSSqlBulkInsert(table, tableName, sqlBulkCopyOptions ?? SqlBulkCopyOptions.KeepIdentity);
    }

    /// <summary>
    ///大批量数据插入,返回成功插入行数
    
    /// </summary>
    /// <param name="connectionString">数据库连接字符串</param>
    /// <param name="table">数据表</param>
    /// <returns>返回成功插入行数</returns>
    private int MySqlBulkInsert(DataTable table, string tableName, string fileName = null, string tmpPath = null)
    {
        if (table.Rows.Count == 0) return 0;
        tmpPath = tmpPath ?? FileHelper.GetCurrentDownLoadPath();
        int insertCount = 0;
        string csv = DataTableToCsv(table);
        string text = $"当前行:{table.Rows.Count}";
        MemoryStream stream = null;
        try
        {
            using (var Connection = DBServerProvider.GetDbConnection(_connectionString, _dbCurrentType))
            {
                if (Connection.State == ConnectionState.Closed)
                {
                    Connection.Open();
                }
                using (IDbTransaction tran = Connection.BeginTransaction())
                {
                    MySqlBulkLoader bulk = new MySqlBulkLoader(Connection as MySqlConnection)
                    {
                        LineTerminator = "\n",
                        TableName = tableName,
                        CharacterSet = "UTF8"
                    };
                    if (csv.IndexOf("\n")>0)
                    {
                        csv = csv.Replace("\n", " ");
                    }
                    var array = Encoding.UTF8.GetBytes(csv);
                    using (stream = new MemoryStream(array))
                    {
                        stream = new MemoryStream(array);
                        bulk.SourceStream = stream; //File.OpenRead(fileName);
                        bulk.Columns.AddRange(table.Columns.Cast<DataColumn>().Select(colum => colum.ColumnName).ToList());
                        insertCount = bulk.Load();
                        tran.Commit();
                    }
                }
            }

        }
        catch (Exception ex)
        {
            throw ex;
        }
        return insertCount;
        //   File.Delete(path);
    }
    /// <summary>
    ///将DataTable转换为标准的CSV
    /// </summary>
    /// <param name="table">数据表</param>
    /// <returns>返回标准的CSV</returns>
    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("\t");
                if (colum.DataType == typeString && row[colum].ToString().Contains(","))
                {
                    sb.Append(row[colum].ToString());
                }
                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.Append("\n");
        }

        return sb.ToString();
    }
    /// <summary>
    /// 2020.08.07增加PGSQL批量写入
    /// </summary>
    /// <param name="table"></param>
    /// <param name="tableName"></param>
    private void PGSqlBulkInsert(DataTable table, string tableName)
    {
        List<string> columns = new List<string>();
        for (int i = 0; i < table.Columns.Count; i++)
        {
            columns.Add("\"" + table.Columns[i].ColumnName + "\"");
        }
        string copySql = $"copy \"public\".\"{tableName}\"({string.Join(',', columns)}) FROM STDIN (FORMAT BINARY)";
        using (var conn = new Npgsql.NpgsqlConnection(_connectionString))
        {
            conn.Open();
            using (var writer = conn.BeginBinaryImport(copySql))
            {
                foreach (DataRow row in table.Rows)
                {
                    writer.StartRow();
                    for (int i = 0; i < table.Columns.Count; i++)
                    {
                        writer.Write(row[i]);
                    }
                }
                writer.Complete();
            }
        }
    }

}

在这里插入图片描述

public class DapperParseGuidTypeHandler : SqlMapper.TypeHandler<Guid?>
{
    public override void SetValue(IDbDataParameter parameter, Guid? guid)
    {
        parameter.Value = guid.ToString();
    }

    public override Guid? Parse(object value)
    {
        if (value == null || value.ToString() == "")
        {
            return null;
        }
        if (value.GetType() == typeof(string))
        {
            return new Guid((string)value);
        }
        return (Guid)value;
    }
}

在这里插入图片描述

1.3 EFCode的使用

1.3.1 BaseDbContext 基类
public abstract class BaseDbContext : DbContext
{
    protected abstract string ConnectionString { get; }

    public bool QueryTracking
    {
        set
        {
            this.ChangeTracker.QueryTrackingBehavior = value ? QueryTrackingBehavior.TrackAll : QueryTrackingBehavior.NoTracking;
        }
    }
    public BaseDbContext() : base() { }
    public BaseDbContext(DbContextOptions<BaseDbContext> options) : base(options) { }
    /// <summary>
    /// 数据库连接配置
    /// </summary>
    /// <param name="optionsBuilder"></param>
    /// <param name="connectionString"></param>
    protected void UseDbType(DbContextOptionsBuilder optionsBuilder,string connectionString)
    {
        if (Const.DBType.Name == Enums.DbCurrentType.MySql.ToString())
        {
            optionsBuilder.UseMySql(connectionString);
        }
        else if (Const.DBType.Name == Enums.DbCurrentType.PgSql.ToString())
        {
            optionsBuilder.UseNpgsql(connectionString);
        }
        else
        {
            optionsBuilder.UseSqlServer(connectionString);
        }
    }
    /// <summary>
    /// (自动注入实体类)
    /// </summary>
    /// <param name="modelBuilder">映射对象</param>
    /// <param name="type">集成Type的实体类</param>
    protected void OnModelCreating(ModelBuilder modelBuilder, Type type)
    {
        try
        {
            //获取所有类库
            var compilationLibrary = DependencyContext
                .Default
                .CompileLibraries
                .Where(x => !x.Serviceable && x.Type != "package" && x.Type == "project");
            foreach (var _compilation in compilationLibrary)
            {
                //加载指定类
                AssemblyLoadContext.Default
                .LoadFromAssemblyName(new AssemblyName(_compilation.Name))
                .GetTypes().Where(x => x.GetTypeInfo().BaseType != null
                && x.BaseType == (type)).ToList()
                .ForEach(t => { modelBuilder.Entity(t); });
            }
            base.OnModelCreating(modelBuilder);
        }
        catch (Exception ex)
        {
            string mapPath = ($"Log/").MapPath();
            Utilities.FileHelper.WriteFile(mapPath, $"syslog_{DateTime.Now.ToString("yyyyMMddHHmmss")}.txt", ex.Message + ex.StackTrace + ex.Source);
        }

    }

}

在这里插入图片描述

1.3.2 SysDbContext系统数据库上下文
public class SysDbContext : BaseDbContext, IDependency
{
    protected override string ConnectionString
    {
        get
        {
            return DBServerProvider.SysConnectingString;
        }
    }
    public SysDbContext() : base() { }

    public SysDbContext(DbContextOptions<BaseDbContext> options) : base(options) { }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.UseDbType(optionsBuilder, ConnectionString);
        //默认禁用实体跟踪
        optionsBuilder = optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        base.OnConfiguring(optionsBuilder);
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder, typeof(SysEntity));
    }
}

在这里插入图片描述

1.3.3 ServiceDbContext业务数据库上下文
public class ServiceDbContext : BaseDbContext, IDependency
{
    protected override string ConnectionString
    {
        get
        {
            return DBServerProvider.ServiceUserCurrnetConnectingString;
        }
    }
    public ServiceDbContext() : base() { }

    public ServiceDbContext(DbContextOptions<BaseDbContext> options) : base(options) { }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.UseDbType(optionsBuilder, ConnectionString);
        //默认禁用实体跟踪
        optionsBuilder = optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        base.OnConfiguring(optionsBuilder);
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder, typeof(ServiceEntity));
    }
}

在这里插入图片描述

1.3.4 ReportDbContext报表数据库上下文
public class ReportDbContext : BaseDbContext, IDependency
{
    protected override string ConnectionString
    {
        get
        {
            return DBServerProvider.ReportConnectingString;
        }
    }
    public ReportDbContext() : base() { }

    public ReportDbContext(DbContextOptions<BaseDbContext> options) : base(options) { }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.UseDbType(optionsBuilder, ConnectionString);
        //默认禁用实体跟踪
        optionsBuilder = optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
        base.OnConfiguring(optionsBuilder);
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder, typeof(ReportEntity));
    }
}

在这里插入图片描述

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: 作为一名程序员,我在2023对自己的计划包括: 1. 不断学习和提升技能:我会继续学习新的编程语言和框架,以及不断提高编码能力。 2. 参加行业相关的培训和会议:我会参加各种行业相关的培训课程和会议,以便获得最新的行业知识和技能。 3. 参加项目并积累经验:我会参加各种项目,以便积累丰富的经验,并提升个人能力。 4. 在业内建立良好的人脉关系:我会努力与业内的同行建立良好的人脉关系,并与他们保持联系。 5. 寻找更好的发展机会:我会不断寻找更好的发展机会,以便在职业生涯中取得更大的成功。 总之,我在2023会努力工作,不断学习和提升,并寻找更好的发展机会,以在职业生涯中取得更大的成功。 ### 回答2: 2023的计划对于我作为一名程序员来说十分重要,我希望能够提升自己的技能水平并取得更好的职业发展。以下是我的计划: 首先,我计划继续学习并掌握新的编程语言和技术。随着科技的不断发展,编程语言和技术也在不断更新换代,作为一名程序员,保持学习的状态是必不可少的。我将花费更多的时间学习目前主流的编程语言,如Python、Java等,并尝试掌握最新的前端和后端技术。通过不断学习,我希望能够拥有更广泛的技术视野和更强大的技术能力。 其次,我计划参与更多的项目和实践。在理论学习之外,实践是提升技能的关键。我计划积极寻找项目机会,无论是个人项目还是团队项目,都可以提供宝贵的实践机会。通过参与各种项目,我可以锻炼解决问题的能力,提高编码和协作能力。同时,我也希望通过实践中的挑战和失败,不断完善自己,进一步提高自己的技术水平和经验。 第三,我计划参加相关的培训和技术交流活动。参加培训和技术交流活动可以与其他程序员交流和学习,了解行业最新动态和趋势。我计划参加各种技术研讨会、讲座和培训班,通过与行业专家和其他程序员的交流,深入了解各种编程技术和最佳实践。同时,我也希望能够积极参与技术社区,与其他程序员分享自己的经验和见解,不断提高自己的影响力和口碑。 最后,我计划在个人项目和开源社区上做出更多的贡献。通过自己的努力,我希望能够在个人项目中实现一些有意义的功能或解决一些实际问题,并将其开源。通过开源社区的贡献,我可以帮助他人解决问题,同时也能够借助其他人的反馈和指导,不断改进自己的代码和设计能力。 总之,2023对于我作为一名程序员来说是充满挑战和机遇的一。我将不懈努力,持续学习和实践,不断提升自己的技能水平和职业发展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愚公搬代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值