///////////////////////////////////////////////////////////////////////////// // File Description : DAL中的所有数据访问类,都需要继承BaseDAL // Copyright : joyin // ------------------------------------------------------------------------- // Date Created : Mar 26, 2010 // Author : jiangxinjun // -------------------------------------------------------------------------// ///////////////////////////////////////////////////////////////////////////// #region Namespace using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.Common; using System.Reflection; using HanHe.Utility; using HanHe.Utility.Data; using HH.WMS.Entitys.Common; using HH.WMS.Common; using HH.Redis.ReisModel; using HH.WMS.Entitys.Basic; #endregion namespace HH.WMS.DAL { /// /// 创建Database委托 /// /// 数据访问工具类实例 //public delegate Database CreateDataBaseHandler(); /// /// DAL所有数据访问类的基类 /// /// DAL中的所有数据访问类,都需要继承BaseDAL public class ErpBaseDAL : BaseDataUtility { public RedisUserEntity userInfo; public enum DBTYPE { MYSQL, MSSQL, ORACLE, ORTHER } public DBTYPE NowDbType { get { if (Now_dbType.Equals("MYSQL")) return DBTYPE.MYSQL; if (Now_dbType.Equals("MSSQL")) return DBTYPE.MSSQL; if (Now_dbType.Equals("ORACLE")) return DBTYPE.ORACLE; return DBTYPE.ORTHER; } } public string Now_dbType = "MSSQL"; /// /// 创建Database委托 /// /// 数据访问工具类实例 public delegate Database CreateDataBaseHandler(); #region 初始化 private Database db; private string databaseName; /// /// 默认的数据库连接字符串在配置文件的名称(根据连接配置获得所要连接的数据库) /// internal static readonly string DATABASE_NAME = "erpConnection"; /// /// 默认根据属性名获取属性对象的策略。 /// private static BindingFlags PublicInstancePropertyBindingFlags = BindingFlags.CreateInstance | BindingFlags.Instance //实例 | BindingFlags.Public //公有 | BindingFlags.SetProperty //可写属性 | BindingFlags.IgnoreCase; //忽略大小写 /// /// 构造函数 /// public ErpBaseDAL() : this(DATABASE_NAME) { } /// /// 构造函数 /// /// 数据库连接字符串在配置文件的名称 internal ErpBaseDAL(string databaseName) { this.databaseName = databaseName; } /// /// 创建Database对象 /// /// 数据访问工具类实例 protected override Database CreateDataBase() { if (db == null) { db = CreateDataAccess(databaseName); } return db; } /// /// 获取Database对象 /// private Database Database { get { return CreateDataBase(); } } #endregion #region DataAccess /// /// 数据库执行工具类 /// internal protected new Database DataAccess { get { return base.DataAccess; } } #endregion #region ExecuteInsertWithGetIdentity /// /// 执行Insert语句,并且输出新增的自增长值 /// /// Sql命令 /// 事务对象,如果为null,则不使用事务 /// 如果执行Insert语句成功,则输出自增长值;否则输出0. /// 执行结果,参考 /// 如果参数trans不为null的话:调用此方法的过程中,trans是不会做Commit,必须方法外部做Commit;但如果出现异常,trans会执行Rollback。 internal SqlExecuteResult ExecuteInsertWithGetIdentity(DbCommand cmd, DbTransaction trans, out int id) { SqlExecuteResult result = new SqlExecuteResult(); id = default(int); //在Insert语句后面添加获取自增长Id的语句 cmd.CommandText += ";" + CommonUseSqlFormat.RETRIEVE_NEWID; if (trans == null) { try { object newid = DataAccess.ExecuteScalar(cmd); if (!IsNullValue(newid)) { id = Convert.ToInt32(newid); result.Success = true; } } catch (Exception ex) { result.Success = false; result.Exception = ex; } } else { try { object newid = DataAccess.ExecuteScalar(cmd, trans); if (!IsNullValue(newid)) { id = Convert.ToInt32(newid); result.Success = true; } } catch (Exception ex) { result.Success = false; result.Exception = ex; DAOManager.RollbackTransaction(trans); } } return result; } #endregion #region ExecuteCommand /// /// 在事务中,执行Sql命令。 /// /// Sql命令 /// 事务对象,如果为null,则不使用事务 /// 执行结果,参考 /// 如果参数trans不为null的话:调用此方法的过程中,trans是不会做Commit,必须方法外部做Commit;但如果出现异常,trans会执行Rollback。 internal SqlExecuteResult ExecuteCommand(DbCommand command, DbTransaction trans) { SqlExecuteResult result = new SqlExecuteResult(); if (trans == null) { //自己创建一个事务执行 return DAOManager.ExecuteTransaction(this.Database, _trans => { try { result.Row = DataAccess.ExecuteNonQuery(command, _trans); result.Success = true; } catch (Exception ex) { result.Success = false; result.Exception = ex; DAOManager.RollbackTransaction(_trans); } return result; }); } else { try { result.Row = DataAccess.ExecuteNonQuery(command, trans); result.Success = true; } catch (Exception ex) { result.Success = false; result.Exception = ex; DAOManager.RollbackTransaction(trans); } } return result; } #endregion #region ExecuteCommands /// /// 在事务中,执行一组Sql命令。 /// /// Sql命令列表 /// 事务对象,如果为null,则不使用事务 /// 执行结果,参考 /// 如果参数trans不为null的话:调用此方法的过程中,trans是不会做Commit,必须方法外部做Commit;但如果出现异常,trans会执行Rollback。 public SqlExecuteResult ExecuteCommands(List commands, DbTransaction trans) { SqlExecuteResult result = new SqlExecuteResult(); if (trans == null) { //自己创建一个事务执行 return DAOManager.ExecuteTransaction(this.Database, _trans => { try { foreach (var command in commands) { DataAccess.ExecuteNonQuery(command, _trans); } result.Success = true; } catch (Exception ex) { result.Success = false; result.Exception = ex; DAOManager.RollbackTransaction(_trans); } return result; }); } else { try { foreach (var command in commands) { DataAccess.ExecuteNonQuery(command, trans); } result.Success = true; } catch (Exception ex) { result.Success = false; result.Exception = ex; DAOManager.RollbackTransaction(trans); } } return result; } #endregion #region CheckExit /// /// /// /// 表名称 /// 栏位名 /// 比对的值 /// PK的栏位 /// /// 输出结果,参考。如果数据存在,SqlExecuteResult的TokenObject包含了此笔数据的Id值;Exception抛出的异常类型为CheckExistException internal bool CheckExitObj(string tableName, string columnName, string mapperValue , string idColumnName) { bool isExist = false; /* * 组合执行以下Sql * select {idColumnName} from {tableName} where {columnName} = {mapperValue} */ string sql = string.Format("SELECT {2} FROM {0} WHERE {1} = @val " , tableName, columnName, idColumnName); DbCommand cmd = DataAccess.GetSqlStringCommand(sql); DataAccess.AddInParameter(cmd, "val", DbType.String, mapperValue); object _Obj = DataAccess.ExecuteScalar(cmd); if (_Obj != null) isExist = true; return isExist; } #endregion #region CheckExist /// /// 检查数据是否在数据库中才能在 /// /// 表名称 /// 栏位名 /// 比对的值 /// PK的栏位 /// 事务 /// 输出结果,参考。如果数据存在,SqlExecuteResult的TokenObject包含了此笔数据的Id值;Exception抛出的异常类型为CheckExistException /// true,表示数据已存在;false,相关数据不存在。 internal bool CheckExist(string tableName, string columnName, string mapperValue , string idColumnName, DbTransaction trans , out SqlExecuteResult result) { bool isExist = false; result = null; /* * 组合执行以下Sql * select {idColumnName} from {tableName} where {columnName} = {mapperValue} */ string sql = string.Format("SELECT {2} FROM {0} WHERE {1} = @val " , tableName, columnName, idColumnName); DbCommand cmd = DataAccess.GetSqlStringCommand(sql); DataAccess.AddInParameter(cmd, "val", DbType.String, mapperValue); using (IDataReader dr = (trans == null ? DataAccess.ExecuteReader(cmd) : DataAccess.ExecuteReader(cmd, trans))) { if (dr.Read()) { isExist = true; result = new SqlExecuteResult() { Success = false, //检测记录是否存在的异常 Exception = new CheckExistException() { Mark = columnName.ToLower() }, TokenObject = dr[idColumnName], }; } dr.Close(); } // object obj = (trans == null ? DataAccess.ExecuteScalar(cmd) : DataAccess.ExecuteScalar(cmd, trans)); return isExist; } #endregion #region SetCommandValue #region CommandMapper /// /// 字段名称映射 /// internal class CommandMapper { /// /// 构造函数 /// /// 字段名称(参数名与字段名一样、属性名为字段名去掉下划线) internal CommandMapper(string colName) : this(colName, colName, GetPropertyNameByColumnName(colName)) { } /// /// 构造函数 /// /// 字段名称 /// 参数名称 /// 属性名称 internal CommandMapper(string colName, string parameterName, string propertyName) { this.ColumnName = colName; this.ParameterName = parameterName; this.PropertyName = propertyName; } /// /// 字段名称 /// internal string ColumnName { get; private set; } /// /// 参数名称 /// internal string ParameterName { get; private set; } /// /// 属性名称 /// internal string PropertyName { get; private set; } } #endregion #region SetCommandValueWithCheck /// /// 为DbCommand赋值参数,赋值时添加检测(只检测字符串大小是否大于数据库所设长度) /// /// 实体 /// 字段、属性、参数名称的映射关系 /// Command对象 /// Command要设置的相关表名 /// 错误参数信息,如果没错误返回空集合 internal List SetCommandValueWithCheck(object entity , List mappers , DbCommand cmd, string tableName) { List list = new List(); Type entityType = entity.GetType(); foreach (var mapper in mappers) { PropertyInfo pInfo = entityType.GetProperty(mapper.PropertyName, PublicInstancePropertyBindingFlags); if (pInfo == null) throw new Exception(entityType.FullName + "类型不存在" + mapper.PropertyName + "属性"); Type pType = pInfo.PropertyType; if (pType == typeof(string)) { //字符串才检验 var checkInvalid = SetCommandValueWithCheck(entity , pInfo , mapper.ParameterName , cmd , mapper.ColumnName , tableName); if (checkInvalid != null) { list.Add(checkInvalid); } } else { if (CollectionUti.HasItem(list)) { continue; } else { this.SetCommandValue(entity, pInfo, mapper.ParameterName, cmd); } } } return list; } /// /// 为DbCommand赋值参数,赋值时添加检测(只检测字符串大小是否大于数据库所设长度) /// /// 相关实体 /// 属性名称 /// 要复制的采纳数 /// DbCommand命令 /// 字段名 /// 表名 /// internal CheckInvalidValue SetCommandValueWithCheck(object entity, string propertyName , string parameterName, DbCommand cmd , string mapperColName, string tableName) { Type entityType = entity.GetType(); PropertyInfo pInfo = entityType.GetProperty(propertyName, PublicInstancePropertyBindingFlags); if (pInfo == null) throw new Exception(entityType.FullName + "类型不存在" + propertyName + "属性"); return SetCommandValueWithCheck(entity , pInfo , parameterName , cmd , mapperColName , tableName); } /// /// 为DbCommand赋值参数,赋值时添加检测(只检测字符串大小是否大于数据库所设长度) /// /// 相关实体 /// 属性名称 /// 要复制的采纳数 /// DbCommand命令 /// 字段名 /// 表名 /// internal CheckInvalidValue SetCommandValueWithCheck(object entity, PropertyInfo pInfo , string parameterName, DbCommand cmd , string mapperColName, string tableName) { object val = pInfo.GetValue(entity, null); CheckInvalidValue checkInvalidValue = null; mapperColName = mapperColName.ToUpper(); var schema = DAOManager.LoadTableSchema(tableName, this.DataAccess); if (!schema.ContainsKey(mapperColName)) { throw new Exception(mapperColName + "在表" + tableName + "中不存在"); } DatabaseColumnStruct dbColumnStruct = schema[mapperColName]; //字符串才检查 if (dbColumnStruct.DbType == typeof(string)) { if (!dbColumnStruct.AllowDBNull && (val == null || val.ToString() == "")) { //检查为null不合法 checkInvalidValue = new CheckInvalidValue() { DBColumnStruct = dbColumnStruct, EntityType = entity.GetType(), PropertyName = pInfo.Name, Value = val, InvalidMessage = "不允许为空" }; } if (checkInvalidValue == null && val != null) { //检查长度 string valString = val.ToString(); if (valString.Length > dbColumnStruct.Size) { checkInvalidValue = new CheckInvalidValue() { DBColumnStruct = dbColumnStruct, EntityType = entity.GetType(), PropertyName = pInfo.Name, Value = val, InvalidMessage = "超过数据库预设长度" + dbColumnStruct.Size.ToString() }; } } } if (checkInvalidValue == null) { //为DbCommand赋值 DataAccess.AddInParameter(cmd, parameterName, DbType.String, val ?? (object)DBNull.Value); } return checkInvalidValue; } /// /// 为DbCommand赋值参数,赋值时添加检测(只检测字符串大小是否大于数据库所设长度) /// /// 值 /// 参数名称 /// Command对象 /// 对应的字段名称 /// Command要设置的相关表名 /// 错误参数信息,如果没错误返回null internal CheckInvalidValue SetCommandValueWithCheck(object val, string parameterName , DbCommand cmd , string mapperColName , string tableName) { CheckInvalidValue checkInvalidValue = null; mapperColName = mapperColName.ToUpper(); var schema = DAOManager.LoadTableSchema(tableName, this.DataAccess); if (!schema.ContainsKey(mapperColName)) { throw new Exception(mapperColName + "在表" + tableName + "中不存在"); } DatabaseColumnStruct dbColumnStruct = schema[mapperColName]; //字符串才检查 if (dbColumnStruct.DbType == typeof(string)) { if (!dbColumnStruct.AllowDBNull && (val == null || val.ToString() == "")) { //检查为null不合法 checkInvalidValue = new CheckInvalidValue() { DBColumnStruct = dbColumnStruct, EntityType = null, PropertyName = null, Value = val, InvalidMessage = "不允许为空" }; } if (checkInvalidValue == null && val != null) { //检查长度 string valString = val.ToString(); if (valString.Length > dbColumnStruct.Size) { checkInvalidValue = new CheckInvalidValue() { DBColumnStruct = dbColumnStruct, EntityType = null, PropertyName = null, Value = val, InvalidMessage = "超过数据库预设长度" + dbColumnStruct.Size.ToString() }; } } } if (checkInvalidValue == null) { //为DbCommand赋值 DataAccess.AddInParameter(cmd, parameterName, DbType.String, val ?? (object)DBNull.Value); } return checkInvalidValue; } #endregion #region SetCommandValue /// /// 为DbCommand赋值参数 /// /// 实体 /// 实体的属性名 /// 参数名 /// DbCommand对象 internal void SetCommandValue(object entity, string propName, string parameterName, DbCommand cmd) { PropertyInfo pInfo = entity.GetType().GetProperty(propName); SetCommandValue(entity, pInfo, parameterName, cmd); } /// /// 为DbCommand赋值参数 /// /// 实体 /// 实体的属性 /// 参数名 /// DbCommand对象 private void SetCommandValue(object entity, PropertyInfo pInfo, string parameterName, DbCommand cmd) { Type type = pInfo.PropertyType; object val = pInfo.GetValue(entity, null); if (type.IsEnum) { val = (int)val; type = typeof(int); } if (type == typeof(int)) { DataAccess.AddInParameter(cmd, parameterName, DbType.Int32, val); } else if (type == typeof(decimal)) { DataAccess.AddInParameter(cmd, parameterName, DbType.Decimal, val); } else if (type == typeof(DateTime)) { DataAccess.AddInParameter(cmd, parameterName, DbType.DateTime, val); } else if (type == typeof(double)) { DataAccess.AddInParameter(cmd, parameterName, DbType.Double, val); } else if (type == typeof(long)) { DataAccess.AddInParameter(cmd, parameterName, DbType.Int64, val); } else if (type == typeof(int?)) { DataAccess.AddInParameter(cmd, parameterName, DbType.Int32, GetNullableDbValue((int?)val)); } else if (type == typeof(decimal?)) { DataAccess.AddInParameter(cmd, parameterName, DbType.Decimal, GetNullableDbValue((decimal?)val)); } else if (type == typeof(DateTime?)) { DataAccess.AddInParameter(cmd, parameterName, DbType.DateTime, GetNullableDbValue((DateTime?)val)); } else if (type == typeof(double?)) { DataAccess.AddInParameter(cmd, parameterName, DbType.Double, GetNullableDbValue((double?)val)); } else if (type == typeof(long?)) { DataAccess.AddInParameter(cmd, parameterName, DbType.Int64, GetNullableDbValue((long?)val)); } else { DataAccess.AddInParameter(cmd, parameterName, DbType.String, val); } } #endregion #endregion #region GetPropertyNameByColumnName /// /// 根据字段名称,寻找属性名称的默认规则 /// /// 字段名称 /// 返回实体属性名称 internal static string GetPropertyNameByColumnName(string colName) { return colName.Replace("_", ""); } #endregion #region SetEntityUti /// /// 创建SetEntity的委托 /// /// 实体的类型 /// internal Action CreateSetEntityHandler() where T : BaseEntity { return new Action((_entity, _reader) => { SetEntityUti(_entity, _reader); }); } /// /// 从DataReader获取数据到实体 /// /// 实体,不允许为空 /// DataReader对象,不允许为空 internal void SetEntityUti(object entity, IDataReader dr) { this.SetEntityUti(entity, dr, delegate { return true; }); } /// /// 从DataReader获取数据到实体 /// /// 实体,不允许为空 /// DataReader对象,不允许为空 /// 属性与字段名称的映射,Key:为字段名,必须都为大写;Value为属性名 internal void SetEntityUti(object entity, IDataReader dr, Dictionary mapper) { SetEntityUti(entity, dr, (_pInfo, _colName) => { if (mapper.ContainsKey(_colName.ToUpper())) { SetEntityUti(entity, mapper[_colName.ToUpper()], _colName, dr); return false; } return true; }); } /// /// 从DataReader获取数据到实体 /// /// 实体,不允许为空 /// DataReader对象,不允许为空 /// 特殊处理,返回true时,就函数默认处理;返回false,函数就不处理 internal void SetEntityUti(object entity, IDataReader dr, Func action) { Type entityType = entity.GetType(); //循环dr的所有字段 int fieldCount = dr.FieldCount; for (int fieldIndex = 0; fieldIndex < fieldCount; fieldIndex++) { //根据字段名称转换为属性名 string colName = dr.GetName(fieldIndex); string propertyName = GetPropertyNameByColumnName(colName); PropertyInfo pInfo = entityType.GetProperty(propertyName, PublicInstancePropertyBindingFlags); if (action(pInfo, colName) && pInfo != null) { SetEntityUti(entity, pInfo, colName, dr); } } } /// /// 从DataReader获取数据到实体 /// /// 实体,不允许为空 /// 属性名,不允许为空 /// 字段名,不允许为空 /// DataReader对象,不允许为空 /// 一般不建议使用,效率问题 internal void SetEntityUti(object entity, string propName, string colName, IDataReader dr) { if (string.IsNullOrEmpty(propName)) throw new NullReferenceException("pInfo不允许为空"); if (entity == null) throw new NullReferenceException("entity不允许为空"); PropertyInfo pInfo = entity.GetType().GetProperty(propName, PublicInstancePropertyBindingFlags); if (pInfo == null) { throw new Exception(propName + "属性在" + entity.GetType().FullName + "不存在"); } SetEntityUti(entity, pInfo, colName, dr); } /// /// 从DataReader获取数据到实体 /// /// 实体,不允许为空 /// 属性对象,不允许为空 /// 字段名,不允许为空 /// DataReader对象,不允许为空 /// 一般不建议使用,效率问题 internal void SetEntityUti(object entity, PropertyInfo pInfo, string colName, IDataReader dr) { if (pInfo == null) throw new NullReferenceException("pInfo不允许为空"); if (entity == null) throw new NullReferenceException("entity不允许为空"); Type pType = pInfo.PropertyType; if (pType == typeof(int)) { pInfo.SetValue(entity, GetDataByDataReader(dr, colName, DefaultData.INT), null); } else if (pType == typeof(decimal)) { pInfo.SetValue(entity, GetDataByDataReader(dr, colName, DefaultData.DECIMAL), null); } else if (pType == typeof(DateTime)) { pInfo.SetValue(entity, GetDataByDataReader(dr, colName, DefaultData.DATETIME), null); } else if (pType == typeof(long)) { pInfo.SetValue(entity, GetDataByDataReader(dr, colName, DefaultData.LONG), null); } else if (pType == typeof(int?)) { pInfo.SetValue(entity, GetNullableDataByDataReader(dr, colName), null); } else if (pType == typeof(decimal?)) { pInfo.SetValue(entity, GetNullableDataByDataReader(dr, colName), null); } else if (pType == typeof(DateTime?)) { pInfo.SetValue(entity, GetNullableDataByDataReader(dr, colName), null); } else if (pType == typeof(Boolean)) { pInfo.SetValue(entity, GetNullableDataByDataReader(dr, colName), null); } else if (pType == typeof(String)) { if (!string.IsNullOrEmpty(GetDataByDataReader(dr, colName, DefaultData.STRING).Trim())) { pInfo.SetValue(entity, GetDataByDataReader(dr, colName, DefaultData.STRING).Trim(), null); } else { pInfo.SetValue(entity, GetDataByDataReader(dr, colName, DefaultData.STRING), null); } } else if (pType == typeof(long?)) { pInfo.SetValue(entity, GetNullableDataByDataReader(dr, colName), null); } else { pInfo.SetValue(entity, GetTrimString(dr, colName).Trim(), null); } } #endregion #region GetNullableDbValue /// /// 把可空值的数据转成Db数据 /// /// /// /// internal static object GetNullableDbValue(Nullable val) where T : struct { if (val.HasValue) { return val.Value; } return DBNull.Value; } #endregion #region 可供自定义创建Database /// /// 【提供给UnitTest使用】Be convenient for changing the ConnectionString in test. /// private static CreateDataBaseHandler createDataBaseHandler; /// /// 【提供给UnitTest使用】Change the default connection string /// /// public static void SetCreateDataBaseHandler(CreateDataBaseHandler handler) { createDataBaseHandler = handler; } #endregion #region CreateDataAccess /// /// 获取配置文件中的数据库字符串信息,并解密 /// /// /// public static Database CreateDataAccess(string databaseName) { Database database = null; if (createDataBaseHandler == null) { //读取Web.Config var config = ConfigurationManager.ConnectionStrings[databaseName]; //config.ConnectionString = ConnectionStringCryptography.Decrypt(config.ConnectionString); //解密字符串 ConnectionStringSettings csCopy = new ConnectionStringSettings(); // csCopy.ConnectionString = ConnectionStringCryptography.Decrypt(config.ConnectionString); csCopy.ConnectionString = config.ConnectionString; csCopy.ProviderName = config.ProviderName; csCopy.Name = config.Name; database = DatabaseFactory.CreateDatabase(csCopy); } else { database = createDataBaseHandler(); } return database; } #endregion } }