作为ERP等数据应用程序,数据库的处理是重中之重。

在框架中,我封装了一个数据库的基类,在每个模组启动或窗体启动过程中,实例化一个基类即可调用CRUD操作(create 添加read读取 update 修改delete删除),当然,还包括基础的SQL事务处理。

这个过程中,还考虑到对插件的管控,利用反射增加了调用授权,避免未经授权的程序盗用数据连接。

看看完整的代码:

    /// <summary>
/// 数据库连接基类
/// </summary>
public class DBContext
{
/// <summary>
/// 本类内部明文连接串
/// </summary>
private string ConnStr = null; /// <summary>
/// 经测试后,数据库是否可正常连接
/// </summary>
public bool IsConnected = false; /// <summary>
/// 连接出错后记录的错误信息
/// </summary>
public string ConnectErrorMessage = string.Empty; /// <summary>
/// 加密后的数据库连接字符串,引用的地方要进行解密.
/// <para>在需要做Socket快速检测的情况下,连接串会包含TestRegion->FastCheckIP:192.168.0.1;FastCheckPort:1433;FastCheckTimeOut:2000;附串,解密后应该去除才能正常使用打开连接。</para>
/// </summary>
public string ConnStrShare = null; /// <summary>
/// 当前DBContext使用的数据库名称
/// </summary>
public string DBName = string.Empty; #region 数据连接的初始化
/// <summary>
/// 以全局信息的ConnStrCurAct连接串为依据初始化一个数据库连接.
/// </summary>
public DBContext()
{
//获取调用者的Title
string tmpTitle = AssemblyInfos.GetAsbAttr(AssemblyInfos.AttrType.Title, Assembly.GetCallingAssembly());
//获取调用者的说明
string tmpDesc = AssemblyInfos.GetAsbAttr(AssemblyInfos.AttrType.Description, Assembly.GetCallingAssembly());
if (tmpTitle != OCrypto.AES16Decrypt(tmpDesc, Core.MasterAESKey))
{
MyMsg.Warning("调用者:" + tmpTitle + "未经过框架授权,无法引用数据连接.");
return;
}
//没有指定连接则获取当前操作帐套的连接字符串;
ConnStrShare = GlbInfo.ConnStrCurAct;
ConnStr = OCrypto.AES16Decrypt(GlbInfo.ConnStrCurAct, Core.MasterAESKey);
Initial();
} /// <summary>
/// 以一个加密后的连接字串为依据初始化一个数据库连接.
/// <para>在需要做Socket快速检测的情况下,连接串应包含TestRegion->FastCheckIP:192.168.0.1;FastCheckPort:1433;FastCheckTimeOut:2000;附串以便做Socket快速连接测试。</para>
/// </summary>
/// <param name="connStrEncrypted">已使用系统默认加密的连接字符串</param>
public DBContext(string connStrEncrypted)
{
//获取调用者的Title
string tmpTitle = AssemblyInfos.GetAsbAttr(AssemblyInfos.AttrType.Title, Assembly.GetCallingAssembly());
//获取调用者的说明
string tmpDesc = AssemblyInfos.GetAsbAttr(AssemblyInfos.AttrType.Description, Assembly.GetCallingAssembly());
if (tmpTitle != OCrypto.AES16Decrypt(tmpDesc, Core.MasterAESKey))
{
MyMsg.Warning("调用者:" + tmpTitle + "未经过框架授权,无法引用数据连接.");
return;
}
ConnStrShare = connStrEncrypted;
ConnStr = OCrypto.AES16Decrypt(connStrEncrypted, Core.MasterAESKey);
Initial();
}
private void Initial()
{
try
{
//StackTrace trace = new StackTrace();
//MethodBase method = trace.GetFrame(1).GetMethod();
//MyMsg.Asterisk(method.Module.Name);
//Guid ownGUID = new Guid(((GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetCallingAssembly(), typeof(GuidAttribute))).Value);
//MyMsg.Asterisk("GetCallingAssembly:"+ownGUID.ToString());
//Guid ownGUID1 = new Guid(((GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetEntryAssembly(), typeof(GuidAttribute))).Value);
//MyMsg.Asterisk("GetEntryAssembly:" + ownGUID1.ToString());
//Guid ownGUID2 = new Guid(((GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(), typeof(GuidAttribute))).Value);
//MyMsg.Asterisk("GetExecutingAssembly:" + ownGUID2.ToString());
//Guid ownGUID3 = new Guid(((GuidAttribute)Attribute.GetCustomAttribute(Assembly.GetAssembly(method.Module.GetType()), typeof(GuidAttribute))).Value);
//MyMsg.Asterisk("GetAssembly(method.GetType()):"+ownGUID3.ToString()); //调用者在授权模块清单之中.ATCore.dll,AITO.exe,ATCust.exe,ATData.dll,ATProj.exe
//bool Authed = StrFunc.StrInArray(method.Module.Name, Crypt.AES16Decrypt(Properties.Settings.Default.CORE_SHARED_TO, AES_KEY));
bool authorized = true;//取消管制
if (authorized)
{
if (ConnStr == null)
{
throw (new Exception("连接字符串没有提供."));
}
else
{
IsConnected = TestConnection();
}
}
else
{
return;
} }
catch (Exception ex)
{
MyMsg.Asterisk("未授权的操作!");
throw ex;
}
} /// <summary>
/// 测试数据库连接是否正常
/// </summary>
/// <returns></returns>
private bool TestConnection()
{
try
{
ConnectErrorMessage = string.Empty;
if(ConnStr.IndexOf("FastCheckIP:")>= && ConnStr.IndexOf("FastCheckPort:") >= )
{
string fastChkIP = OString.GetMidStr(ConnStr, "FastCheckIP:", ";").Trim();
int fastCheckPort = OString.NZ2Int(OString.GetMidStr(ConnStr, "FastCheckPort:", ";").Trim());
int fastCheckTimeOut = OString.NZ2Int(OString.GetMidStr(ConnStr, "FastCheckTimeOut:", ";").Trim());
if (!string.IsNullOrEmpty(fastChkIP) && fastCheckPort> && fastCheckTimeOut>)
{
string textRst = ONetwork.TestSokectConn(fastChkIP, fastCheckPort, fastCheckTimeOut);
if (textRst != "OK")
{
ConnectErrorMessage = textRst;
return false;
}
}
}
ConnStr = OString.LeftOf(ConnStr, "TestRegion->");
using (SqlConnection con = new SqlConnection(ConnStr))
{
con.Open();
DBName = con.Database;
return true;
}
}
catch (Exception ex)
{
ConnectErrorMessage = ex.Message;
return false;
}
}
#endregion /// <summary>
/// 用MasterAESKey还原已经加密过的字符串,并去除掉额外的用于Socket测试的属性
/// </summary>
/// <param name="connStrEncred"></param>
/// <returns></returns>
private string GetRConnStr(string connStrEncred)
{
return ConnStr = OString.LeftOf(OCrypto.AES16Decrypt(connStrEncred, Core.MasterAESKey), "TestRegion->");
} #region SQL作业区域
/// <summary>
/// 执行UPDATE、INSERT 和 DELETE 语句,返回值为该命令所影响的行数。对于所有其他类型的语句,返回值为 -1。如果发生回滚,返回值也为 -1
/// <para>尽量使用 “>=”,不要使用 ">"</para>
/// <para>进行Insert、update的时候,应该防止冲突(特别是数据量大的时候,锁会升级)</para>
/// <para>LIKE使用注意(尽量不采用 “%1%” 之类的方式处理,多采用 “1% ”、“%1”)</para>
/// <para>避免连接字段查询(如 a.c1+'|'+b.c2 = XXXX,应该采用 a.c1= 'X' and b.c2 = 'XXX')</para>
/// </summary>
/// <param name="sqlText"></param>
/// <param name="paras">参数列表,如new SqlParameter ("@Age",100)</param>
public int RunSql(string sqlText, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if(conn.Database!=DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = new SqlCommand(sqlText, conn))
{
if (paras != null) cmd.Parameters.AddRange(paras);
int rst = cmd.ExecuteNonQuery();
cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
return rst;
}
}
}
catch (Exception ex)
{
MyMsg.Exclamation(ex.Message);
throw ex;
}
} /// <summary>
/// 批量执行SQL语句,传入SQL语句+参数的字典,如果是同样的语句重复执行,则使用"Lead"+i+"||||||"(6个|)的方法区分开每条语句避免传入失败.
/// 各语句成功执行返回0,失败回滚返回-1
/// </summary>
/// <param name="dicSqls">SQL语句+参数字典</param>
/// <param name="cmdTimeOut">CommandTimeout,此参数大于30时才起作用</param>
/// <returns></returns>
public int RunSqlsInTran(Dictionary<string, SqlParameter[]> dicSqls, int cmdTimeOut = )
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlTransaction tran = conn.BeginTransaction()) //开始一个事务
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.Transaction = tran; //必须指定事务对象
//设置一个超时时间,需时过长的应该放在存储过程中处理
if (cmdTimeOut > ) cmd.CommandTimeout = cmdTimeOut;
//开始
if (dicSqls != null && dicSqls.Count >= )
{
foreach (KeyValuePair<string, SqlParameter[]> sqls in dicSqls)
{
int m = sqls.Key.IndexOf("||||||");
if (m >= )
{
cmd.CommandText = sqls.Key.Substring(m + );
}
else cmd.CommandText = sqls.Key;
cmd.Parameters.Clear();
if (sqls.Value != null) cmd.Parameters.AddRange(sqls.Value);
cmd.ExecuteNonQuery();
}
}
//结束
cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
}
try
{
tran.Commit();//事务提交
return ;
}
catch
{
tran.Rollback();//事务回滚
return -;
}
finally
{
}
}//事务结束
}
}
catch (Exception ex)
{
MyMsg.Exclamation(ex.Message);
return -;
}
}
/// <summary>
/// 按顺序批量执行SQL语句.
/// 传入SQL语句+参数的字典,如果是同样的语句重复执行,则使用"Lead"+i+"||||||"的方法区分开每条语句避免传入失败.
/// 成功执行后返回"{success:ok}"字符串,如果执行步骤出错,则返回步骤Lead字符串+"{error:..."的状态字,事务过程中出错返回"{exception-tran:..."
/// 传入的所有语句都要有具有返回值(select要有记录,update等要有影响的行数),没有返回值则发生回滚。
/// </summary>
/// <param name="dicSqls"></param>
/// <param name="cmdTimeOut">CommandTimeout,此参数大于30时才起作用</param>
/// <returns></returns>
public string RunSeqSqlsInTran(Dictionary<string, SqlParameter[]> dicSqls, int cmdTimeOut = )
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
string rtnValue = string.Empty;
using (SqlTransaction tran = conn.BeginTransaction()) //开始一个事务
{
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.Transaction = tran; //必须指定事务对象
if (cmdTimeOut > ) cmd.CommandTimeout = cmdTimeOut; //设置一个超时时间,需时过长的应该放在存储过程中处理
//开始
if (dicSqls != null && dicSqls.Count >= )
{
object tmpO = null;
int runRstRows = ;
foreach (KeyValuePair<string, SqlParameter[]> sqls in dicSqls)
{
int m = sqls.Key.IndexOf("||||||");
if (m >= )
{
rtnValue = sqls.Key.Substring(, m);
cmd.CommandText = sqls.Key.Substring(m + );
}
else
{
rtnValue = "未指定的作业";
cmd.CommandText = sqls.Key;
}
cmd.Parameters.Clear();
if (sqls.Value != null) cmd.Parameters.AddRange(sqls.Value);
if (cmd.CommandText.Trim().Substring(, ) == "SELECT")
{
tmpO = cmd.ExecuteScalar();
if (tmpO == null)
{
tran.Rollback();//事务回滚
return "{error:RunSeqSqlsInTran-" + rtnValue + "}";
}
}
else
{
runRstRows = cmd.ExecuteNonQuery();
if (runRstRows <= )
{
tran.Rollback();//事务回滚
return "{error:RunSeqSqlsInTran-" + rtnValue + "}";
}
}
}
}
//结束
cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
}
try
{
tran.Commit();//事务提交
return "{success:ok}";
}
catch (Exception ex)
{
tran.Rollback();//事务回滚
return "{exception-tran:" + ex.Message + "}";
}
finally
{
}
}//事务结束
}
}
catch (Exception ex)
{
MyMsg.Exclamation(ex.Message);
return "{exception:" + ex.Message + "}";
} }
/// <summary>
/// 执行SQL语句,并填充指定的Dataset中的表(在填充之前会清空此表的原有数据,如有主从关联,则不能建立约束,或在执行前清除关联子表).
/// <para>尽量使用 “>=”,不要使用 ">"</para>
/// <para>进行Insert、update的时候,应该防止冲突(特别是数据量大的时候,锁会升级)</para>
/// <para>LIKE使用注意(尽量不采用 “%1%” 之类的方式处理,多采用 “1% ”、“%1”)</para>
/// <para>避免连接字段查询(如 a.c1+'|'+b.c2 = XXXX,应该采用 a.c1= 'X' and b.c2 = 'XXX')</para>
/// </summary>
/// <param name="tagDS">目标Dataset</param>
/// <param name="tableName">目标表名,当为空时将填充Tables[0]</param>
/// <param name="sqlText">SQL语句</param>
/// <param name="paras">参数</param>
/// <returns></returns>
public bool SqlToDS(DataSet tagDS, string tableName, string sqlText, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sqlText;
if (paras != null) cmd.Parameters.AddRange(paras);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
if (string.IsNullOrEmpty(tableName))
{
tagDS.Tables[].Clear(); //先清除再填充,如有建立主从关联的会出错,可在调用端先处理清除.
adapter.Fill(tagDS.Tables[]);
}
else
{
tagDS.Tables[tableName].Clear();
adapter.Fill(tagDS,tableName);
}
if(cmd.Parameters!=null) cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
return true;
}
}
}
catch (Exception)
{
return false;
}
} /// <summary>
/// 执行SQL语句,并返回一个Datatable结果集
/// <para>尽量使用 “>=”,不要使用 ">"</para>
/// <para>进行Insert、update的时候,应该防止冲突(特别是数据量大的时候,锁会升级)</para>
/// <para>LIKE使用注意(尽量不采用 “%1%” 之类的方式处理,多采用 “1% ”、“%1”)</para>
/// <para>避免连接字段查询(如 a.c1+'|'+b.c2 = XXXX,应该采用 a.c1= 'X' and b.c2 = 'XXX')</para>
/// </summary>
/// <param name="sqlText"></param>
/// <param name="paras"></param>
/// <returns></returns>
public DataTable SqlToDT(string sqlText, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sqlText;
if (paras != null) cmd.Parameters.AddRange(paras);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet dataset = new DataSet();
adapter.Fill(dataset);
cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
return dataset.Tables[];
}
}
}
catch (Exception ex)
{
MyMsg.Exclamation(ex.Message);
return null;
throw ex;
}
} /// <summary>
/// 执行SQL语句,并返回一个Datatable结果集的首行
/// <para>尽量使用 “>=”,不要使用 ">"</para>
/// <para>进行Insert、update的时候,应该防止冲突(特别是数据量大的时候,锁会升级)</para>
/// <para>LIKE使用注意(尽量不采用 “%1%” 之类的方式处理,多采用 “1% ”、“%1”)</para>
/// <para>避免连接字段查询(如 a.c1+'|'+b.c2 = XXXX,应该采用 a.c1= 'X' and b.c2 = 'XXX')</para>
/// </summary>
/// <param name="sqlText"></param>
/// <param name="paras"></param>
/// <returns></returns>
public DataRow SqlToDRow(string sqlText, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sqlText;
if (paras != null) cmd.Parameters.AddRange(paras);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet dataset = new DataSet();
adapter.Fill(dataset);
cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
DataTable DTTmp = dataset.Tables[];
if (DTTmp == null) return null;
if (DTTmp.Rows.Count < ) return null;
return DTTmp.Rows[];
}
}
}
catch (Exception ex)
{
return null;
throw ex;
}
} /// <summary>
/// 执行SQL语句,并返回第一行第一列的值为string,如果记录不存在则返回空字符串, 执行出错则返回{error:XX}
/// <para>尽量使用 “>=”,不要使用 ">"</para>
/// <para>进行Insert、update的时候,应该防止冲突(特别是数据量大的时候,锁会升级)</para>
/// <para>LIKE使用注意(尽量不采用 “%1%” 之类的方式处理,多采用 “1% ”、“%1”)</para>
/// <para>避免连接字段查询(如 a.c1+'|'+b.c2 = XXXX,应该采用 a.c1= 'X' and b.c2 = 'XXX')</para>
/// </summary>
/// <param name="sqlText">sql语句</param>
/// <param name="paras">参数</param>
/// <returns></returns>
public string SqlToString(string sqlText, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = sqlText;
if (paras != null) cmd.Parameters.AddRange(paras);
object rtnObj = cmd.ExecuteScalar();
cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
if (rtnObj == null)
{
return string.Empty;
}
else return rtnObj.ToString();
}
}
}
catch (Exception ex)
{
return "{error:SqlToString-" + ex.Message + "}";
}
} /// <summary>
/// 从不同服务器插入大量数据到目标服务器的数据表中(使用了系统加密后的连接字符串)
/// </summary>
/// <param name="targetConnStr">目标服务器的连接字符串(已加密的)</param>
/// <param name="targetDBTable">目标服务器中的目标表名称</param>
/// <param name="sourceConnStr">数据获取来源服务器的连接字符串(已加密的)</param>
/// <param name="sourceSqlText">获取数据的SQL语句</param>
/// <param name="columnMap">表结构映射(可留空)</param>
public bool BulkCopy(string targetConnStr, string targetDBTable, string sourceConnStr, string sourceSqlText, Dictionary<string, string> columnMap = null)
{
//还原连接字符串
targetConnStr = GetRConnStr(targetConnStr);
sourceConnStr = GetRConnStr(sourceConnStr);
// 源
using (SqlConnection sourceConnection = new SqlConnection(sourceConnStr))
{
SqlCommand myCommand = new SqlCommand(sourceSqlText, sourceConnection);
sourceConnection.Open();
SqlDataReader reader = myCommand.ExecuteReader();
// 目的
using (SqlConnection targetConn = new SqlConnection(targetConnStr))
{
// 打开连接
targetConn.Open();
using (SqlTransaction tran = targetConn.BeginTransaction()) //开始一个事务
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(targetConn))
{
if (columnMap != null && columnMap.Count >= )
{
foreach (KeyValuePair<string, string> pair in columnMap)
{
bulkCopy.ColumnMappings.Add(pair.Key, pair.Value);
}
}
bulkCopy.BulkCopyTimeout = ;
bulkCopy.BatchSize = ;
bulkCopy.NotifyAfter = ;
bulkCopy.DestinationTableName = targetDBTable;
bulkCopy.WriteToServer(reader);
}
try
{
tran.Commit();//事务提交
return true;
}
catch
{
tran.Rollback();//事务回滚
return false;
}
finally
{
reader.Close();
} }
}
}
} /// <summary>
/// 从Datatable中插入大量数据到目标服务器的数据表中
/// </summary>
/// <param name="targetConnStr">目标服务器的连接字符串(已加密的)</param>
/// <param name="targetDBTable">目标服务器中的目标表名称</param>
/// <param name="sourceDT">原始数据Datatable</param>
/// <param name="columnMap">表结构映射(可留空)</param>
public bool BulkCopyDT(string targetConnStr, string targetDBTable, DataTable sourceDT, Dictionary<string, string> columnMap = null)
{
//还原连接字符串
targetConnStr = GetRConnStr(targetConnStr);
using (SqlConnection targetConn = new SqlConnection(targetConnStr))
{
// 打开连接
targetConn.Open();
using (SqlTransaction tran = targetConn.BeginTransaction()) //开始一个事务
{
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(targetConn, SqlBulkCopyOptions.Default, tran)) //放入事务之中
{
if (columnMap != null && columnMap.Count >= )
{
foreach (KeyValuePair<string, string> pair in columnMap)
{
bulkCopy.ColumnMappings.Add(pair.Key, pair.Value);
}
}
bulkCopy.BulkCopyTimeout = ;
bulkCopy.BatchSize = ;
bulkCopy.NotifyAfter = ;
bulkCopy.DestinationTableName = targetDBTable;
bulkCopy.WriteToServer(sourceDT);
}
try
{
tran.Commit();//事务提交
return true;
}
catch
{
tran.Rollback();//事务回滚
return false;
}
}
}
} /// <summary>
/// 先插入到根据目标表创建的临时表,再做相关插入操作.如果目标表中有自增列,则表结构必须全部字段映射.如果先删除后插入,请注意使用的是TRUNCATE TABLE模式,数据不可恢复.
/// </summary>
/// <param name="targetConnStr">目标服务器的连接字符串(已加密的)</param>
/// <param name="targetDBTable">目标服务器中的目标表名称</param>
/// <param name="sourceConnStr">数据获取来源服务器的连接字符串(已加密的)</param>
/// <param name="sourceSqlText">获取数据的SQL语句</param>
/// <param name="keyField">主键字段名称(默认需提供),先删旧后插入新的情况下,可以留空.</param>
/// <param name="DelBeforInsert">是否先删除旧数据,再新增新数据(默认为否)</param>
/// <param name="columnMap">表结构映射(可留空)</param>
/// <param name="hasAutoRKEY">如果有自增列,则表结构必须映射</param>
/// <param name="needUpdateFlds">是否需要对旧数据执行更新操作,是的话则必须指定更新表达式</param>
/// <param name="updFldsName">旧数据更新表达式,以逗号分隔.如:(YYPass,YYDept)表示将写入目标表中的YYPass,YYDept字段更新为来源数据.</param>
public bool BulkCopyByTempTable(string targetConnStr, string targetDBTable, string sourceConnStr, string sourceSqlText, string keyField = "", bool DelBeforInsert = false, Dictionary<string, string> columnMap = null, bool hasAutoRKEY = false, bool needUpdateFlds = false, string updFldsName = "")
{
//还原连接字符串
targetConnStr = GetRConnStr(targetConnStr);
sourceConnStr = GetRConnStr(sourceConnStr);
string columnsList = string.Empty;
string whereStr = string.Empty;
// 源
using (SqlConnection sourceConnection = new SqlConnection(sourceConnStr))
{
SqlCommand myCommand = new SqlCommand(sourceSqlText, sourceConnection);
sourceConnection.Open();
SqlDataReader reader = myCommand.ExecuteReader(); // 目的
using (SqlConnection targetConn = new SqlConnection(targetConnStr))
{
// 打开连接
targetConn.Open(); using (SqlTransaction tran = targetConn.BeginTransaction()) //开始一个事务
{
string tmpTabName = "atmpBCP" + DateTime.Now.Ticks.ToString();
using (SqlCommand cmd = new SqlCommand())
{
cmd.Connection = targetConn;
cmd.Transaction = tran; //必须指定事务对象 cmd.CommandText = "SELECT * INTO " + tmpTabName + " FROM " + targetDBTable + " WHERE 1=2 "; //依照目标表创建临时表
cmd.ExecuteNonQuery(); }
using (SqlBulkCopy bulkCopy = new SqlBulkCopy(targetConn, SqlBulkCopyOptions.Default, tran)) //放入事务之中
{
if (columnMap != null && columnMap.Count >= )
{ foreach (KeyValuePair<string, string> pair in columnMap)
{
bulkCopy.ColumnMappings.Add(pair.Key, pair.Value);
columnsList += pair.Value + ",";
}
columnsList = columnsList.Substring(, columnsList.Length - );
}
bulkCopy.BulkCopyTimeout = ;
bulkCopy.BatchSize = ;
bulkCopy.NotifyAfter = ;
bulkCopy.DestinationTableName = tmpTabName;
bulkCopy.WriteToServer(reader);
}
//完成数据到临时表的插入后 using (SqlCommand dCommand = new SqlCommand())
{
dCommand.Connection = targetConn;
dCommand.Transaction = tran; //必须指定事务对象 if (DelBeforInsert) //先删除再插入
{
dCommand.CommandText = "TRUNCATE TABLE " + targetDBTable;
dCommand.ExecuteNonQuery(); //插入新记录
if (hasAutoRKEY)
{
dCommand.CommandText = "INSERT INTO " + targetDBTable + " (" + columnsList + ") SELECT " + columnsList + " FROM " + tmpTabName;
}
else
{
dCommand.CommandText = "INSERT INTO " + targetDBTable + " SELECT * FROM " + tmpTabName;
}
dCommand.ExecuteNonQuery(); }
else //插入不存在的记录
{
//如果需要则更新旧数据,旧表和临时表结构一致
if (needUpdateFlds)
{
if (!string.IsNullOrEmpty(updFldsName))
{
string updStr = string.Empty;
string[] updFlds = OString.SplitStr(updFldsName, ",");//获取要更新的字段名
foreach (string fldName in updFlds)
{
updStr += "[" + fldName + "]=" + tmpTabName + "." + "[" + fldName + "],";
}
updStr = OString.CutLastStrIf(updStr, ",");
dCommand.CommandText = "UPDATE " + targetDBTable + " SET " + updStr + " FROM " + tmpTabName + " INNER JOIN " + targetDBTable + " ON " + tmpTabName + "." + keyField + " = " + targetDBTable + "." + keyField + "";
dCommand.ExecuteNonQuery();
}
} //插入不存在的新记录
if (!string.IsNullOrEmpty(keyField))
{
whereStr = " WHERE (" + keyField + " NOT IN (SELECT " + keyField + " FROM " + targetDBTable + "))";
}
if (hasAutoRKEY)
{
dCommand.CommandText = "INSERT INTO " + targetDBTable + " (" + columnsList + ") SELECT " + columnsList + " FROM " + tmpTabName + whereStr;
}
else
{
dCommand.CommandText = "INSERT INTO " + targetDBTable + " SELECT * FROM " + tmpTabName + whereStr;
}
dCommand.ExecuteNonQuery();
} } try
{
tran.Commit();//事务提交
return true;
}
catch
{
tran.Rollback();//事务回滚
return false;
}
finally
{
reader.Close();
//tran.Dispose();
using (SqlCommand dCmd = new SqlCommand())
{
dCmd.Connection = targetConn;
dCmd.CommandText = "DROP TABLE " + tmpTabName; //操作完成删除临时表
dCmd.ExecuteNonQuery();
}
}
}
}
}
} /// <summary>
/// 先清空目标表,再直接插入.
/// </summary>
/// <param name="targetConnStr">目标服务器的连接字符串(已加密的)</param>
/// <param name="targetDBTable">目标服务器中的目标表名称</param>
/// <param name="sourceConnStr">数据获取来源服务器的连接字符串(已加密的)</param>
/// <param name="sourceSqlText">获取数据的SQL语句</param>
/// <param name="columnMap">表结构映射(可留空)</param>
public bool BulkCopyFirstClear(string targetConnStr, string targetDBTable, string sourceConnStr, string sourceSqlText, Dictionary<string, string> columnMap = null)
{
//还原连接字符串
targetConnStr = GetRConnStr(targetConnStr);
sourceConnStr = GetRConnStr(sourceConnStr);
// 源
using (SqlConnection sourceConnection = new SqlConnection(sourceConnStr))
{
SqlCommand myCommand = new SqlCommand(sourceSqlText, sourceConnection);
sourceConnection.Open();
SqlDataReader reader = myCommand.ExecuteReader(); // 目的
using (SqlConnection targetConn = new SqlConnection(targetConnStr))
{
targetConn.Open(); // 打开连接 using (SqlTransaction tran = targetConn.BeginTransaction()) //开始一个事务
{
using (SqlCommand dCommand = new SqlCommand())
{
dCommand.Connection = targetConn;
dCommand.Transaction = tran; //必须指定事务对象
dCommand.CommandText = "TRUNCATE TABLE " + targetDBTable;
dCommand.ExecuteNonQuery();
} using (SqlBulkCopy bulkCopy = new SqlBulkCopy(targetConn, SqlBulkCopyOptions.Default, tran)) //将批量作业加入事务之中
{
if (columnMap != null && columnMap.Count >= )
{
foreach (KeyValuePair<string, string> pair in columnMap)
{
bulkCopy.ColumnMappings.Add(pair.Key, pair.Value);
}
}
bulkCopy.BulkCopyTimeout = ;
bulkCopy.BatchSize = ;
bulkCopy.NotifyAfter = ;
bulkCopy.DestinationTableName = targetDBTable;
bulkCopy.WriteToServer(reader);
} try
{
tran.Commit();//事务提交
return true;
}
catch
{
tran.Rollback();//事务回滚
return false;
}
finally
{
reader.Close();
} } }
}
} #endregion #region 存储过程PROCEDURE作业区域 /// <summary>
/// 执行存储过程,返回存储过程中return的int值
/// </summary>
/// <param name="procName">存储过程名称</param>
/// <param name="paras">SqlParameter[]</param>
/// <returns></returns>
public int RunProcedure(string procName, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = new SqlCommand(procName, conn))
{
cmd.CommandType = CommandType.StoredProcedure; if (paras != null) cmd.Parameters.AddRange(paras); SqlParameter sp = cmd.Parameters.Add("procReturn", SqlDbType.Int);
sp.Direction = ParameterDirection.ReturnValue;
cmd.ExecuteNonQuery();
int pr = Convert.ToInt32(cmd.Parameters["procReturn"].Value);
return pr;
}
}
}
catch (Exception e)
{
throw e;
}
} /// <summary>
/// 执行存储过程,并返回字符串.
/// </summary>
/// <param name="procName">存储过程名称</param>
/// <param name="inputOutputPra">输出参数名称,必须与存储过程中的参数定义相符</param>
/// <param name="paras">参数</param>
/// <returns></returns>
public string ProcToString(string procName, string inputOutputPra, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = new SqlCommand(procName, conn))
{
cmd.CommandType = CommandType.StoredProcedure; if (paras != null) cmd.Parameters.AddRange(paras); SqlParameter sp = cmd.Parameters.Add(inputOutputPra, SqlDbType.NVarChar, );
sp.Direction = ParameterDirection.InputOutput;
cmd.ExecuteNonQuery();
return OString.NZ2Str(cmd.Parameters[inputOutputPra].Value);
}
}
}
catch (Exception ex)
{
return "{error:ProcToString-" + ex.Message + "}";
}
} /// <summary>
/// 执行存储过程,并将第一行第一列作为返回字符串返回.
/// </summary>
/// <param name="procName">存储过程名称</param>
/// <param name="paras">参数</param>
/// <returns></returns>
public string ProcSelToString(string procName, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = new SqlCommand(procName, conn))
{
cmd.CommandType = CommandType.StoredProcedure; if (paras != null) cmd.Parameters.AddRange(paras);
return OString.NZ2Str(cmd.ExecuteScalar());
}
}
}
catch (Exception ex)
{
return "{error:ProcSelToString-" + ex.Message + "}";
}
}
/// <summary>
/// 执行存储过程,并返回DataTable.
/// </summary>
/// <param name="procName">存储过程名称</param>
/// <param name="paras">参数</param>
/// <returns></returns>
public DataTable ProcToDT(string procName, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if (conn.Database != DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = procName;
cmd.CommandType = CommandType.StoredProcedure;
if (paras != null) cmd.Parameters.AddRange(paras);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);
DataSet dataset = new DataSet();
adapter.Fill(dataset);
cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
return dataset.Tables[];
}
}
}
catch (Exception)
{
return null;
}
} /// <summary>
/// 判断记录是否存在(IF EXISTS (查找语句) SELECT 'OK' ELSE SELECT '')
/// <para>当输入的语句错误时,也会返回False</para>
/// </summary>
/// <param name="fltSql">提供查找语句,如SELECT UserID FROM TB20U_User WHERE (UserID = 'uid'),必须返回一个字段</param>
/// <returns></returns>
public bool HasRecord(string fltSql)
{
fltSql = "IF EXISTS (" + fltSql + ") SELECT 'OK' ELSE SELECT ''";
string tmpRst = SqlToString(fltSql);
if (!string.IsNullOrEmpty(tmpRst))
{
if (!(tmpRst.IndexOf("{error:") >= ))
{
return true;
}
else
{
MyMsg.Warning("原始SQL语句执行异常,记录存在性判断可能会存在失误!请联系系统管理员处理。", tmpRst);
return false;
}
}
return false;
} /// <summary>
/// 根据指定查找条件查找记录,没找到则执行新增语句,找到则执行更新语句.
/// </summary>
/// <param name="Sqlsearch">类似Select a from b where 1=1</param>
/// <param name="sqlUpdate">更新语句</param>
/// <param name="sqlInsert">新增语句</param>
/// <returns></returns>
public bool UpdateOrInsert(string Sqlsearch, string sqlUpdate, string sqlInsert)
{
int ret = ;
if (HasRecord(Sqlsearch))
{
ret = RunSql(sqlUpdate);
}
else
{
ret = RunSql(sqlInsert);
}
if (ret > ) return true; else return false;
} /// <summary>
/// 按照指定的数据来源类型获取数据DT
/// </summary>
/// <param name="rcdSourceType">数据类型:SQLTEXT,VIEW,PROC,STRINGARRAY,错误类型将按SQLTEXT处理</param>
/// <param name="rcdSource">数据来源</param>
/// <param name="whereStr">查询字符串</param>
/// <param name="paras">查询字符串中应用到的参数SqlParameter[]</param>
/// <param name="orderByStr">排序表达式(如:A DESC,B)</param>
/// <returns></returns>
public DataTable GetDTBySourceType(string rcdSourceType, string rcdSource, string whereStr, SqlParameter[] paras, string orderByStr = "")
{
rcdSourceType = rcdSourceType.ToUpper();
DataTable dt = new DataTable();
string sqlText = string.Empty;
try
{
switch (rcdSourceType)
{
case "SQLTEXT": //SQL语句,一般应采用视图,性能比较高
sqlText = "SELECT * FROM (" + rcdSource + ") TmpA";
if (!string.IsNullOrEmpty(whereStr))
{
sqlText += " WHERE " + whereStr;
}
if (!string.IsNullOrEmpty(orderByStr))
{
sqlText += " ORDER BY " + orderByStr;
}
dt = SqlToDT(sqlText, paras);
break;
case "VIEW": //视图(用户输入的参数值用于视图查询)
sqlText = "SELECT * FROM " + rcdSource;
if (!string.IsNullOrEmpty(whereStr))
{
sqlText += " WHERE " + whereStr;
}
if (!string.IsNullOrEmpty(orderByStr))
{
sqlText += " ORDER BY " + orderByStr;
}
dt = SqlToDT(sqlText, paras);
break;
case "PROC": //存储过程只能接收参数,不能再附加WHERE条件
dt = ProcToDT(rcdSource, paras);
break;
case "STRINGARRAY": //字符串数组
dt = OString.StringToDT(rcdSource);
break;
default:
sqlText = "SELECT * FROM (" + rcdSource + ") TmpA";
if (!string.IsNullOrEmpty(whereStr))
{
sqlText += " WHERE " + whereStr;
}
if (!string.IsNullOrEmpty(orderByStr))
{
sqlText += " ORDER BY " + orderByStr;
}
dt = SqlToDT(sqlText, paras); break;
}
return dt;
}
catch (Exception)
{
return null;
}
}
#endregion }

DBContext.cs

其中最基础的一个方法:

        public int RunSql(string sqlText, params SqlParameter[] paras)
{
try
{
using (SqlConnection conn = new SqlConnection(ConnStr))
{
conn.Open();
if(conn.Database!=DBName) conn.ChangeDatabase(DBName);//避免架构变更后引起的对象名无效问题
using (SqlCommand cmd = new SqlCommand(sqlText, conn))
{
if (paras != null) cmd.Parameters.AddRange(paras);
int rst = cmd.ExecuteNonQuery();
cmd.Parameters.Clear(); //清除掉参数,如有OUTPUT则不能使用此句
return rst;
}
}
}
catch (Exception ex)
{
MyMsg.Exclamation(ex.Message);
throw ex;
}
}

  

前提是引用 :

using System.Data;
using System.Data.SqlClient;

  关于参数SqlParameter[]的传递:

SqlParameter[] paras = new SqlParameter[]
{
new SqlParameter("@UserID", postUserID),
new SqlParameter("@PasswordHash", postUserPass)
};

然后调用:

RunSql("Select * from Users Where UserID=@UserID,PasswordHash=@PasswordHash", paras);

=========================================

大部分操作都可以通过这个类的方法来直接调用,我们需要的是编写优秀的SQL语句,那是一门更需要钻研的技能。

这个类的实例可以查看上一章登录窗体的代码。

C# Winform下一个热插拔的MIS/MRP/ERP框架12(数据处理基类)的更多相关文章

  1. C# Winform下一个热插拔的MIS/MRP/ERP框架15(窗体基类场景1)

    最基础的窗体基类其实是通过应用场景反推的结构. 以下是场景一: 单表应用,普通的数据,比如单位/颜色/特殊字典等使用者少的,无需过多控制的可以使用一个数据表格来管理. 和Excel表格差不多,批量修改 ...

  2. C# Winform下一个热插拔的MIS/MRP/ERP框架13(窗体基类)

    作为一个ERP数据处理框架,大部分的开发场景都差不多. 理想中,对于通用数据处理,我的步骤如下: 1.为窗体指定数据来源(数据表/查询等): 2.拖入编辑控件,指定绑定字段: 3.结束. 为此,我设计 ...

  3. C# Winform下一个热插拔的MIS/MRP/ERP框架11(启航)

    初学时,有了想法却完全不知道该从何下指,此序列将抛砖引玉,与大家共同学习进步. 一个程序的初始,必然是启动. 我的要求: 1.应用程序保持单例: 2.从配置文件加载一些基础数据进行初始化: 3.显示软 ...

  4. C# Winform下一个热插拔的MIS/MRP/ERP框架(简介)

    Programmer普弱哥们都喜欢玩自己的框架,我也不例外. 理想中,这个框架要易于理解.易于扩展.易于维护:最重要的,易于CODING. 系统是1主体框架+N模组的多个EXE/DLL组成的,在主体框 ...

  5. C# Winform下一个热插拔的MIS/MRP/ERP框架(多语言方案)

    个别时候,我们需要一种多语种切换方案. 我的方案是这样的: 1.使用文本文本存储多语言元素,应用程序启动时加载到内存表中: 2.应用程序启动时从配置文件加载语种定义: 3.所有窗体继承自一个Base基 ...

  6. C# Winform下一个热插拔的MIS/MRP/ERP框架14(自动更新)

    对于软件来说,启用自动更新是非常必要的. 根据软件的应用场景,我们可以设计不同的更新模型. 目前,IMES框架运行在.Net framework 4.0下面,使用的Win系统版本在Win7,域内管控, ...

  7. C# Winform下一个热插拔的MIS/MRP/ERP框架(通用控件)

    一直对商业控件不感冒, 结合日常工作, 我写了几个常用控件. 一.下拉框控件(仿Access下拉框:F4下拉,自动输入,支持单/多列显示),可在Datagridview中使用. 1.常规: 2.Dat ...

  8. C# Winform下一个热插拔的MIS/MRP/ERP框架16(窗体基类场景2)

    如果没有特别需求,和场景1一样只变更表名,主键字段,检测字段等名称,不需要写其它代码了. * 清单列表+单笔编辑/保存,适用于大多数基础资料管理以及简单的单据资料录入(当然,排版是要改一改的): * ...

  9. MFC下一个通用非阻塞的等待执行结束的对话框类

    头文件:CPictureEx用于显示一个等待动画 #pragma once #include "afxwin.h" #include "resource.h" ...

随机推荐

  1. oracle创建表空间、创建用户

    create user user_name identified by user_name create temporary tablespace user_name_temp tempfile '/ ...

  2. Deep Learning 学习笔记(7):神经网络的求解 与 反向传播算法(Back Propagation)

    反向传播算法(Back Propagation): 引言: 在逻辑回归中,我们使用梯度下降法求参数方程的最优解. 这种方法在神经网络中并不能直接使用, 因为神经网络有多层参数(最少两层),(?为何不能 ...

  3. VB.NET使用TagLib#读取MP3中的ID3v2标签

    Taglib#是一个为.NET开发的元数据读取类库,为一个开源项目,可以在他们的官网上获取windows版本的源码包或者编译好的类库:http://download.banshee.fm/taglib ...

  4. 使用Selenium登录新浪微博

    为了总结一下Selenium的用法,具体用了这个例子来说明一下. Selenium简单来说,就是通过程序驱动一个浏览器,并且可以通过程序来帮你做一些事情,例如点击.填表呀之类的. 换句话说,你在浏览器 ...

  5. Swift 添加自定义响应事件

    一,新建一个协议(Protocol) VisitURLProtocol.swift import UIKit protocol VisitURLProtocol{ func didVisitURL(u ...

  6. error: undefined reference to 'av_register_all()'

    cygwin下ndk编译工程中使用ffmpeg时出现的错误:“error: undefined reference to 'av_register_all()'” 使用ffmpeg的源文件是  *.c ...

  7. Hadoop Serialization -- hadoop序列化详解 (3)【ObjectWritable,集合Writable以及自定义的Writable】

    前瞻:本文介绍ObjectWritable,集合Writable以及自定义的Writable TextPair 回顾: 前面了解到hadoop本身支持java的基本类型的序列化,并且提供相应的包装实现 ...

  8. Linux的基本指令--

     VIM简介: Vi有三种基本工作模式 1.命令模式 2.文本输入模式 3. 末行模式 VIM基本操作: 一 . 进入插入模式: i: 插入光标前一个字符 I: 插入行首 a: 插入光标后一个字符 A ...

  9. LoadRunner 关联和集合点、检查点

    1)关联的定义 很多时候,当时录完之后,没有问题.过一段时间再跑脚本,就不会成功.比如session,过期了,再一次使用,就会出错.这个时候,需要在每次访问的时候动态的拿到session,这种情况就需 ...

  10. SpringBoot16 MockMvc的使用、JsonPath的使用、请求参数问题、JsonView、分页查询参数、JsonProperty

    1 MockMvc的使用 利用MockMvc可以快速实现MVC测试 坑01:利用MockMvc进行测试时应用上下文路径是不包含在请求路径中的 1.1 创建一个SpringBoot项目 项目脚手架 1. ...