using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Text; namespace LJLib.DAL.SQL { /// /// 全局初始化时,需要添加要支持的引擎(SqlServer/Sqlite) /// internal static class DbSqlHelper { /// /// 从数据库获取当前时间 /// SQL Server :SELECT GETDATE() /// SQLite :SELECT DATETIME() /// public static DateTime GetServerTime(TCommand cmd) where TCommand : DbCommand { var engine = GetEngine(cmd.GetType()); return engine.GetServerTime(cmd); } /// /// 获取单表中符合条件的行数 /// public static int SelectCount(TCommand cmd, string table, string wherestr, IDictionary sqlparams = null) where TCommand : DbCommand { string strcmd = "SELECT COUNT(0) FROM " + table; if (!string.IsNullOrEmpty(wherestr)) { wherestr = wherestr.Trim(); strcmd += " WHERE " + wherestr; } cmd.CommandText = strcmd; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); if (sqlparams != null) { foreach (var sqlparam in sqlparams) { var value = sqlparam.Value; if (value == null) { value = DBNull.Value; } AddWithValue(cmd, sqlparam.Key, value); } } return Convert.ToInt32(cmd.ExecuteScalar()); } /// /// 添加参数值 /// private static void AddWithValue(TCommand cmd, string name, object value) where TCommand : DbCommand { var engine = GetEngine(cmd.GetType()); engine.AddWithValue(cmd, name, value); if (cmd.Parameters[name].Value == null) { cmd.Parameters[name].Value = DBNull.Value; } } public static void SelectJoin(TCommand cmd, string selectStr, string whereStr, IDictionary parms, string orderByStr, string outputFields, int pageindex, int pagesize, List returnList) where TCommand : DbCommand where T : new() { cmd.CommandText = SqlStrHelper.BuildSelectStr(selectStr, ref outputFields, whereStr, orderByStr, pageindex, pagesize); ; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); if (parms != null) { foreach (var parm in parms) { AddWithValue(cmd, parm.Key, parm.Value); } } var properties = GetProperties(typeof(T), outputFields); GetValues(cmd, returnList, properties); } private static object ConvertValue(Type parmType, object value) { if (!parmType.IsAssignableFrom(value.GetType())) { if (parmType.IsAssignableFrom(typeof(byte))) { value = Convert.ToByte(value); } else if (parmType.IsAssignableFrom(typeof(sbyte))) { value = Convert.ToSByte(value); } else if (parmType.IsAssignableFrom(typeof(short))) { value = Convert.ToInt16(value); } else if (parmType.IsAssignableFrom(typeof(ushort))) { value = Convert.ToUInt16(value); } else if (parmType.IsAssignableFrom(typeof(int))) { value = Convert.ToInt32(value); } else if (parmType.IsAssignableFrom(typeof(uint))) { value = Convert.ToUInt32(value); } else if (parmType.IsAssignableFrom(typeof(long))) { value = Convert.ToInt64(value); } else if (parmType.IsAssignableFrom(typeof(ulong))) { value = Convert.ToUInt64(value); } else if (parmType.IsAssignableFrom(typeof(float))) { value = Convert.ToSingle(value); } else if (parmType.IsAssignableFrom(typeof(double))) { value = Convert.ToDouble(value); } else if (parmType.IsAssignableFrom(typeof(decimal))) { value = Convert.ToDecimal(value); } else if (parmType.IsAssignableFrom(typeof(bool))) { value = Convert.ToBoolean(value); } else if (parmType.IsAssignableFrom(typeof(bool))) { value = Convert.ToBoolean(value); } else if (parmType.IsAssignableFrom(typeof(char))) { value = Convert.ToChar(value); } else if (parmType.IsAssignableFrom(typeof(DateTime))) { value = Convert.ToDateTime(value); } else if (parmType.IsAssignableFrom(typeof(string))) { value = Convert.ToString(value); } else if (parmType.IsEnum) { value = Enum.ToObject(parmType, value); } else { throw new Exception(string.Format("不能将{0}转换成{1}", value.GetType(), parmType)); } } return value; } public static int Select(TCommand cmd, string tablename, string whereStr, IDictionary parms, string orderStr, int pagesize, int pageindex, IList modles, IDictionary maps, string fields) where TCommand : DbCommand where T : new() { var strCmd = string.Format("SELECT {0} FROM {1}", fields, tablename); cmd.CommandText = SqlStrHelper.BuildSelectStr(strCmd, ref fields, whereStr, orderStr, pageindex, pagesize); cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); if (parms != null) { foreach (var parm in parms) { AddWithValue(cmd, parm.Key, parm.Value); } } var targetMaps = GetTargetMaps(maps, fields); using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { T modle = new T(); GetValue(reader, modle, targetMaps); modles.Add(modle); } } return modles.Count; } private static void GetValue(DbDataReader reader, object modle, Dictionary targetMaps) { foreach (var property in targetMaps) { MethodInfo setMethod = property.Value.GetSetMethod(); if (setMethod == null) { continue; } object value = null; try { value = reader[property.Key]; } catch (Exception) { continue; } if (value == null || value == DBNull.Value) { continue; } if (value is string) { value = value.ToString().Trim(); } var parmType = setMethod.GetParameters()[0].ParameterType; value = ConvertValue(parmType, value); setMethod.Invoke(modle, new object[] { value }); } } public static int Select(TCommand cmd, IList modles, string wherestr, string fields = "*") where TCommand : DbCommand where T : new() { return Select(cmd, modles, wherestr, null, null, fields, 0, 0); } public static int Select(TCommand cmd, IList modles, string wherestr, IDictionary sqlparams, string fields = "*") where TCommand : DbCommand where T : new() { return Select(cmd, modles, wherestr, sqlparams, null, fields, 0, 0); } public static int Select(TCommand cmd, IList modles, string wherestr, IDictionary sqlparams, int pageindex, int pagesize, string orderstr, string fields = "*") where TCommand : DbCommand where T : new() { return Select(cmd, modles, wherestr, sqlparams, orderstr, fields, pageindex, pagesize); } public static int Select(TCommand cmd, IList modles, string whereStr, IDictionary sqlparams, string orderByStr, string outputFields, int pageindex, int pagesize) where TCommand : DbCommand where T : new() { if (modles.IsReadOnly) { throw new ArgumentException("参数modles不能为只读"); } var propertyies = GetProperties(typeof(T), outputFields); if (propertyies.Count == 0) { propertyies = new List(GetProperties(typeof(T)).Values); } var strCmd = string.Empty; foreach (var propertyInfo in propertyies) { if (string.IsNullOrEmpty(strCmd)) { strCmd = propertyInfo.Name; } else { strCmd += "," + propertyInfo.Name; } } strCmd = "SELECT " + strCmd + " FROM " + typeof(T).Name; var outCmdStr = SqlStrHelper.BuildSelectStr(strCmd, ref outputFields, whereStr, orderByStr, pageindex, pagesize); cmd.CommandText = outCmdStr; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); if (sqlparams != null) { foreach (var parm in sqlparams) { AddWithValue(cmd, parm.Key, parm.Value); } } GetValues(cmd, modles, propertyies); return modles.Count; } private static void GetValues(TCommand cmd, IList modles, IList propertyies) where TCommand : DbCommand where T : new() { try { using (var reader = cmd.ExecuteReader()) { while (reader.Read()) { T modle = new T(); GetValue(reader, modle, propertyies); modles.Add(modle); } } } catch (Exception) { //Debug.Write(cmd.CommandText); throw; } } private static void GetValue(DbDataReader reader, T modle, IList propertyies) { foreach (PropertyInfo property in propertyies) { MethodInfo setMethod = property.GetSetMethod(); if (setMethod == null) { continue; } object value = null; try { value = reader[property.Name]; } catch (Exception) { continue; } if (value == null || value == DBNull.Value) { continue; } if (value is string) { value = value.ToString().Trim(); } var parmType = setMethod.GetParameters()[0].ParameterType; value = ConvertValue(parmType, value); setMethod.Invoke(modle, new object[] { value }); } } private static object _pksyncRoot = new object(); private static Dictionary _type_pks = new Dictionary(); private static string[] GetPKs(Type type) { // DONE: 返回模型类的主键 lock (_pksyncRoot) { if (_type_pks.ContainsKey(type)) { return _type_pks[type]; } var attrs = type.GetCustomAttributes(typeof(PK), true); if (attrs.Length == 0) { _type_pks[type] = new string[] { }; } else { PK pk = attrs[0] as PK; _type_pks[type] = pk.keys; } return _type_pks[type]; } } public static int SelectOne(TCommand cmd, string tablename, string whereStr, IDictionary parms, T Modle, string fields) where TCommand : DbCommand { // 生成语句 var propertyies = GetProperties(typeof(T), fields); if (propertyies.Count == 0) { propertyies = new List(GetProperties(typeof(T)).Values); } var strCmd = string.Empty; foreach (var propertyInfo in propertyies) { if (string.IsNullOrEmpty(strCmd)) { strCmd = propertyInfo.Name; } else { strCmd += "," + propertyInfo.Name; } } strCmd = "SELECT " + strCmd + " FROM " + tablename; if (!string.IsNullOrEmpty(whereStr)) { strCmd += " WHERE " + whereStr; } cmd.CommandText = strCmd; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); if (parms != null) { foreach (var kvp in parms) { AddWithValue(cmd, kvp.Key, kvp.Value); } } using (var reader = cmd.ExecuteReader()) { if (!reader.Read()) { return 0; } GetValue(reader, Modle, propertyies); return 1; } } public static int SelectOne(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand { // 查找非空主键 var fpkpropertyies = GetNotNullProperties(modle); // 生成语句 var propertyies = GetProperties(typeof(T), fields); if (propertyies.Count == 0) { propertyies = new List(GetProperties(typeof(T)).Values); } var strCmd = string.Empty; foreach (var propertyInfo in propertyies) { if (string.IsNullOrEmpty(strCmd)) { strCmd = propertyInfo.Name; } else { strCmd += "," + propertyInfo.Name; } } strCmd = "SELECT " + strCmd + " FROM " + typeof(T).Name; strCmd += string.Format(" WHERE {0}=@{0}", fpkpropertyies[0].Name); for (int i = 1; i < fpkpropertyies.Count; i++) { strCmd += string.Format(" AND {0}=@{0}", fpkpropertyies[i].Name); } cmd.CommandText = strCmd; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); foreach (var property in fpkpropertyies) { object value = property.GetGetMethod().Invoke(modle, null); AddWithValue(cmd, "@" + property.Name, value); } using (var reader = cmd.ExecuteReader()) { if (!reader.Read()) { return 0; } GetValue(reader, modle, propertyies); return 1; } } /// /// 查找非空主键 /// /// /// /// private static IList GetNotNullProperties(T modle) { var pks = GetPKs(typeof(T)); if (pks == null || pks.Length == 0) { throw new Exception(string.Format("模型类{0}没有定义主键", typeof(T).FullName)); } IList fpkpropertyies = null; foreach (var pk in pks) { if (string.IsNullOrEmpty(pk)) { throw new Exception(string.Format("模型类{0}的主键不能为空", typeof(T).FullName)); } var withnullpk = false; var pkproperties = GetProperties(typeof(T), pk); if (pkproperties.Count == 0) { throw new Exception(string.Format("模型类{0}的主键与字段名不符", typeof(T).FullName)); } foreach (var propertyInfo in pkproperties) { var getMethod = propertyInfo.GetGetMethod(); var value = getMethod.Invoke(modle, null); if (value == null) { withnullpk = true; break; } } if (!withnullpk) { fpkpropertyies = pkproperties; break; } } if (fpkpropertyies == null) { throw new Exception("转入模型主键为空"); } return fpkpropertyies; } public static int Delete(TCommand cmd, T modle) where TCommand : DbCommand { var fpkpropertyies = GetNotNullProperties(modle); var strCmd = string.Empty; strCmd = "DELETE FROM " + typeof(T).Name; strCmd += string.Format(" WHERE {0}=@{0}", fpkpropertyies[0].Name); for (int i = 1; i < fpkpropertyies.Count; i++) { strCmd += string.Format(" AND {0}=@{0}", fpkpropertyies[i].Name); } cmd.CommandText = strCmd; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); foreach (var property in fpkpropertyies) { object value = property.GetGetMethod().Invoke(modle, null); AddWithValue(cmd, "@" + property.Name, value); } return cmd.ExecuteNonQuery(); } /// /// 异构对象插入数据库 /// public static int Insert(TCommand cmd, string tablename, Dictionary maps, T modle, string fields = "*") where TCommand : DbCommand { if (string.IsNullOrEmpty(tablename)) { tablename = typeof(T).Name; } // DONE: 处理大小写问题 var targetfields = GetTargetMaps(maps, fields); cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); string tablefields = string.Empty; string valuefields = string.Empty; foreach (var targetfield in targetfields) { if (string.IsNullOrEmpty(tablefields)) { tablefields = targetfield.Key; valuefields = "@" + targetfield.Key; } else { tablefields += "," + targetfield.Key; valuefields += ",@" + targetfield.Key; } AddWithValue(cmd, "@" + targetfield.Key, targetfield.Value.GetGetMethod().Invoke(modle, null)); } if (string.IsNullOrEmpty(tablefields)) { throw new Exception("没有一个有效插入字段"); } cmd.CommandText = string.Format("INSERT INTO {0}({1}) VALUES({2})", tablename, tablefields, valuefields); try { return cmd.ExecuteNonQuery(); } catch (Exception ex) { Trace.Write(ex.ToString()); Trace.Write(ModleToString(modle)); throw; } } public static int Insert(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand { return Insert(cmd, null, null, modle, fields); ; } private static Dictionary GetTargetMaps(IDictionary maps, string fields) { var newmaps = new Dictionary(); if (maps != null) { foreach (var map in maps) { newmaps[map.Key.Trim().ToLower()] = map.Value.Trim().ToLower(); } } var targetfields = new Dictionary(); var orgfields = GetProperties(typeof (T)); string[] arr_fields; if (fields.Equals("*")) { arr_fields = orgfields.Keys.ToArray(); } else { arr_fields = fields.Split(','); } foreach (var field in arr_fields) { var key = field.Trim().ToLower(); if (targetfields.ContainsKey(key)) { continue; } if (newmaps.ContainsKey(key) && orgfields.ContainsKey(newmaps[key])) { targetfields[key] = orgfields[newmaps[key]]; } else if (orgfields.ContainsKey(key)) { targetfields[key] = orgfields[key]; } } return targetfields; } public static int Update(TCommand cmd, string tablename, Dictionary maps, T modle, string pkfields, string fields = "*") where TCommand : DbCommand { // DONE: 处理大小写问题 var pkfields_dir = GetTargetMaps(maps, pkfields); var targetfields = GetTargetMaps(maps, fields); cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); string keyFields = string.Empty; foreach (var targetfield in pkfields_dir) { if (string.IsNullOrEmpty(keyFields)) { keyFields = string.Format("{0} = @{0}", targetfield.Key); } else { keyFields += string.Format(" AND {0} = @{0}", targetfield.Key); } AddWithValue(cmd, "@" + targetfield.Key, targetfield.Value.GetGetMethod().Invoke(modle, null)); } if (string.IsNullOrEmpty(keyFields)) { throw new Exception("没有一个有效的条件字段"); } string setFields = string.Empty; foreach (var targetfield in targetfields) { if (string.IsNullOrEmpty(setFields)) { setFields = string.Format("{0} = @{0}", targetfield.Key); } else { setFields += string.Format(", {0} = @{0}", targetfield.Key); } AddWithValue(cmd, "@" + targetfield.Key, targetfield.Value.GetGetMethod().Invoke(modle, null)); } if (string.IsNullOrEmpty(setFields)) { throw new Exception("没有一个有效更新字段"); } cmd.CommandText = string.Format("UPDATE {0} SET {1} WHERE {2}", tablename, setFields, keyFields); try { return cmd.ExecuteNonQuery(); } catch (Exception ex) { Trace.Write(ex.ToString()); Trace.Write(ModleToString(modle)); throw; } } public static int Update(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand { var pks = GetPKs(typeof(T)); if (pks == null || pks.Length == 0) { throw new Exception(string.Format("当前类{0}没有定义关键字段", typeof(T).Name)); } var pkfields = pks[0]; if (pks.Length > 0) { foreach (var pk in pks) { if (string.IsNullOrEmpty(pk)) { throw new Exception(string.Format("模型类{0}的主键不能为空", typeof(T).FullName)); } var withnullpk = false; var pkproperties = GetProperties(typeof(T), pk); if (pkproperties.Count == 0) { throw new Exception(string.Format("模型类{0}的主键与字段名不符", typeof(T).FullName)); } foreach (var propertyInfo in pkproperties) { var getMethod = propertyInfo.GetGetMethod(); var value = getMethod.Invoke(modle, null); if (value == null) { withnullpk = true; break; } } if (!withnullpk) { pkfields = pk; break; } } } return Update(cmd, typeof (T).Name, null, modle, pkfields, fields); } public static int InsertOrUpdate(TCommand cmd, T modle, string fields = "*") where TCommand : DbCommand { try { // 查找非空主键 var ifinsert = false; var pks = GetPKs(typeof(T)); if (pks == null || pks.Length == 0) { ifinsert = true; } IList fpkpropertyies = null; if (!ifinsert) { foreach (var pk in pks) { if (string.IsNullOrEmpty(pk)) { throw new Exception(string.Format("模型类{0}的主键不能为空", typeof(T).FullName)); } var withnullpk = false; var pkproperties = GetProperties(typeof(T), pk); if (pkproperties.Count == 0) { throw new Exception(string.Format("模型类{0}的主键与字段名不符", typeof(T).FullName)); } foreach (var propertyInfo in pkproperties) { var getMethod = propertyInfo.GetGetMethod(); var value = getMethod.Invoke(modle, null); if (value == null) { withnullpk = true; break; } } if (!withnullpk) { fpkpropertyies = pkproperties; break; } } if (fpkpropertyies == null) { ifinsert = true; } } List propertyies = null; if (!ifinsert) { // 按主键更新 propertyies = GetProperties(typeof(T), fields); if (propertyies.Count == 0) { propertyies = new List(GetProperties(typeof(T)).Values); } var pknames = new HashSet(); foreach (var fpk in fpkpropertyies) { pknames.Add(fpk.Name); } for (int i = propertyies.Count - 1; i >= 0; i--) { if (pknames.Contains(propertyies[i].Name)) { propertyies.RemoveAt(i); } } if (propertyies.Count == 0) { string strCmd = string.Format("SELECT COUNT(0) FROM " + typeof(T).Name + " WHERE {0}=@{0}", fpkpropertyies[0].Name); for (int i = 1; i < fpkpropertyies.Count; i++) { strCmd += string.Format(" AND {0}=@{0}", fpkpropertyies[i].Name); } cmd.CommandText = strCmd; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); foreach (var pk in fpkpropertyies) { object value = pk.GetGetMethod().Invoke(modle, null); AddWithValue(cmd, "@" + pk.Name, value); } var cnt = Convert.ToUInt32(cmd.ExecuteScalar()); if (cnt == 0) { ifinsert = true; } } else { string strCmd = string.Format("UPDATE " + typeof(T).Name + " SET {0}=@{0}", propertyies[0].Name); for (int i = 1; i < propertyies.Count; i++) { strCmd += string.Format(",{0}=@{0}", propertyies[i].Name); } strCmd += string.Format(" WHERE {0}=@{0}", fpkpropertyies[0].Name); for (int i = 1; i < fpkpropertyies.Count; i++) { strCmd += string.Format(" AND {0}=@{0}", fpkpropertyies[i].Name); } cmd.CommandText = strCmd; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); foreach (var pk in fpkpropertyies) { object value = pk.GetGetMethod().Invoke(modle, null); AddWithValue(cmd, "@" + pk.Name, value); } foreach (var field in propertyies) { object value = field.GetGetMethod().Invoke(modle, null); AddWithValue(cmd, "@" + field.Name, value); } var cnt = cmd.ExecuteNonQuery(); if (cnt == 0) { ifinsert = true; } else { return cnt; } } } if (ifinsert) { // 插入 if (propertyies == null) // 只有在无主键的情况下才会为空 { propertyies = GetProperties(typeof(T), fields); if (propertyies.Count == 0) { propertyies = new List(GetProperties(typeof(T)).Values); } } if (fpkpropertyies != null) { propertyies.AddRange(fpkpropertyies); } if (propertyies.Count == 0) { throw new Exception(string.Format("模型{0}没有字段定义", typeof(T).FullName)); } string strCmd = string.Format("INSERT INTO " + typeof(T).Name + "({0}", propertyies[0].Name); for (int i = 1; i < propertyies.Count; i++) { strCmd += string.Format(",{0}", propertyies[i].Name); } strCmd += string.Format(") VALUES(@{0}", propertyies[0].Name); for (int i = 1; i < propertyies.Count; i++) { strCmd += string.Format(",@{0}", propertyies[i].Name); } strCmd += ")"; cmd.CommandText = strCmd; cmd.CommandType = CommandType.Text; cmd.Parameters.Clear(); foreach (var field in propertyies) { object value = field.GetGetMethod().Invoke(modle, null); AddWithValue(cmd, "@" + field.Name, value); } return cmd.ExecuteNonQuery(); } return 0; } catch (Exception ex) { Trace.Write(ex.ToString()); Trace.Write(ModleToString(modle)); throw; } } private static object ModleToString(object modle) { if (modle == null) { return "{}"; } var list = GetProperties(modle.GetType()).Values; StringBuilder rslt = new StringBuilder(); rslt.Append(modle.GetType().ToString() + ":{"); bool hasone = false; foreach (var pro in list) { var getMethod = pro.GetGetMethod(); if (getMethod == null) { continue; } var value = getMethod.Invoke(modle, null); var curent = string.Format("{0}:\"{1}\"", pro.Name, value ?? "nil"); if (!hasone) { rslt.Append(curent); hasone = true; } else { rslt.Append("," + curent); } } rslt.Append("}"); return rslt.ToString(); } private static List GetProperties(Type type, string outputFields) { List rslt = new List(); Dictionary properties = GetProperties(type); string[] fields = outputFields.Split(','); foreach (string field in fields) { string key = field.Trim().ToLower(); if (properties.ContainsKey(key)) { rslt.Add(properties[key]); } } return rslt; } private static Dictionary> _typeinfoCache = new Dictionary>(); private static object _syncRoot_typeinfoCache = new object(); private static Dictionary GetProperties(Type type) { lock (_syncRoot_typeinfoCache) { if (_typeinfoCache.ContainsKey(type)) { return _typeinfoCache[type]; } PropertyInfo[] properties = type.GetProperties(); Dictionary dirProperties = new Dictionary(); foreach (PropertyInfo property in properties) { string key = property.Name.Trim().ToLower(); if (!dirProperties.ContainsKey(key)) { dirProperties[key] = property; } } _typeinfoCache[type] = dirProperties; return dirProperties; } } private static Dictionary _cmd_engines = new Dictionary(); private static object _eng_root = new object(); public static void Add(SqlEngine engine) where T : DbCommand { if (engine == null) { throw new Exception("engine参数不能为null"); } lock (_eng_root) { _cmd_engines[typeof(T)] = engine; } } private static ISqlEngine GetEngine(Type type) { lock (_eng_root) { if (!_cmd_engines.ContainsKey(type)) { throw new Exception(string.Format("{0}未关联数据库引擎", type.FullName)); } return _cmd_engines[type]; } } } }