一,基本思路:利用C#的標簽和反射功能實現自定義輕量級ORM 標簽Attribute附著在實體屬性或實體類名上,這樣可以取到實體對應的表名,屬性對應的表欄位名,數據類型,是否主鍵,欄位註釋等基本信息 反射實現對實體動態賦值取值。 二,比較重要的類 1、ISqlHelper:介面,定義數據操作的基本方 ...
一,基本思路:利用C#的標簽和反射功能實現自定義輕量級ORM
標簽Attribute附著在實體屬性或實體類名上,這樣可以取到實體對應的表名,屬性對應的表欄位名,數據類型,是否主鍵,欄位註釋等基本信息
反射實現對實體動態賦值取值。
二,比較重要的類
1、ISqlHelper:介面,定義數據操作的基本方法,增刪改查,事務。
SqlHelper:實現了ISqlHelper介面,將數據操作基本方法實現,不同資料庫oracle,db2,sqlserver需要的參數類型不同,將這些不確定的信息以抽象方法的形式開出來在一層設置。 抽象類,定義了GetPasType抽象方法(不同資料庫命令參數類不一樣,如oracle用OracleParameter類型,sqlserver用SqlParameter類型,用這個方法取參數類信息),GetCmdType抽象方法(如Oracle用OracleCommand類型,sqlserver用SqlCommand類型);GetPageSql抽象方法(不同資料庫查詢分頁sql語句寫法不一樣,因此分頁方法在下一層實現),SetPasChar抽象方法(不同資料庫參數符號不一樣,oracel用':',sqlserver用'@')
DB2SqlHelper,MSSQLSqlHelper,OracleSqlHelper都繼承自SqlHelper,實現常用資料庫的基本操作方法。
2、ColumnAttribute:繼承自Attribute,實體類屬性標簽,有4個屬性(欄位名,欄位說明,數據類型,是否主鍵);TableAttribute繼承自Attribute,實體名標簽,記錄實體對應的表名和表註釋。
3、MyBaseClass:實體類的基類,包含了一些基本數據操作,實體里如果有int,double,datetime等類型都要設置為可空類型(因為是基礎類型的話都有預設值,這樣在增改查的時候就不清楚究竟是預設值還是程式員傳入的參數值,用可空類型就能區分)
SetHelper方法:設置資料庫基本信息,如連接字元串,資料庫類型。參數為ISqlHelper。
Insert方法:將實體對應數據插入資料庫
InsertCmd方法:返回插入資料庫的命令
DeleteByPk方法:通過主鍵刪除數據,主鍵對應屬性必須有值,沒有值操作失敗
DeleteCmdByPk方法:返回通過主鍵刪除數據的命令
UpdateByPk方法:通過主鍵更新數據,主鍵對應屬性必須有值,沒有值操作失敗
UpdateCmdByPk方法:返回通過主鍵更新數據的命令
Select方法:查詢數據,返回DataTable,重載方法返回對象集合List<T>,查詢參數就是本實體里屬性值不為null的所有屬性
4、MyDbHelper:包含數據操作常用方法,基本功能與MyBaseClass差不多。
Select方法:查詢數據,參數為實體,返回實體集合
GetEntityFromTable方法:把datable里的數據轉換成實體集合,參數為datatable,返回值List<T>
Update方法:更新數據,更新條件和更新值都是實體
Delete方法:刪除數據,以實體屬性值為條件刪除
5、EntityHelper:用於創建實體,保存為實體類的cs文件或返回實體類的字元串
三、代碼
public interface ISqlHelper
{
/// <summary>
/// 執行查詢操作
/// </summary>
DataTable Select(string sql, List<DbParameter> pas);
/// <summary>
/// 執行查詢操作
/// </summary>
DataTable Select(string sql);
/// <summary>
/// 執行新增,修改,刪除操作
/// </summary>
int ExeNoQuery(string sql, List<DbParameter> pas);
/// <summary>
/// 執行新增,修改,刪除操作
/// </summary>
int ExeNoQuery(string sql);
/// <summary>
/// 執行事務,sql,參數各不相同
/// </summary>
bool ExeTrans(Dictionary<string, List<DbParameter>> dic, out string errMsg);
/// <summary>
/// 執行事務,相同的sql,參數不同
/// </summary>
bool ExeTrans(string sql, List<List<DbParameter>> pass, out string errMsg);
/// <summary>
/// 執行事務
/// </summary>
bool ExeTrans(List<DbCommand> cmds, out string errMsg);
/// <summary>
/// 設置SQL參數形式如:MSSQL的‘@’,DB2‘@’,ORACLE‘:’
/// </summary>
string SetPasChar();
/// <summary>
/// 根據表名,欄位(如C1,C2,C3),where條件(如A='a' AND B= 'b'),起止行號得到不同區間數據
/// </summary>
DataTable GetPageTable(string tableName, string fields, string where, int fromIndex, int toIndex);
/// <summary>
/// 根據表名,where條件得到總行數
/// </summary>
int GetCountLines(string tableName, string where);
/// <summary>
/// 得到參數實例,因為不同資料庫參數類型不一樣
/// </summary>
Type GetPasType();
/// <summary>
/// 得到命令類型,因為不同資料庫命令類型不一樣
/// </summary>
Type GetCmdType();
}
public abstract class SqlHelper : ISqlHelper
{
protected string connStr = "";
protected DbConnection conn = null;
protected DbCommand cmd = null;
protected DbDataAdapter adapter = null;
public SqlHelper(string connStr)
{
this.connStr = connStr;
}
/// <summary>
/// 查詢數據
/// </summary>
public DataTable Select(string sql, List<DbParameter> pas)
{
DataTable dt = new DataTable();
try
{
InitDataEnviroment();
conn.Open();
if (conn.State == ConnectionState.Open)
{
cmd.Connection = conn;
cmd.CommandText = sql;
//添加參數
if (pas != null)
{
foreach (DbParameter pa in pas)
{
cmd.Parameters.Add(pa);
}
}
adapter.SelectCommand = cmd;
adapter.Fill(dt);
}
return dt;
}
catch (Exception ex)
{
return null;
}
finally
{
DisposeDataEnviroment();
}
}
/// <summary>
/// 查詢數據
/// </summary>
public DataTable Select(string sql)
{
DataTable dt = new DataTable();
try
{
InitDataEnviroment();
conn.Open();
if (conn.State == ConnectionState.Open)
{
cmd.Connection = conn;
cmd.CommandText = sql;
adapter.SelectCommand = cmd;
adapter.Fill(dt);
}
return dt;
}
catch (Exception ex)
{
return null;
}
finally
{
DisposeDataEnviroment();
}
}
/// <summary>
/// 執行新增,修改,刪除操作
/// </summary>
public int ExeNoQuery(string sql, List<DbParameter> pas)
{
int cols = 0;
try
{
InitDataEnviroment();
conn.Open();
if (conn.State == ConnectionState.Open)
{
cmd.Connection = conn;
cmd.CommandText = sql;
//添加參數
if (pas != null)
{
foreach (DbParameter pa in pas)
{
cmd.Parameters.Add(pa);
}
}
cols = cmd.ExecuteNonQuery();
}
return cols;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return 0;
}
finally
{
DisposeDataEnviroment();
}
}
/// <summary>
/// 執行新增,修改,刪除操作
/// </summary>
public int ExeNoQuery(string sql)
{
int cols = 0;
try
{
InitDataEnviroment();
conn.Open();
if (conn.State == ConnectionState.Open)
{
cmd.Connection = conn;
cmd.CommandText = sql;
cols = cmd.ExecuteNonQuery();
}
return cols;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return 0;
}
finally
{
DisposeDataEnviroment();
}
}
/// <summary>
/// 執行事務
/// </summary>
public bool ExeTrans(Dictionary<string, List<DbParameter>> dic, out string errMsg)
{
if (dic != null)
{
errMsg = "";
try
{
InitConnection();
InitCommand();
conn.Open();
if (conn.State == ConnectionState.Open)
{
cmd.Connection = conn;
using (IDbTransaction trans = conn.BeginTransaction())
{
//這一層try.catch防止有命令執行錯誤而用來回滾
try
{
foreach (KeyValuePair<string, List<DbParameter>> kv in dic)
{
cmd.CommandText = kv.Key;
foreach (DbParameter pa in kv.Value)
{
cmd.Parameters.Add(pa);
}
int cols = cmd.ExecuteNonQuery();
//清空參數,避免下一次執行時干擾
cmd.Parameters.Clear();
}
trans.Commit();
}
catch (Exception ep)
{
errMsg = ep.Message;
trans.Rollback();
return false;
}
}
}
return true;
}
catch (Exception ex)
{
errMsg = ex.Message;
return false;
}
finally
{
DisposeDataEnviroment();
}
}
else
{
errMsg = "sql及參數為null";
return false;
}
}
/// <summary>
/// 執行事務
/// </summary>
public bool ExeTrans(string sql, List<List<DbParameter>> pass, out string errMsg)
{
if (pass != null && (!string.IsNullOrEmpty(sql)))
{
errMsg = "";
try
{
InitConnection();
InitCommand();
conn.Open();
if (conn.State == ConnectionState.Open)
{
cmd.Connection = conn;
using (DbTransaction trans = conn.BeginTransaction())
{
//這一層try.catch防止有命令執行錯誤而用來回滾
try
{
cmd.Transaction = trans;
foreach (List<DbParameter> pas in pass)
{
cmd.CommandText = sql;
foreach (DbParameter pa in pas)
{
cmd.Parameters.Add(pa);
}
int cols = cmd.ExecuteNonQuery();
//清空參數,避免下一次執行時干擾
cmd.Parameters.Clear();
}
trans.Commit();
}
catch (Exception ep)
{
errMsg = ep.Message;
trans.Rollback();
return false;
}
}
}
return true;
}
catch (Exception ex)
{
errMsg = ex.Message;
return false;
}
finally
{
DisposeDataEnviroment();
}
}
else
{
errMsg = "sql及參數為null";
return false;
}
}
/// <summary>
/// 執行事務
/// </summary>
public bool ExeTrans(List<DbCommand> cmds, out string errMsg)
{
errMsg = "";
try
{
InitConnection();
InitCommand();
conn.Open();
if (conn.State == ConnectionState.Open)
{
using (DbTransaction trans = conn.BeginTransaction())
{
try
{
foreach (DbCommand dbcmd in cmds)
{
dbcmd.Connection = conn;
dbcmd.Transaction = trans;
dbcmd.ExecuteNonQuery();
dbcmd.Dispose();
}
trans.Commit();
}
catch (Exception ep)
{
errMsg = ep.Message;
trans.Rollback();
return false;
}
}
}
return true;
}
catch (Exception ex)
{
errMsg = ex.Message;
return false;
}
finally
{
DisposeDataEnviroment();
}
}
/// <summary>
/// 初始化連接,命令,適配器
/// </summary>
protected abstract void InitDataEnviroment();
protected abstract void InitConnection();
private void InitCommand()
{
cmd = Activator.CreateInstance(GetCmdType()) as DbCommand;
}
/// <summary>
/// 關閉連接,釋放資源
/// </summary>
private void DisposeDataEnviroment()
{
if (conn != null)
{
if (!conn.State.Equals(ConnectionState.Closed))
{
conn.Close();
}
conn.Dispose();
}
if (cmd != null) cmd.Dispose();
if (adapter != null) adapter.Dispose();
}
/// <summary>
/// 設置SQL參數形式如:MSSQL的‘@’,DBA2‘@’,ORACLE‘:’
/// </summary>
protected abstract string SetPas();
/// <summary>
/// 實現ISqlHelper介面的參數方法
/// </summary>
public string SetPasChar()
{
return SetPas();
}
/// <summary>
/// 根據表名,欄位(如C1,C2,C3),where條件(如A='a' AND B= 'b'),起止行號得到不同區間數據
/// </summary>
public DataTable GetPageTable(string tableName, string fields, string where, int fromIndex, int toIndex)
{
//判斷表名,欄位是否為空
if (string.IsNullOrEmpty(tableName) || string.IsNullOrEmpty(fields))
{
return null;
}
//拼接where條件
if (!string.IsNullOrEmpty(where))
{
where = string.Format(" WHERE {0}", where);
}
return Select(GetPageSql(tableName, fields, where, fromIndex, toIndex), null);
}
/// <summary>
/// 分頁語句需要的函數row_number不同,在下一層實現
/// </summary>
protected abstract string GetPageSql(string tableName, string fields, string where, int fromIndex, int toIndex);
/// <summary>
/// 根據表名,where條件(如A='a' AND B = 'b')得到總行數
/// </summary>
public int GetCountLines(string tableName, string where)
{
if (!string.IsNullOrEmpty(where))
{
where = string.Format(" WHERE {0}", where);
}
string sql = string.Format("SELECT COUNT(1) FROM {0} {1}", tableName, where);
int cols = 0;
DataTable dt = this.Select(sql, null);
if (dt != null && dt.Rows.Count > 0)
{
cols = int.Parse(dt.Rows[0][0].ToString());
}
return cols;
}
public abstract Type GetPasType();
public abstract Type GetCmdType();
}
public class OracleSqlHelper : SqlHelper
{
public OracleSqlHelper(string connStr)
: base(connStr)
{
}
protected override void InitDataEnviroment()
{
conn = new OracleConnection();
conn.ConnectionString = connStr;
cmd = new OracleCommand();
adapter = new OracleDataAdapter();
}
protected override void InitConnection()
{
conn = new OracleConnection();
conn.ConnectionString = connStr;
}
protected override string SetPas()
{
return ":";
}
/// <summary>
/// 根據表名,欄位(C1,C2,C3的形式),where條件,起止行號得到不同區間數據的SQL語句
/// </summary>
protected override string GetPageSql(string tableName, string fields, string where, int fromIndex, int toIndex)
{
string sql = string.Format("SELECT * FROM (SELECT ROWNUM RN,{0} FROM {1} {2}) WHERE RN>={3} AND RN<={4}", fields, tableName, where, fromIndex, toIndex);
return sql;
}
public override Type GetPasType()
{
return typeof(OracleParameter);
}
public override Type GetCmdType()
{
return typeof(OracleCommand);
}
}
/// <summary>
/// 反射和標記實現ORM,insert,update,delete,select
/// </summary>
public class MyBaseClass
{
private ISqlHelper _helper = null; //操作數據的處理函數
/// <summary>
/// 插入一條記錄,需要先調用SetHelper設置資料庫操作函數
/// </summary>
public int Insert()
{
int cols = 0;
string fields = GetFields();
if (_helper != null)
{
//sql參數形式 MSSQL@,DB2@,ORACLE:
string paschar = _helper.SetPasChar();
//拼接insert腳本
string sql = string.Format("INSERT INTO {0}({1}) VALUES({2})", GetTableName(), fields, paschar + fields.Replace(",", "," + paschar));
List<DbParameter> pas = new List<DbParameter>();
List<ColumnNameValueRelation> lst = GetColumns(false);
foreach (ColumnNameValueRelation cv in lst)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name;
para.Value = cv.Value;
pas.Add(para);
}
cols = _helper.ExeNoQuery(sql, pas);
}
return cols;
}
/// <summary>
/// 插入記錄命令,需要先調用SetHelper設置資料庫操作函數
/// </summary>
public DbCommand InsertCmd()
{
DbCommand cmd = null;
string fields = GetFields();
if (_helper != null)
{
cmd = (DbCommand)Activator.CreateInstance(_helper.GetCmdType());
//cmd.Connection = _helper.GetConnection();在helper的ExeTrans中設置
//sql參數形式 MSSQL@,DB2@,ORACLE:
string paschar = _helper.SetPasChar();
//拼接insert腳本
string sql = string.Format("INSERT INTO {0}({1}) VALUES({2})", GetTableName(), fields, paschar + fields.Replace(",", "," + paschar));
cmd.CommandText = sql;
List<DbParameter> pas = new List<DbParameter>();
List<ColumnNameValueRelation> lst = GetColumns(false);
foreach (ColumnNameValueRelation cv in lst)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name;
para.Value = cv.Value;
cmd.Parameters.Add(para);
}
}
return cmd;
}
/// <summary>
/// 通過主鍵刪除,需要先調用SetHelper設置資料庫操作函數
/// </summary>
public int DeleteByPk()
{
int cols = 0;
string keyName = GetKeyName();
//主鍵不能為空,處理程式不能為null
if ((!string.IsNullOrEmpty(keyName)) && _helper != null)
{
string sql = string.Format("DELETE FROM {0} WHERE {1} = {2}{3}", GetTableName(), keyName, _helper.SetPasChar(), keyName);
object value = GetColumns(false).Where(en => en.Name.Equals(keyName)).ToList()[0].Value;
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = keyName;
para.Value = value;
List<DbParameter> pas = new List<DbParameter>();
pas.Add(para);
cols = _helper.ExeNoQuery(sql, pas);
}
return cols;
}
/// <summary>
/// 刪除命令,需要先調用SetHelper設置資料庫操作函數
/// </summary>
public DbCommand DeleteCmdByPk()
{
DbCommand cmd = null;
string keyName = GetKeyName();
//主鍵不能為空,處理程式不能為null
if ((!string.IsNullOrEmpty(keyName)) && _helper != null)
{
cmd = (DbCommand)Activator.CreateInstance(_helper.GetCmdType());
//cmd.Connection = _helper.GetConnection();在helper的ExeTrans中設置
string sql = string.Format("DELETE FROM {0} WHERE {1} = {2}{3}", GetTableName(), keyName, _helper.SetPasChar(), keyName);
cmd.CommandText = sql;
object value = GetColumns(false).Where(en => en.Name.Equals(keyName)).ToList()[0].Value;
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = keyName;
para.Value = value;
cmd.Parameters.Add(para);
}
return cmd;
}
/// <summary>
/// 通過主鍵修改,需要先調用SetHelper設置資料庫操作函數
/// </summary>
public int UpdateByPk()
{
int cols = 0;
string keyName = GetKeyName();
//主鍵不能為空,處理程式不能為null
if ((!string.IsNullOrEmpty(keyName)) && _helper != null)
{
List<ColumnNameValueRelation> lst = GetColumns(false);
//構建sql的修改欄位部分,C1=:C1,C2=:C2....
//Where找出不是主鍵的實例,Select用實例的Name值構造List<string>,Aggregate拼接不同欄位
string updateFields = lst.Where(en => (!en.Name.Equals(keyName))).ToList().Select(en => (string.Format("{0}={1}{2}", en.Name, _helper.SetPasChar(), en.Name))).ToList().Aggregate<string>((curr, next) => string.Format("{0},{1}", curr, next));
//拼接update的sql
string sql = string.Format("UPDATE {0} SET {1} WHERE {2} = {3}{4}", GetTableName(), updateFields, keyName, _helper.SetPasChar(), keyName);
//參數序列
List<DbParameter> pas = new List<DbParameter>();
foreach (ColumnNameValueRelation cv in lst)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name;
para.Value = cv.Value;
pas.Add(para);
}
cols = _helper.ExeNoQuery(sql, pas);
}
return cols;
}
/// <summary>
/// 修改命令,需要先調用SetHelper設置資料庫操作函數
/// </summary>
public DbCommand UpdateCmdByPk()
{
DbCommand cmd = null;
string keyName = GetKeyName();
//主鍵不能為空,處理程式不能為null
if ((!string.IsNullOrEmpty(keyName)) && _helper != null)
{
cmd = (DbCommand)Activator.CreateInstance(_helper.GetCmdType());
//cmd.Connection = _helper.GetConnection();在helper的ExeTrans中設置
List<ColumnNameValueRelation> lst = GetColumns(false);
//構建sql的修改欄位部分,C1=:C1,C2=:C2....
//Where找出不是主鍵的實例,Select用實例的Name值構造List<string>,Aggregate拼接不同欄位
string updateFields = lst.Where(en => (!en.Name.Equals(keyName))).ToList().Select(en => (string.Format("{0}={1}{2}", en.Name, _helper.SetPasChar(), en.Name))).ToList().Aggregate<string>((curr, next) => string.Format("{0},{1}", curr, next));
//拼接update的sql
string sql = string.Format("UPDATE {0} SET {1} WHERE {2} = {3}{4}", GetTableName(), updateFields, keyName, _helper.SetPasChar(), keyName);
cmd.CommandText = sql;
foreach (ColumnNameValueRelation cv in lst)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name;
para.Value = cv.Value;
cmd.Parameters.Add(para);
}
}
return cmd;
}
/// <summary>
/// 根據實例的屬性值查詢,引用類型屬性的null值不會加入到where條件,欄位是值類型(int,double,decimal)需要改為可空類型才能加入到where中,DateTime也要設置為可空類型(因為DateTime有預設值)。需要先調用SetHelper設置資料庫操作函數
/// </summary>
public List<T> Select<T>()
{
List<T> lst = new List<T>();
DataTable dt = Select();
if (dt != null)
{
foreach (DataRow dr in dt.Rows)
{
object obj = Activator.CreateInstance(this.GetType());
PropertyInfo[] props = this.GetType().GetProperties();
if (props != null)
{
foreach (PropertyInfo prop in props)
{
object[] attrs = prop.GetCustomAttributes(typeof(ColumnAttribute), true);
string columnName = ((ColumnAttribute)attrs[0]).ColumnName;
//給實例的屬性賦值
//if判斷是否為可空類型
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))//屬性是可空類型
{
//對可空類型賦值 如果值是DBNull則不需要賦值
if (!DBNull.Value.Equals(dr[columnName]))
{
//反射給可空類型賦值 ChangeType的Type參數值要為基礎類型 如int?的基礎類型是int decimal?的基礎類型是decimal
prop.SetValue(obj, Convert.ChangeType(dr[columnName], Nullable.GetUnderlyingType(prop.PropertyType)), null);
}
}
else //不是可空類型
{
prop.SetValue(obj, Convert.ChangeType(dr[columnName], prop.PropertyType), null);
}
}
}
lst.Add((T)obj);
}
}
return lst;
}
//根據實例的屬性值查詢,null值不作where條件
private DataTable Select()
{
DataTable dt = null;
string keyName = GetKeyName();
//設置了處理程式才能取到數據
if (_helper != null)
{
//null值不做where條件
List<ColumnNameValueRelation> lst = GetColumns(false);
//構建sql的where條件欄位部分,C1=:C1 AND C2=:C2....
//Select用實例的Name值構造List<string>,Aggregate拼接不同欄位
string selectFields = lst.Select(en => (string.Format("{0}={1}{2}", en.Name, _helper.SetPasChar(), en.Name))).ToList().Aggregate<string>((curr, next) => string.Format("{0} AND {1}", curr, next));
//拼接select的sql
string sql = string.Format("SELECT * FROM {0} WHERE {1}", GetTableName(), selectFields);
//參數序列
List<DbParameter> pas = new List<DbParameter>();
//添加參數值
foreach (ColumnNameValueRelation cv in lst)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name;
para.Value = cv.Value;
pas.Add(para);
}
dt = _helper.Select(sql, pas);
}
return dt;
}
//設置操作數據的處理函數
public void SetHelper(ISqlHelper helper)
{
_helper = helper;
}
//取得表名
private string GetTableName()
{
string name = "";
Type tableType = this.GetType();
object[] attrs = tableType.GetCustomAttributes(typeof(TableAttribute), true);
if (attrs != null && attrs.Length > 0)
{
name = ((TableAttribute)attrs[0]).TableName;
}
return name;
}
//獲取主鍵名稱
private string GetKeyName()
{
string keyName = "";
Type type = this.GetType();
PropertyInfo[] props = type.GetProperties();
if (props != null)
{
foreach (PropertyInfo pi in props)
{
//獲取屬性的標記 欄位信息
object[] colAttrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true);
if (colAttrs != null && colAttrs.Length > 0)
{
ColumnAttribute attr = colAttrs[0] as ColumnAttribute;
if (attr.IsPK == true)
{
keyName = attr.ColumnName;//如果設置了主鍵,可以取到,沒有就返回""
}
}
}
}
return keyName;
}
// 獲取實例中欄位名稱與欄位值的對應關係,containsNull表示是否包含NULL值及對應欄位名稱
private List<ColumnNameValueRelation> GetColumns(bool containsNull)
{
//存放欄位名稱和值的對應關係
List<ColumnNameValueRelation> lst = new List<ColumnNameValueRelation>();
Type type = this.GetType();
//取到實例的屬性
PropertyInfo[] props = type.GetProperties();
if (props != null)
{
foreach (PropertyInfo pi in props)
{
//獲取屬性的標記 取欄位信息
object[] colAttrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true);
if (colAttrs != null && colAttrs.Length > 0)
{
ColumnAttribute attr = colAttrs[0] as ColumnAttribute;
object value = pi.GetValue(this, null);//取屬性值
if (value == null)
{
if (containsNull) //值為null並且需要獲取null數據
{
lst.Add(new ColumnNameValueRelation(attr.ColumnName, value));
}
}
else
{
lst.Add(new ColumnNameValueRelation(attr.ColumnName, value));
}
}
}
}
return lst;
}
//欄位名的序列 用,連接 如f1,f2,f3,f4
private string GetFields()
{
List<ColumnNameValueRelation> lst = GetColumns(false);
//獲取欄位的序列
List<string> fields = lst.Select<ColumnNameValueRelation, string>(fr => fr.Name).ToList<string>();
//將欄位名稱用','連接
return fields.Aggregate<string>((curr, next) => string.Format("{0},{1}", curr, next));
}
}
public class MyDbHelper
{
private ISqlHelper _helper = null; //操作數據的處理函數
public MyDbHelper(ISqlHelper helper)
{
_helper = helper;
}
/// <summary>
/// 根據實例的屬性值查詢,引用類型屬性的null值不會加入到where條件,欄位是值類型(int,double,decimal)需要改為可空類型才能加入到where中,DateTime也要設置為可空類型(因為DateTime有預設值)。需要先調用SetHelper設置資料庫操作函數
/// </summary>
public List<T> Select<T>(T where)
{
DataTable dt = SelectData<T>(where);
return GetEntityFromTable<T>(dt);
}
public List<T> Select<T>()
{
DataTable dt = SelectData<T>();
return GetEntityFromTable<T>(dt);
}
/// <summary>
/// 將DataTable的數據轉換成實體數據集合,T類型必須從MyBaseClass類型繼承,屬性要加上欄位相關信息的標記
/// </summary>
public List<T> GetEntityFromTable<T>(DataTable dt)
{
List<T> lst = new List<T>();
if (dt != null)
{
PropertyInfo[] props = typeof(T).GetProperties();
foreach (DataRow dr in dt.Rows)
{
object obj = Activator.CreateInstance(typeof(T));
if (props != null)
{
foreach (PropertyInfo prop in props)
{
object[] attrs = prop.GetCustomAttributes(typeof(ColumnAttribute), true);
string columnName = ((ColumnAttribute)attrs[0]).ColumnName;
if (dt.Columns.Contains(columnName))//源數據的列中是否包含實體屬性對應欄位
{
//給實例的屬性賦值
//if判斷是否為可空類型
if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))//屬性是可空類型
{
//對可空類型賦值 如果值是DBNull則不需要賦值
if (!DBNull.Value.Equals(dr[columnName]))
{
//反射給可空類型賦值 ChangeType的Type參數值要為基礎類型 如int?的基礎類型是int decimal?的基礎類型是decimal
prop.SetValue(obj, Convert.ChangeType(dr[columnName], Nullable.GetUnderlyingType(prop.PropertyType)), null);
}
}
else //不是可空類型
{
prop.SetValue(obj, Convert.ChangeType(dr[columnName], prop.PropertyType), null);
}
}
}
}
lst.Add((T)obj);
}
}
return lst;
}
/// <summary>
/// 以where的值作條件,更新為value中的值
/// </summary>
public int Update<T>(T where, T value)
{
int cols = 0;
//必需要有操作函數
if (_helper != null)
{
//條件和更新值都不能為null
if (where != null && value != null)
{
//取where條件
List<ColumnNameValueRelation> whereList = GetColumns<T>(false, where);
//取value值
List<ColumnNameValueRelation> valueList = GetColumns<T>(false, value);
if (whereList != null && valueList != null && whereList.Count > 0 && valueList.Count > 0)
{
//set和where中的欄位有可能相同,為了避免參數名重覆,給set欄位的參數末加sp,給where欄位的參數末加wp
string wp = "W";
string sp = "S";
//拼sql set部分 Select先組裝成A=:A的形式,Aggregate累加成A=:A,B=:B
string sqlSet = valueList.Select(en => string.Format("{0}={1}{2}{3}", en.Name, _helper.SetPasChar(), en.Name, sp)).Aggregate((x, y) => (string.Format("{0},{1}", x, y)));
//拼sql where條件部分 Select先組裝成A=:A的形式,Aggregate累加成A=:A AND B=:B
string sqlWhere = whereList.Select(en => string.Format("{0}={1}{2}{3}", en.Name, _helper.SetPasChar(), en.Name, wp)).Aggregate((x, y) => (string.Format("{0} AND {1}", x, y)));
//參數序列
List<DbParameter> pas = new List<DbParameter>();
//添加參數值 set值
foreach (ColumnNameValueRelation cv in valueList)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name + sp;
para.Value = cv.Value;
pas.Add(para);
}
//添加參數值 where值
foreach (ColumnNameValueRelation cv in whereList)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name + wp;
para.Value = cv.Value;
pas.Add(para);
}
//形成完整sql
string sql = string.Format("UPDATE {0} SET {1} WHERE {2}", GetTableName<T>(), sqlSet, sqlWhere);
cols = _helper.ExeNoQuery(sql, pas);
}
}
}
return cols;
}
public int Delete<T>(T where)
{
int cols = 0;
if (_helper != null)
{
//條件不能為null
if (where != null)
{
//取where條件
List<ColumnNameValueRelation> whereList = GetColumns<T>(false, where);
if (whereList != null && whereList.Count > 0)
{
//拼sql where條件 Select先組裝成A=:A的形式,Aggregate累加成A=:A AND B=:B
string sqlWhere = whereList.Select(en => string.Format("{0}={1}{2}", en.Name, _helper.SetPasChar(), en.Name)).Aggregate((x, y) => (string.Format("{0} AND {1}", x, y)));
//參數序列
List<DbParameter> pas = new List<DbParameter>();
//添加參數值 where
foreach (ColumnNameValueRelation cv in whereList)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name;
para.Value = cv.Value;
pas.Add(para);
}
//拼接sql
string sql = string.Format("DELETE FROM {0} WHERE {1}", GetTableName<T>(), sqlWhere);
cols = _helper.ExeNoQuery(sql, pas);
}
}
}
return cols;
}
//根據實例的屬性值查詢,null值不作where條件
internal DataTable SelectData<T>(T where)
{
DataTable dt = null;
//string keyName = GetKeyName<T>();
//設置了處理程式才能取到數據
if (_helper != null)
{
//null值不做where條件
List<ColumnNameValueRelation> lst = GetColumns<T>(false, where);
//構建sql的where條件欄位部分,C1=:C1 AND C2=:C2....
//Select用實例的Name值構造List<string>,Aggregate拼接不同欄位
string selectFields = lst.Select(en => (string.Format("{0}={1}{2}", en.Name, _helper.SetPasChar(), en.Name))).ToList().Aggregate<string>((curr, next) => string.Format("{0} AND {1}", curr, next));
//拼接select的sql
string sql = string.Format("SELECT * FROM {0} WHERE {1}", GetTableName<T>(), selectFields);
//參數序列
List<DbParameter> pas = new List<DbParameter>();
//添加參數值
foreach (ColumnNameValueRelation cv in lst)
{
DbParameter para = (DbParameter)Activator.CreateInstance(_helper.GetPasType());
para.ParameterName = cv.Name;
para.Value = cv.Value;
pas.Add(para);
}
dt = _helper.Select(sql, pas);
}
return dt;
}
internal DataTable SelectData<T>()
{
DataTable dt = null;
//設置了處理程式才能取到數據
if (_helper != null)
{
string sql = string.Format("SELECT * FROM {0}", GetTableName<T>());
dt = _helper.Select(sql);
}
return dt;
}
//取得表名
internal string GetTableName<T>()
{
string name = "";
Type tableType = typeof(T);
object[] attrs = tableType.GetCustomAttributes(typeof(TableAttribute), true);
if (attrs != null && attrs.Length > 0)
{
name = ((TableAttribute)attrs[0]).TableName;
}
return name;
}
//獲取實例中欄位名稱與欄位值的對應關係,containsNull表示是否包含NULL值及對應欄位名稱
internal List<ColumnNameValueRelation> GetColumns<T>(bool containsNull, T where)
{
if (where == null)
{
return null;
}
//存放欄位名稱和值的對應關係
List<ColumnNameValueRelation> lst = new List<ColumnNameValueRelation>();
Type type = typeof(T);
//取到實例的屬性
PropertyInfo[] props = type.GetProperties();
if (props != null)
{
foreach (PropertyInfo pi in props)
{
//獲取屬性的標記 取欄位信息
object[] colAttrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true);
if (colAttrs != null && colAttrs.Length > 0)
{
ColumnAttribute attr = colAttrs[0] as ColumnAttribute;
object value = pi.GetValue(where, null);//取屬性值
if (value == null)
{
if (containsNull) //值為null並且需要獲取null數據
{
lst.Add(new ColumnNameValueRelation(attr.ColumnName, value));
}
}
else
{
lst.Add(new ColumnNameValueRelation(attr.ColumnName, value));
}
}
}
}
return lst;
}
//獲取主鍵名稱
internal string GetKeyName<T>()
{
string keyName = "";
Type type = typeof(T);
PropertyInfo[] props = type.GetProperties();
if (props != null)
{
foreach (PropertyInfo pi in props)
{
//獲取屬性的標記 欄位信息
object[] colAttrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true);
if (colAttrs != null && colAttrs.Length > 0)
{
ColumnAttribute attr = colAttrs[0] as ColumnAttribute;
if (attr.IsPK == true)
{
keyName = attr.ColumnName;//如果設置了主鍵,可以取到,沒有就返回""
}
}
}
}
return keyName;
}
//欄位名的序列 用,連接 如f1,f2,f3,f4
internal string GetFields<T>()
{
List<string> lst = new List<string>();
Type type = typeof(T);
//取到實例的屬性
PropertyInfo[] props = type.GetProperties();
if (props != null)
{
foreach (PropertyInfo pi in props)
{
//獲取屬性的標記 取欄位信息
object[] colAttrs = pi.GetCustomAttributes(typeof(ColumnAttribute), true);
if (colAttrs != null && colAttrs.Length > 0)
{
ColumnAttribute attr = colAttrs[0] as ColumnAttribute;
lst.Add(attr.ColumnName);
}
}
}
//將欄位名稱用','連接
return lst.Aggregate<string>((curr, next) => string.Format("{0},{1}", curr, next));
}
}
/// <summary>
/// 生成實體類
/// </summary>
public class EntityHelper
{
private ISqlHelper helper = null;
private DataBaseEnum dbenum;
/// <summary>
/// 需要知道資料庫類型和連接字元串
/// </summary>
public EntityHelper(DataBaseEnum dbe, string connStr)
{
dbenum = dbe;
if (dbenum.Equals(DataBaseEnum.Oracle))
{
helper = new OracleSqlHelper(connStr);
}
if (dbenum.Equals(DataBaseEnum.SqlServer))
{
helper = new MSSQLSqlHelper(connStr);
}
if (dbenum.Equals(DataBaseEnum.DB2))
{
helper = new DB2SqlHelper(connStr);
}
}
/// <summary>
/// 生成實體字元串
/// </summary>
public string CreateEntity(string tableName, string spaceName)
{
string str = "";
string nameSpace = "ABC.TEST";
if (!string.IsNullOrEmpty(spaceName))
{
nameSpace = spaceName;
}
tableName = tableName.Trim().ToUpper();
if (!string.IsNullOrEmpty(tableName))
{
List<ColumnInfo> lst = GetColumn(tableName);
if (lst != null)
{
StringBuilder sb = new StringBuilder();
sb.AppendLine("using System;");
sb.AppendLine("using System.Collections.Generic;");
sb.AppendLine("using System.Linq;");
sb.AppendLine("using System.Text;");
sb.AppendLine("using System.Data;");
sb.AppendLine("using MyORM;");
sb.AppendLine(null);//空一行
sb.AppendLine(string.Format("namespace {0}", nameSpace));
sb.AppendLine("{");
sb.AppendLine(string.Format("[TableAttribute(\"{0}\")]", tableName));
sb.AppendLine(string.Format("public class {0}Entity : MyBaseClass", ForMatName(tableName)));
sb.AppendLine("{");
//屬性序列
sb.AppendLine(lst.Select(en => string.Format("///<summary>\r\n///{0}\r\n///</summary>\r\n[ColumnAttribute(\"{1}\", DbType.{2} {3})]\r\npublic {4} {5}\r\n{6} get; set; {7}", en.Note, en.ColumnName, GetDbType(en.ColumnType), en.PkInfo.Equals("Y") ? ", IsPK = true" : "", GetOrmType(en.ColumnType), ForMatName(en.ColumnName), "{", "}")).Aggregate((x, y) => x + "\r\n" + y));
sb.AppendLine("}");
sb.AppendLine("}");
str = sb.ToString();
}
}
return str;
}
/// <summary>
/// 生成實體類 fullFileName如c:\123.cs
/// </summary>
public void CreateEntity(string tableName, string spaceName, string fullFileName)
{
if (!string.IsNullOrEmpty(fullFileName))
{
string es = CreateEntity(tableName, spaceName);
try
{
//先判斷文件目錄是否存在
int index = fullFileName.LastIndexOf('\\');
if (index - 1 > 0)
{
if (Directory.Exists(fullFileName.Substring(0, index)))
{
using (FileStream ins = new FileStream(fullFileName, FileMode.Create))
{
byte[] bts = Encoding.UTF8.GetBytes(es);
ins.Write(bts, 0, bts.Length);
}
}
}
}
catch (Exception ex)
{ }
}
}
/// <summary>
/// 將字元串用-分割,首字母大寫;如: hello_world->HelloWorld
/// </summary>
private string ForMatName(string name)
{
string rtn = name.Split('_').Where(a => !string.IsNullOrEmpty(a)).Select(b => (b.Substring(0, 1).ToUpper() + b.Substring(1).ToLower())).Aggregate((x, y) => x + y);
return rtn;
}
private string GetSql(string tableName)
{
string sql = "";
if (!string.IsNullOrEmpty(tableName))
{
if (dbenum.Equals(DataBaseEnum.Oracle))
{
sql = @"SELECT T.COLUMN_NAME,
T.DATA_TYPE,
A.COMMENTS NOTE,
DECODE(C.CONSTRAINT_TYPE, 'P', 'Y', 'N') PK_INFO
FROM USER_TAB_COLS T
LEFT JOIN USER_COL_COMMENTS A
ON T.TABLE_NAME = A.TABLE_NAME
AND T.COLUMN_NAME = A.COLUMN_NAME
LEFT JOIN (SELECT UC.TABLE_NAME,
UC.CONSTRAINT_NAME,
UC.COLUMN_NAME,
U.CONSTRAINT_TYPE
FROM USER_CONS_COLUMNS UC
INNER JOIN USER_CONSTRAINTS U
ON UC.TABLE_NAME = U.TABLE_NAME
AND UC.CONSTRAINT_NAME = U.CONSTRAINT_NAME
AND U.CONSTRAINT_TYPE = 'P') UC
ON T.TABLE_NAME = UC.TABLE_NAME
AND T.COLUMN_NAME = UC.COLUMN_NAME
LEFT JOIN USER_CONSTRAINTS C
ON UC.CONSTRAINT_NAME = C.CONSTRAINT_NAME
WHERE UPPER(T.TABLE_NAME) = '" + tableName.Trim().ToUpper() + "'";
}
if (dbenum.Equals(DataBaseEnum.SqlServer))
{
sql = @"SELECT TAB.NAME,COL.NAME AS COLUMN_NAME,TP.NAME AS DATA_TYPE,ISNULL (DS.VALUE, '') AS NOTE,CASE WHEN EXISTS (SELECT 1 FROM SYSOBJECTS WHERE XTYPE = 'PK' AND PARENT_OBJ = COL.ID AND NAME IN (SELECT NAME FROM SYSINDEXES WHERE INDID IN (SELECT INDID FROM SYSINDEXKEYS WHERE ID = COL.ID AND COLID = COL.COLID))) THEN 'Y' ELSE 'N' END AS PK_INFO FROM SYSOBJECTS TAB LEFT JOIN SYSCOLUMNS COL ON TAB.ID = COL.ID LEFT JOIN SYSTYPES TP ON COL.XUSERTYPE = TP.XUSERTYPE LEFT JOIN SYS.EXTENDED_PROPERTIES DS ON COL.ID = DS.MAJOR_ID AND COL.COLID = DS.MINOR_ID WHERE TAB.XTYPE = 'U' AND TAB.NAME = '" + tableName.Trim().ToUpper() + "'";
}
if (dbenum.Equals(DataBaseEnum.DB2))
{
sql = @"SELECT d.name tbName,
COALESCE(d.remarks, '') tbDesc,
a.name COLUMN_NAME,
a.coltype DATA_TYPE,
decode(a.nulls, 'Y', '1', '0') NOT_NULL,
decode(a.identity, 'Y', '1', '0') auto,
a.longlength width,
a.scale precision,
a.remarks NOTE,
decode(n.unique_colcount, '1', '1', '0') unique,
decode(n.uniquerule, 'P', 'Y', 'N') PK_INFO,
COALESCE(n.name, '') indexName
FROM sysibm.syscolumns a
INNER JOIN sysibm.systables d
on a.tbname = d.name
LEFT JOIN sysibm.sysindexes n
on n.tbname = d.name
and SUBSTR(colnames, 2) = a.name
where d.name = '" + tableName + "'";
}
}
return sql;
}
/// <summary>
/// 將查出的表結構信息組裝成實體;COLUMN_NAME DATA_TYPE NOTE PK_INFO
/// </summary>
private List<ColumnInfo> GetColumn(string tableName)
{
List<ColumnInfo> lst = null;
string sql = GetSql(tableName);
if (!string.IsNullOrEmpty(sql))
{
DataTable dt = helper.Select(sql, null);
if (dt != null)
{
lst = new List<ColumnInfo>();
ColumnInfo ci = null;
foreach (DataRow dr in dt.Rows)
{
ci = new ColumnInfo();
ci.ColumnName = dr["COLUMN_NAME"].ToString().ToUpper();
ci.ColumnType = GetEnType(dr["DATA_TYPE"].ToString());
ci.Note = dr["NOTE"].ToString();
ci.PkInfo = dr["PK_INFO"].ToString();
lst.Add(ci);
}
}
}
return lst;
}
/// <summary>
/// C#基礎類型轉換為DbType對應類型
/// </summary>
private string GetDbType(string type)
{
string dbtype = "";
if (type.Equals("string"))
{
dbtype = "AnsiString";
}
else if (type.Equals("byte[]"))
{
dbtype = "Binary";
}
else
{
dbtype = type;
}
return dbtype;
}
/// <summary>
/// 將c#基礎數據類型轉成實體數據類型:除引用類型以外的數字日期等轉為可空類型
/// </summary>
private string GetOrmType(string type)
{
string ormtype = "";
if (type.Equals("string") || type.Equals("byte[]"))
{
ormtype = type; //string和數組是引用類型
}
else
{
ormtype = type + "?"; //數字日期等轉為可空類型
}
return ormtype;
}
/// <summary>
/// 將資料庫基本數據類型轉為C#數據類型
/// </summary>
private string GetEnType(string dataType)
{
string type = "";
//基礎類型string Int32 Decimal DateTime
switch (dataType.Trim())
{
//1、oracle
case "CHAR": type = "string"; break;
case "NCHAR": type = "string"; break;
case "VARCHAR": type = "string"; break;
case "VARCHAR2": type = "string"; break;
case "NVARCHAR2": type = "string"; break;
case "NUMBER": type = "Decimal"; break;
case "INTEGER": type = "Int32"; break;
case "BINARY_FLOAT": type = "Decimal"; break;
case "BINARY_DOUBLE": type = "Decimal"; break;
case "DATE": type = "DateTime"; break;
case "TIMESTAMP": type = "DateTime"; break;