因爲這個項目沒有使用框架,使用了sqlite數據庫。後面的業務可想而知會使用多少拼接sql,這就會至關麻煩 一旦數據庫改變 就要改不少東西。sql
因此基礎的就是封裝生成sql。須要使用反射和自定義的特性。 自定義特性在於「綁定數據庫列名」和「綁定業務格式」數據庫
1、業務一---自動生成sql
1.首先是實體對應的表:[特性--》TableNameAttr]
using System;
using System.Collections.Generic;
using System.Text;框架
namespace PublicLibrary.attr
{函數
//數據庫表名 [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class TableNameAttr: Attribute{ string value; public TableNameAttr(string value) { this.Value = value; } public string Value { get => value; set => this.value = value; } }
}
2.其次是實體字段對應的列名:[特性--》TableFieldAttr]
using System;工具
namespace PublicLibrary.attr
{ui
//查詢 新增 修改的註解 [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)] public class TableFieldAttr:Attribute { //bool是boolean 的類型 //是否存在的字段==> 針對查詢 private bool isExist =true; //數據庫列名 private string columName; //字符串類型 private string jdbcType; //默認值 private string value;
/* //新增 修改 選着性操做的字段this
private bool selective;*/ //須要自定義的數據庫函數 private bool definedFunc; //是否主鍵 private bool primaryKey =false; //函數的表達式 private string patternStr; //是否更新 默認爲true private bool isUpdate =true; public TableFieldAttr(string columName) { this.ColumName = columName; } //字段數據庫不存在 public TableFieldAttr(bool isExist) { this.IsExist = false; } //行數據列名 默認值 public TableFieldAttr(string columName, string value) { this.ColumName = columName; this.Value = value; } public TableFieldAttr(string columName, string value, string jdbcType,bool definedFunc, bool primaryKey, string patternStr) { this.ColumName = columName; this.DefinedFunc = definedFunc; this.JdbcType = jdbcType; this.DefinedFunc = definedFunc; this.PrimaryKey = primaryKey; this.PatternStr = patternStr; this.Value = value; } public TableFieldAttr(string columName, string value, string jdbcType,bool definedFunc, bool primaryKey, string patternStr,bool isUpdate) { this.ColumName = columName; this.DefinedFunc = definedFunc; this.JdbcType = jdbcType; this.DefinedFunc = definedFunc; this.PrimaryKey = primaryKey; this.PatternStr = patternStr; this.Value = value; this.IsUpdate = isUpdate; } public bool IsExist { get => isExist; set => isExist = value; } public string ColumName { get => columName; set => columName = value; } public string JdbcType { get => jdbcType; set => jdbcType = value; } public string Value { get => value; set => this.value = value; } public bool DefinedFunc { get => definedFunc; set => definedFunc = value; } public bool PrimaryKey { get => primaryKey; set => primaryKey = value; } public string PatternStr { get => patternStr; set => patternStr = value; } public bool IsUpdate { get => isUpdate; set => isUpdate = value; } }
}
3.再就是建立sql的公共方法:
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using PublicLibrary.attr;
using PublicLibrary.serivce;
using PublicLibrary.serivce.impl;spa
namespace PublicLibrary
{excel
public static class SQLiteSqlUtils { /// <summary> /// 建立 查詢語句 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t">對象</param> /// <param name="whereColums">查詢出的字段,如[id,name]</param> /// <returns></returns> public static string CreateSelectSql<T>(T t,string[] whereColums) { Type type = typeof(T); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; var startTime = DateTime.Now; TableNameAttr tableAttr = type.GetCustomAttribute<TableNameAttr>(); string tableName = tableAttr != null ? tableAttr.Value : ""; string sqlTemp = "SELECT #{colums} FROM " + tableName + " WHERE 1=1 #{whereColums}"; Dictionary<string, TableFieldAttr> fieldAttrDic = new Dictionary<string, TableFieldAttr>(); StringBuilder colums = new StringBuilder(); StringBuilder whereColumsTem = new StringBuilder(""); FieldInfo[] fieldInfos = type.GetFields(bindingFlags); PropertyInfo propertyInfo = null; int countFlag = 0; IEnumerable<TableFieldAttr> enumerable = null; for (int i = 0; i < fieldInfos.Length; i++) { enumerable = fieldInfos[i].GetCustomAttributes<TableFieldAttr>(); foreach (TableFieldAttr attr in enumerable){ //不是主鍵 和是數據庫字段 if (attr.IsExist) { fieldAttrDic.Add(fieldInfos[i].Name, attr); colums.Append((countFlag == 0 ? "" : ",") + attr.ColumName); countFlag++; } } } countFlag = 0; TableFieldAttr fieldAttr = null; if (whereColums != null) { for (int k = 0; k < whereColums.Length; k++) { propertyInfo = type.GetProperty(UpperCaseFirst(whereColums[k]), bindingFlags); if (propertyInfo != null) { fieldAttr = fieldAttrDic[whereColums[k]]; whereColumsTem.Append(" and " + (fieldAttr == null ? "NoField" : fieldAttr.ColumName) + "='" + propertyInfo.GetValue(t) + "'"); /*whereColumsTem.Append((countFlag == 0 ? " " : " and ") + tableName + "." + (fieldAttr == null ? "NoField" : fieldAttr.ColumName) + "='" + propertyInfo.GetValue(t) + "'"); countFlag++;*/ } } } string selectSql = sqlTemp.Replace("#{colums}", colums.ToString()).Replace("#{whereColums}", whereColumsTem.ToString()); return selectSql; } /// <summary> /// 建立 刪除語句 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t">對象</param> /// <param name="whereColums">查詢出的字段,如[id,name]</param> /// <returns></returns> public static string CreateDeleteSql<T>(T t, string[] whereColums) { Dictionary<string, TableFieldAttr> fieldAttrDic = new Dictionary<string, TableFieldAttr>(); Type type = typeof(T); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; var startTime = DateTime.Now; TableNameAttr tableAttr = type.GetCustomAttribute<TableNameAttr>(); string tableName = tableAttr != null ? tableAttr.Value : ""; string sqlTemp = "DELETE FROM " + tableName + " WHERE 1=1 #{whereColums}"; StringBuilder whereColumsTem = new StringBuilder(""); FieldInfo[] fieldInfos = type.GetFields(bindingFlags); PropertyInfo propertyInfo = null; IEnumerable<TableFieldAttr> enumerable = null; int countFlag = 0; for (int i = 0; i < fieldInfos.Length; i++){ enumerable = fieldInfos[i].GetCustomAttributes<TableFieldAttr>(); foreach (TableFieldAttr attr in enumerable){ //不是主鍵 和是數據庫字段 if (attr.IsExist){ fieldAttrDic.Add(fieldInfos[i].Name, attr); } } } TableFieldAttr fieldAttr = null; if (whereColums != null) { for (int k = 0; k < whereColums.Length; k++) { propertyInfo = type.GetProperty(UpperCaseFirst(whereColums[k]), bindingFlags); if (propertyInfo != null) { fieldAttr = fieldAttrDic[whereColums[k]]; whereColumsTem.Append(" and " + (fieldAttr == null ? "NoField" : fieldAttr.ColumName) + "='" + propertyInfo.GetValue(t) + "'"); } } } string deleteSql = sqlTemp.Replace("#{whereColums}", whereColumsTem.ToString()); return deleteSql; } public static string CreateInsertSql<T>(T t){ List<T> list = new List<T>(); list.Add(t); return CreateInsertSql<T>( list, new ColumServiceImpl()); } public static string CreateInsertSql<T>(T t, ColumService columService){ List<T> list = new List<T>(); list.Add(t); return CreateInsertSql<T>(list, columService); } public static string CreateInsertSql<T>( List<T> list) { return CreateInsertSql<T>(list, new ColumServiceImpl()); } //新增 批量新增的sql public static string CreateInsertSql<T>(List<T> list,ColumService columService) { Type type = typeof(T); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; var startTime = DateTime.Now; TableNameAttr tableAttr = type.GetCustomAttribute<TableNameAttr>(); string tableName = tableAttr != null ? tableAttr.Value : ""; string insertHead = "INSERT INTO " + tableName + "(#{colums}) VALUES\n"; string valuesTemp = "(#{values})"; FieldInfo[] fieldInfos = type.GetFields(bindingFlags); Dictionary<string, TableFieldAttr> table = new Dictionary<string, TableFieldAttr>(); Dictionary<string, PropertyInfo> tablePropertys = new Dictionary<string, PropertyInfo>(); //string iteminfo = ""; PropertyInfo propertyinfo = null; TableFieldAttr tableFieldAttr = null; IEnumerable<TableFieldAttr> enumerable = null; string columsTemplet = ""; string valuesTemplet = ""; for (int i = 0; i < fieldInfos.Length; i++) { tablePropertys.Add(fieldInfos[i].Name, type.GetProperty(UpperCaseFirst(fieldInfos[i].Name), bindingFlags)); enumerable = fieldInfos[i].GetCustomAttributes<TableFieldAttr>(); foreach (TableFieldAttr attr in enumerable) { table.Add(fieldInfos[i].Name, attr); attr.JdbcType = fieldInfos[i].FieldType.ToString(); //不是主鍵 和是數據庫字段 if (attr.IsExist) { columsTemplet += " " + attr.ColumName + " ,"; valuesTemplet += " #{" + fieldInfos[i].Name + "} ,"; } } } insertHead = insertHead.Replace("#{colums}", columsTemplet.Substring(0, columsTemplet.Length - 1)); valuesTemp = valuesTemp.Replace("#{values}", valuesTemplet.Substring(0, valuesTemplet.Length - 1)); string valuesInfo = ""; string setValue = ""; for (int k = 0; k < list.Count; k++) { object value = ""; string currentValue = ""; string rowInfo = valuesTemp; //rowInfo = ; foreach (string key in table.Keys) { propertyinfo = tablePropertys[key]; tableFieldAttr = table[key]; //默認值 不進行函數轉換 if (tableFieldAttr.Value != null) { value = tableFieldAttr.Value; currentValue = value.ToString(); setValue = currentValue; } else if (propertyinfo != null) { value = tablePropertys[key].GetValue(list[k], null); currentValue = (value == null) ? "''" : "'" + value.ToString() + "'"; setValue = tableFieldAttr.DefinedFunc ? columService.DoFormat(key, currentValue, tableFieldAttr.PatternStr) : currentValue; } rowInfo = rowInfo.Replace("#{" + key + "}", setValue); } valuesInfo += rowInfo + ","; } var endTime = DateTime.Now; TimeSpan ts = endTime.Subtract(startTime); Console.WriteLine("insert語句生成耗時{0}ms.", ts.TotalMilliseconds); return insertHead + valuesInfo.Substring(0, valuesInfo.Length - 1); } /// <summary> /// 單條數據更新 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <param name="whereColums"></param> /// <returns></returns> public static string CreateUpdateSql<T>(T t, string[] whereColums) { List<T> list = new List<T>(); list.Add(t); return CreateUpdateSql<T>(list, whereColums, new ColumServiceImpl()); } /// <summary> /// 更新的語句 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="t"></param> /// <param name="whereColums">whereColums 必填 參考 新增和修改【id,name】</param> /// <param name="columService"></param> /// <returns></returns> public static string CreateUpdateSql<T>(T t, string[] whereColums, ColumService columService){ List<T> list = new List<T>(); list.Add(t); return CreateUpdateSql<T>( list, whereColums, columService); } /// <summary> /// 多條數據更新 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="list"></param> /// <param name="whereColums"></param> /// <returns></returns> public static string CreateUpdateSql<T>(List<T> list, string[] whereColums) { return CreateUpdateSql<T>(list, whereColums, new ColumServiceImpl()); } /// <summary> /// 修改 批量修改的sql 主語法 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="list"></param> /// <param name="whereColums"></param> /// <param name="columService"></param> /// <returns></returns> public static string CreateUpdateSql<T>(List<T> list, string[] whereColums, ColumService columService) { StringBuilder whereColumsTem = new StringBuilder(""); List<string> whereColumTs = new List<string>(); if (whereColums != null) { whereColumTs = new List<string>(whereColums); } var startTime = DateTime.Now; BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; Type type = typeof(T); TableNameAttr tableAttr = type.GetCustomAttribute<TableNameAttr>(); string tableName = tableAttr != null ? tableAttr.Value : ""; string updateSql = ""; string updateHead = "UPDATE " + tableName + " #{colums} "; FieldInfo[] fieldInfos = type.GetFields(bindingFlags); Dictionary<string, TableFieldAttr> table = new Dictionary<string, TableFieldAttr>(); Dictionary<string, PropertyInfo> tablePropertys = new Dictionary<string, PropertyInfo>(); PropertyInfo propertyinfo = null; TableFieldAttr tableFieldAttr = null; IEnumerable<TableFieldAttr> enumerable = null; string setTemplet = ""; for (int i = 0; i < fieldInfos.Length; i++) { tablePropertys.Add(fieldInfos[i].Name, type.GetProperty(UpperCaseFirst(fieldInfos[i].Name), bindingFlags)); enumerable = fieldInfos[i].GetCustomAttributes<TableFieldAttr>(); foreach (TableFieldAttr attr in enumerable) { table.Add(fieldInfos[i].Name, attr); attr.JdbcType = fieldInfos[i].FieldType.ToString(); //不是主鍵 和是數據庫字段 if (attr.IsExist && !attr.PrimaryKey && attr.IsUpdate) { setTemplet += " " + attr.ColumName + "= #{" + fieldInfos[i].Name + "} ,"; } //匹配 if (whereColumTs.Contains(fieldInfos[i].Name)) { whereColumsTem.Append(" AND " + attr.ColumName + " = #{"+ fieldInfos[i].Name + "}"); } } } setTemplet = "set " + setTemplet.Substring(0, setTemplet.Length - 1); if (whereColumTs.Count>0){ setTemplet += " WHERE 1=1 " + whereColumsTem.ToString(); } //updateHead += setTemplet; string colum = ""; object value = ""; string currentValue = ""; for (int k = 0; k < list.Count; k++) { colum = setTemplet; foreach (string key in table.Keys){ propertyinfo = tablePropertys[key]; tableFieldAttr = table[key]; if (tableFieldAttr.Value != null) { value = tableFieldAttr.Value; //默認值不作函數處理 currentValue = value.ToString(); } else if (propertyinfo != null){ value = tablePropertys[key].GetValue(list[k], null); currentValue = (value == null) ? "''" : "'" + value.ToString() + "'"; //實際值纔會作函數處理 currentValue = tableFieldAttr.DefinedFunc ? columService.DoFormat(key, currentValue, tableFieldAttr.PatternStr) : currentValue; } else{ currentValue = "''"; } colum = colum.Replace("#{" + key + "}", currentValue); } updateSql += updateHead.Replace("#{colums}", colum) + "\n;"; } updateSql = updateSql.Substring(0, updateSql.Length - 1); var endTime = DateTime.Now; TimeSpan ts = endTime.Subtract(startTime); Console.WriteLine("update語句生成耗時{0}ms.", ts.TotalMilliseconds); return updateSql; } /// <summary> /// 首字母大寫 /// </summary> /// <param name="str"></param> /// <returns></returns> public static string UpperCaseFirst(this string str) { if (string.IsNullOrWhiteSpace(str)) return string.Empty; char[] s = str.ToCharArray(); char c = s[0]; if ('a' <= c && c <= 'z') c = (char)(c & ~0x20); s[0] = c; return new string(s); } }
}code
實際使用
針對實體:
方法調用示例:
List<OsZbSupplierProductInfo> record =new List<OsZbSupplierProductInfo>();
SQLiteSqlUtils.CreateInsertSql(record)
業務2.針對導入excel
如法炮製 須要什麼?須要列的下標 列內容非空驗證 重複性驗證 格式驗證 長度驗證
1.自定義特效
using System;
namespace PublicLibrary.attr
{
//導入的註解【特徵值/註解】 [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)] public class ColumnInfoAttr:Attribute{ //位置 int index = -1; // 長度 int length = 32; // 是否爲空 bool nullable = false; // 時間格式 string dateFormat = ""; //正則表單式 驗證數據格式 string pattern = ""; public ColumnInfoAttr(int index, int length){ this.index = index; this.length = length; } public ColumnInfoAttr(int index, int length, bool nullable) { this.index = index; this.length = length; this.nullable = nullable; } public ColumnInfoAttr(int index, int length, bool nullable,string dateFormat) { this.index = index; this.length = length; this.nullable = nullable; this.dateFormat = dateFormat; } public ColumnInfoAttr(int index, int length, bool nullable, string dateFormat, string pattern) { this.index = index; this.length = length; this.nullable = nullable; this.dateFormat = dateFormat; this.Pattern = pattern; } public int Index { get => index; set => index = value; } public int Length { get => length; set => length = value; } public bool Nullable { get => nullable; set => nullable = value; } public string DateFormat { get => dateFormat; set => dateFormat = value; } public string Pattern { get => pattern; set => pattern = value; } }
}
2.公共方法【注此部分沒有校驗重複性】
using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Forms;
using ess_zbfz_main.dto;
using ExcelDataReader;
using PublicLibrary;
using PublicLibrary.attr;
namespace ess_zbfz_main.util
{
//導入工具類 public class ExcelUtil { //, Dictionary<string, string> dbListDict, string[] keys public static MessageInfo<T> ReadExcel<T>(int firstIndex){ MessageInfo<T> messageInfo = new MessageInfo<T>(); FileStream fileStream =null; IExcelDataReader reader = null; DataSet result = null; try { //小於0 默認是第三行開始讀取 firstIndex = firstIndex < 0 ? 2 : firstIndex; OpenFileDialog fileImportDialog = new OpenFileDialog(); fileImportDialog.Filter = "導入文件包(*.xlsx)|*.xlsx";//擴展名 fileImportDialog.FileName = ""; if (fileImportDialog.ShowDialog() == DialogResult.OK) { string saveTempPath = @System.AppDomain.CurrentDomain.BaseDirectory + "data\\receiveData\\";//臨時存放的路徑 /* if (!File.Exists(saveTempPath)) { File.Create(saveTempPath); }*/ string saveName = fileImportDialog.FileName.Substring(fileImportDialog.FileName.LastIndexOf("\\") + 1); string dataPath = saveTempPath + saveName;//文件地址 File.Copy(fileImportDialog.FileNames[0], dataPath, true); //解析處理 start //stream = fileStream = File.Open(fileImportDialog.FileName, FileMode.Open, FileAccess.Read); reader = ExcelReaderFactory.CreateReader(fileStream); object[] curObject = new object[10]; result = reader.AsDataSet(new ExcelDataSetConfiguration() { ConfigureDataTable = (_) => new ExcelDataTableConfiguration() { UseHeaderRow = true, ReadHeaderRow = (rowReader) => { // 從第幾行以後開始讀取 int index = firstIndex; if (index != rowReader.Depth) { rowReader.Read(); } } } }); DataTableCollection tableCollection = result.Tables; //初步處理的數據 messageInfo = GetmessageInfo<T>(tableCollection[0], firstIndex); //reader.Close(); return messageInfo; } } catch(Exception ex) { Console.WriteLine(ex.Message); MessageBox.Show("導入文件錯誤信息:" + ex.Message); } finally{ //須要釋放資源 if (reader != null) { reader.Close(); } if (fileStream != null) { fileStream.Close(); } if (result != null) { result.Clear(); } } return messageInfo; } public static MessageInfo<T> GetmessageInfo<T>(DataTable dt, int firstIndex) { MessageInfo<T> messageInfo = new MessageInfo<T>(); bool existError = false; int totalCount = dt.Rows.Count; int successCount = 0; //錯誤信息 StringBuilder errorSb = new StringBuilder(); BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; var list = new List<T>(); Type type = typeof(T); ColumnInfoAttr columnInfoAttr = null; FieldInfo[] fieldInfos = type.GetFields(bindingFlags); Dictionary<int, PropertyInfo> dictionAry = new Dictionary<int, PropertyInfo>(); Dictionary<int, ColumnInfoAttr> columnDic = new Dictionary<int, ColumnInfoAttr>(); //行屬性 //PropertyInfo propertyInfo = type.GetProperty("CurExcelIndex"); for (int p = 0; p < fieldInfos.Length; p++) { columnInfoAttr = fieldInfos[p].GetCustomAttribute<ColumnInfoAttr>(); if (columnInfoAttr != null) { dictionAry.Add(columnInfoAttr.Index, type.GetProperty(SQLiteSqlUtils.UpperCaseFirst(fieldInfos[p].Name))); columnDic.Add(columnInfoAttr.Index, columnInfoAttr); } } PropertyInfo currentProp = null; //實體 T s; bool flag = false; int currentRow = firstIndex; foreach (DataRow item in dt.Rows){ currentRow++; s = Activator.CreateInstance<T>(); for (int i = 0; i < dt.Columns.Count; i++) { if (dictionAry.ContainsKey(i)){ currentProp = dictionAry[i]; columnInfoAttr = columnDic[i]; object v = null; if (currentProp.PropertyType.ToString().Contains("System.Nullable")) { v = Convert.ChangeType(item[i], Nullable.GetUnderlyingType(currentProp.PropertyType)); } else{ v = Convert.ChangeType(item[i], currentProp.PropertyType); } //不能夠爲空==> 非空驗證 if (!columnInfoAttr.Nullable && (v == null || v.ToString().Trim().Length<=0)) { //successCount++; existError = true; errorSb.Append("第" + currentRow + "行," + dt.Columns[i].ColumnName + " 數據不得爲空\n"); flag = true; //break; } //不爲空 超過了最大長度==> 長度驗證 if (v != null && columnInfoAttr.Length < v.ToString().Length) { //successCount++; existError = true; errorSb.Append("第" + currentRow + "行," + dt.Columns[i].ColumnName + " 數據長度不得超過" + columnInfoAttr.Length + "個字符\n"); flag = true; //break; } //正則驗證部分==> 數據格式驗證 if (v != null && columnInfoAttr.Pattern!=null && columnInfoAttr.Pattern != "" && v.ToString().Trim().Length > 0){ //不匹配正則 if(!Regex.IsMatch(v.ToString().Trim(), columnInfoAttr.Pattern)) { existError = true; errorSb.Append("第" + currentRow + "行," + dt.Columns[i].ColumnName + " 數據格式不正確"); flag = true; } } //是否校驗不合格 if (flag) { flag = false; successCount++; break; } currentProp.SetValue(s, v, null); } } currentProp = dictionAry[-10]; currentProp.SetValue(s, currentRow, null);//設置excel的行列 currentProp = null; list.Add(s); } //返回的信息 messageInfo.Record = list; messageInfo.ErrorInfo = errorSb.ToString(); messageInfo.TotalCount = totalCount; messageInfo.ErrorCount = totalCount - successCount; messageInfo.SuccessCount = successCount; messageInfo.ExistError = existError; return messageInfo; } }
}
3.具體的使用
實體:
方法調用:
int firstIndex = 2; MessageInfo<OsZbSupplierProductInfo> messageInfo = ExcelUtil.ReadExcel<OsZbSupplierProductInfo>(firstIndex);
本文來源於:宋文超super,專屬平臺有csdn、思否(SegmentFault)、 簡書、 開源中國(oschina),轉載請註明出處。