C#_自定義簡單ORM

来源:http://www.cnblogs.com/cy2011/archive/2017/02/08/6374687.html
-Advertisement-
Play Games

一,基本思路:利用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;

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 三種情況:final數據、方法和類 一、final數據 一個永不改變的編譯時常量。(編譯時常量必須是基本數據類型,必須在這個常量定義時賦值) 一個在運行時被初始化的值,而不希望它被改變。 對於基本類型,final使數值恆定不變;對於對象引用,final使引用恆定不變,然而對象其自身卻是可以被修改的。 ...
  • 隨著目前微信越來越火,所以研究微信的人也就越來越多,這不前一段時間,我們公司就讓我做一個微信公眾號中問卷調查發紅包功能,經過一段時間的研究,把功能完成,裡面主要的實現步驟都是按照微信公眾號開發文檔來的,很詳細,在整個過程唯有紅包演算法需要仔細編寫,因為畢竟涉及到錢,所以得小心,而且不僅微信中需要發紅包 ...
  • 20170209問題解析請點擊今日問題下方的“【Java每日一題】20170210”查看(問題解析在公眾號首發,公眾號ID:weknow619) 今日問題: 請問主程式輸出結果是什麼?(點擊以下“【Java每日一題】20170210”查看20170209問題解析) 題目原發佈於公眾號、簡書:【Jav ...
  • 我們在前面用了許多章節來討論如何把數據從後臺資料庫中搬到記憶體,然後進行逐行操作運算。我們選定的解決方案是把後臺數據轉換成記憶體中的數據流。無論在打開資料庫表或從資料庫讀取數據等環節都涉及到對資料庫表這項資源的安全使用:我們最起碼要保證在完成使用或者使用中途出現錯誤異常退出時能釋放占用的資源。談到資源使 ...
  • #!/usr/bin/eny python #! -*- coding:utf-8 -*- """ import time a1 = True while a1: print('1') time.sleep(3) a1 = False print('end') """ #菜比的輸出10內的整數。 #... ...
  • 我們來講一下組合模式: 怎麼是組合模式呢?組合模式,將對象組合成樹形結構以表示‘部分-整體’的層次結構,組合模式是的用戶對單個對象和組合對象的用用具有一致性。 與一個很簡單的例子,公司的組織架構,大都是樹枝結構的。下麵,我們來看一下如何用組合模式寫樹枝結構。 客戶端 結果: 好,是不是很簡單啊…… ...
  • 外觀模式 目的:的意圖是為子系統提供一個介面,方便其使用。 外觀模式常用於一些常規的應用程式的開發,因為一般都會對子系統的類進行重構,所以外觀類主要的職責就是為了給子系統提供簡單的訪問方式, 使其有一個明確的目的,從而完成對系統的重構。外觀類介於工具類和應用程式之間。 要註意實例與外觀的區別: 1、 ...
  • 官網:http://www.haproxy.org/ 個人感覺haproxy學習的重點在於配置上,把配置文檔搞懂了就明白大部分套路了。不過本篇內容屬於入門學習:1.使用haproxy簡單的實現負載均衡的效果。2.使用自帶監控查看效果。後續待學習的方向是訪問日誌配置、優化等~ 簡介: 我在虛擬機上裝的 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...