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; //类名既表名
}
}
}