using System; using System.Collections; using System.Collections.Generic; using System.Data.Common; using System.Linq; using System.Reflection; using System.Text; using CSFramework.DB.Common; namespace CSFramework.DB { /// /// DbCommand命令生成器,根据对象模型(Type)自动生成三种DbCommand,支持MsSQL,MySQL,Oracle /// public class DbCommandGenerator { private IDatabase _db; /// /// 构造器 /// /// CSFramework.DB数据库底层通用接口 public DbCommandGenerator(IDatabase db) { _db = db; } /// /// 创建Insert命令 - 处理实体对象数据 /// /// 对象类型 /// 自增字段(或不支持更新的字段)数组 /// public DbCommand GetInsertCommand(T obj, params string[] ignoreFields) where T : new() { var model = obj.GetType(); var tableName = GetTableName(model); //获取类对应的表名 var cmd = _db.CreateCommand("", System.Data.CommandType.Text); if (ignoreFields == null || ignoreFields.Length == 0) ignoreFields = GetAttributeFields(obj.GetType(), typeof(IgnoreField)); #region 主表信息========================== var strSql = new StringBuilder(); var str1 = new StringBuilder(); //数据字段 var str2 = new StringBuilder(); //数据参数 //利用反射获得属性的所有公共属性 var pros = model.GetProperties(BindingFlags.Instance | BindingFlags.Public); strSql.Append("INSERT INTO " + tableName + "("); foreach (var pi in pros) { //跳过被忽略的字段(不生成SQL脚本),如:自增字段。必须忽略大小写匹配! if (ignoreFields != null && ignoreFields.Any(e => e.ToLower() == pi.Name.ToLower())) continue; //主键字段或IList数据类型不生成Update-SQL脚本 //IList数据类型不生成Insert-SQL脚本 if (!IsObjectListType(pi.PropertyType)) { //判断属性值是否为空 str1.Append(pi.Name + ","); //拼接字段 str2.Append(_db.ParamSymboName + pi.Name + ","); //声明参数 var p = _db.CreateParameter(pi.Name, GetValue(obj, pi)); cmd.Parameters.Add(p); //对参数赋值 } } strSql.Append(str1.ToString().Trim(',')); strSql.Append(") VALUES ("); strSql.Append(str2.ToString().Trim(',')); strSql.Append("); "); #endregion cmd.CommandText = CodeSafeHelper.GetSafeSQL(strSql.ToString()); return cmd; } /// /// 获取标识有特性(Attribute)的字段 /// /// /// /// /// public string[] GetAttributeFields(Type objType, Type attributeType) { var result = new List(); //获取所有字段属性名称 var pros = objType.GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (var pi in pros) { var list = pi.GetCustomAttributes(attributeType); if (list.Count() > 0) result.Add(pi.Name); } if (result.Count > 0) return result.ToArray(); else return null; } /// /// 创建Insert命令 /// /// 对象类型 /// 自增字段(或不支持更新的字段)数组 /// public DbCommand GetInsertCommand(Type model, params string[] ignoreFields) { var tableName = GetTableName(model); //获取类对应的表名 var cmd = _db.CreateCommand("", System.Data.CommandType.Text); if (ignoreFields == null || ignoreFields.Length == 0) ignoreFields = GetAttributeFields(model, typeof(IgnoreField)); #region 主表信息========================== var strSql = new StringBuilder(); var str1 = new StringBuilder(); //数据字段 var str2 = new StringBuilder(); //数据参数 //利用反射获得属性的所有公共属性 var pros = model.GetProperties(BindingFlags.Instance | BindingFlags.Public); strSql.Append("INSERT INTO " + tableName + "("); foreach (var pi in pros) { //跳过被忽略的字段(不生成SQL脚本),如:自增字段。必须忽略大小写匹配! if (ignoreFields != null && ignoreFields.Any(e => e.ToLower() == pi.Name.ToLower())) continue; //主键字段或IList数据类型不生成Update-SQL脚本 //IList数据类型不生成Insert-SQL脚本 if (!typeof(IList).IsAssignableFrom(pi.PropertyType)) { //判断属性值是否为空 str1.Append(pi.Name + ","); //拼接字段 str2.Append(_db.ParamSymboName + pi.Name + ","); //声明参数 cmd.Parameters.Add(_db.CreateParameter(pi.Name, DataTypeConverter.DotNetType2DbType( pi.PropertyType.Name), 0, pi.Name, DBNull.Value)); //对参数赋值 } } strSql.Append(str1.ToString().Trim(',')); strSql.Append(") VALUES ("); strSql.Append(str2.ToString().Trim(',')); strSql.Append(") "); #endregion cmd.CommandText = CodeSafeHelper.GetSafeSQL(strSql.ToString()); return cmd; } /// /// 创建Delete命令 /// /// 对象类型 /// 主键字段名数组 /// public DbCommand GetDeleteCommand(Type model, params string[] PKs) { if (PKs == null || PKs.Length == 0) PKs = GetAttributeFields(model, typeof(KeyField)); if (PKs == null || PKs.Length == 0) throw new Exception("没有指定主键字段!"); var tableName = GetTableName(model); //获取类对应的表名 var cmd = _db.CreateCommand("", System.Data.CommandType.Text); var PKTypeNames = new Dictionary(); #region 主表信息========================== var strSql = new StringBuilder(); //利用反射获得属性的所有公共属性 var pros = model.GetProperties(BindingFlags.Instance | BindingFlags.Public); strSql.Append("DELETE FROM " + tableName + " WHERE "); foreach (var pi in pros) if (PKs.Any(e => e.ToLower() == pi.Name.ToLower())) PKTypeNames[pi.Name] = pi.PropertyType.Name; //组合主键 WHERE 条件 foreach (var pk in PKs) { if (Array.IndexOf(PKs, pk) == 0) strSql.Append(pk + "=" + _db.ParamSymboName + pk); //声明参数 else strSql.Append(" AND " + pk + "=" + _db.ParamSymboName + pk); //声明参数 cmd.Parameters.Add(_db.CreateParameter(pk, DataTypeConverter.DotNetType2DbType(PKTypeNames[pk]), 0, pk, DBNull.Value)); //对参数赋值 } #endregion cmd.CommandText = CodeSafeHelper.GetSafeSQL(strSql.ToString()); return cmd; } /// /// 创建Delete命令-处理实体对象数据 /// /// 对象类型 /// 主键字段名数组 /// public DbCommand GetDeleteCommand(T obj, params string[] PKs) where T : new() { if (PKs == null || PKs.Length == 0) PKs = GetAttributeFields(obj.GetType(), typeof(KeyField)); if (PKs == null || PKs.Length == 0) throw new Exception("没有指定主键字段!"); var model = obj.GetType(); var tableName = GetTableName(model); //获取类对应的表名 var cmd = _db.CreateCommand("", System.Data.CommandType.Text); var PKTypeNames = new Dictionary(); var PKValues = new Dictionary(); #region 主表信息========================== var strSql = new StringBuilder(); //利用反射获得属性的所有公共属性 var pros = model.GetProperties(BindingFlags.Instance | BindingFlags.Public); strSql.Append("DELETE FROM " + tableName + " WHERE "); foreach (var pi in pros) if (PKs.Any(e => e.ToLower() == pi.Name.ToLower())) { PKTypeNames[pi.Name] = pi.PropertyType.Name; PKValues[pi.Name] = GetValue(obj, pi); } //组合主键 WHERE 条件 foreach (var pk in PKs) { if (Array.IndexOf(PKs, pk) == 0) strSql.Append(pk + "=" + _db.ParamSymboName + pk); //声明参数 else strSql.Append(" AND " + pk + "=" + _db.ParamSymboName + pk); //声明参数 cmd.Parameters.Add(_db.CreateParameter(pk, PKValues[pk])); //对参数赋值 } #endregion cmd.CommandText = CodeSafeHelper.GetSafeSQL(strSql.ToString()); return cmd; } /// /// 创建Update命令 - 处理实体对象数据 /// /// 对象类型 /// 主键字段名数组 /// 自增字段(或不支持更新的字段)数组 /// 指定更新的字段 /// public DbCommand GetUpdateCommand(T obj, string[] PKs = null, string[] ignoreFields = null, string[] updateFields = null) where T : new() { if (PKs == null) PKs = GetAttributeFields(obj.GetType(), typeof(KeyField)); if (ignoreFields == null) ignoreFields = GetAttributeFields(obj.GetType(), typeof(IgnoreField)); if (PKs == null || PKs.Length == 0) throw new Exception("没有指定主键字段!"); var model = obj.GetType(); var tableName = GetTableName(model); //获取类对应的表名 var cmd = _db.CreateCommand("", System.Data.CommandType.Text); var PKTypeNames = new Dictionary(); var PKValues = new Dictionary(); #region 主表信息========================== var strSql = new StringBuilder(); var str1 = new StringBuilder(); //数据字段 var str2 = new StringBuilder(); //数据参数 //利用反射获得属性的所有公共属性 var pros = model.GetProperties(BindingFlags.Instance | BindingFlags.Public); strSql.Append("UPDATE " + tableName + " SET "); var isPK = false; foreach (var pi in pros) { isPK = PKs.Any(e => e.ToLower() == pi.Name.ToLower()); //获取主键的数据类型 if (isPK) { PKTypeNames[pi.Name] = pi.PropertyType.Name; PKValues[pi.Name] = GetValue(obj, pi); } //跳过被忽略的字段(不生成SQL脚本),如:自增字段。必须忽略大小写匹配! if (ignoreFields != null && ignoreFields.Any(e => e.ToLower() == pi.Name.ToLower())) continue; //指定更新的字段 if (updateFields != null && updateFields.Any(e => e.ToLower() == pi.Name.ToLower()) == false) continue; //主键字段或IList数据类型不生成Update-SQL脚本 //IList数据类型不生成Insert-SQL脚本 if (!isPK && !typeof(IList).IsAssignableFrom(pi.PropertyType)) { //判断属性值是否为空 str1.Append(pi.Name + "=" + _db.ParamSymboName + pi.Name + ","); //声明参数 cmd.Parameters.Add( _db.CreateParameter(pi.Name, GetValue(obj, pi))); //对参数赋值 } } strSql.Append(str1.ToString().Trim(',')); strSql.Append(" WHERE "); foreach (var pk in PKs) { if (Array.IndexOf(PKs, pk) == 0) strSql.Append(pk + "=" + _db.ParamSymboName + pk); //声明参数 else strSql.Append(" AND " + pk + "=" + _db.ParamSymboName + pk); //声明参数 cmd.Parameters.Add(_db.CreateParameter(pk, PKValues[pk])); //对参数赋值 } #endregion cmd.CommandText = CodeSafeHelper.GetSafeSQL(strSql.ToString()); return cmd; } /// /// 创建Update命令 /// /// 对象类型 /// 主键字段名数组 /// 自增字段(或不支持更新的字段)数组 /// 指定更新的字段 /// public DbCommand GetUpdateCommand(Type model, string[] PKs = null, string[] ignoreFields = null, string[] updateFields = null) { if (PKs == null) PKs = GetAttributeFields(model, typeof(KeyField)); if (ignoreFields == null) ignoreFields = GetAttributeFields(model, typeof(IgnoreField)); if (PKs == null || PKs.Length == 0) throw new Exception("没有指定主键字段!"); var tableName = GetTableName(model); //获取类对应的表名 var cmd = _db.CreateCommand("", System.Data.CommandType.Text); var PKTypeNames = new Dictionary(); #region 主表信息========================== var strSql = new StringBuilder(); var str1 = new StringBuilder(); //数据字段 var str2 = new StringBuilder(); //数据参数 //利用反射获得属性的所有公共属性 var pros = model.GetProperties(BindingFlags.Instance | BindingFlags.Public); strSql.Append("UPDATE " + tableName + " SET "); var isPK = false; foreach (var pi in pros) { isPK = PKs.Any(e => e.ToLower() == pi.Name.ToLower()); //获取主键的数据类型 if (isPK) PKTypeNames[pi.Name] = pi.PropertyType.Name; //跳过被忽略的字段(不生成SQL脚本),如:自增字段。必须忽略大小写匹配! if (ignoreFields != null && ignoreFields.Any(e => e.ToLower() == pi.Name.ToLower())) continue; //指定更新的字段 if (updateFields != null && updateFields.Any(e => e.ToLower() == pi.Name.ToLower()) == false) continue; //主键字段或IList数据类型不生成Update-SQL脚本 //IList数据类型不生成Insert-SQL脚本 if (!isPK && !typeof(IList).IsAssignableFrom(pi.PropertyType)) { //判断属性值是否为空 str1.Append(pi.Name + "=" + _db.ParamSymboName + pi.Name + ","); //声明参数 cmd.Parameters.Add(_db.CreateParameter(pi.Name, DataTypeConverter.DotNetType2DbType( pi.PropertyType.Name), 0, pi.Name, DBNull.Value)); //对参数赋值 } } strSql.Append(str1.ToString().Trim(',')); strSql.Append(" WHERE "); foreach (var pk in PKs) { if (Array.IndexOf(PKs, pk) == 0) strSql.Append(pk + "=" + _db.ParamSymboName + pk); //声明参数 else strSql.Append(" AND " + pk + "=" + _db.ParamSymboName + pk); //声明参数 cmd.Parameters.Add(_db.CreateParameter(pk, DataTypeConverter.DotNetType2DbType(PKTypeNames[pk]), 0, pk, DBNull.Value)); //对参数赋值 } #endregion cmd.CommandText = CodeSafeHelper.GetSafeSQL(strSql.ToString()); return cmd; } /// /// 判断属性的数据类型是对象列表(对象列表不支持生成SQL,必须转换为byte[]) /// /// 属性类型 /// private bool IsObjectListType(Type propertyType) { if (propertyType == null) return false; //特殊处理,数组类型byte[]允许存储数据库 if (propertyType == typeof(byte[])) return false; return typeof(IList).IsAssignableFrom(propertyType); } /// /// 获取对象属性的值 /// /// /// /// private object GetValue(object obj, PropertyInfo pi) { var o = pi.GetValue(obj, null); //转换DBNull,非常重要!!! if (o == null) return DBNull.Value; if (pi.PropertyType == typeof(DateTime)) //处理空日期 if (DateTime.MinValue == DateTime.Parse(o.ToString())) return DBNull.Value; return o; } /// /// 获取类对应的表名 /// /// 实体模型对应的类 /// public string GetTableName(Type model) { //从类的特性获取 var list = model.GetCustomAttributes(typeof(TableInfoAttribute), false); if (list != null && list.Length > 0) return (list[0] as TableInfoAttribute).TableName; else return model.Name; //类名既表名 } } }