C# Winform下一個熱插拔的MIS/MRP/ERP框架12(數據處理基類)

做爲ERP等數據應用程序,數據庫的處理是重中之重。sql

在框架中,我封裝了一個數據庫的基類,在每一個模組啓動或窗體啓動過程當中,實例化一個基類便可調用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:")>=0 && ConnStr.IndexOf("FastCheckPort:") >= 0)
                {
                    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>0 && fastCheckTimeOut>0)
                    {
                        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 = 0)
        {
            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 > 30) cmd.CommandTimeout = cmdTimeOut;
                            //開始
                            if (dicSqls != null && dicSqls.Count >= 0)
                            {
                                foreach (KeyValuePair<string, SqlParameter[]> sqls in dicSqls)
                                {
                                    int m = sqls.Key.IndexOf("||||||");
                                    if (m >= 0)
                                    {
                                        cmd.CommandText = sqls.Key.Substring(m + 6);
                                    }
                                    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 0;
                        }
                        catch
                        {
                            tran.Rollback();//事務回滾
                            return -1;
                        }
                        finally
                        {
                        }
                    }//事務結束
                }
            }
            catch (Exception ex)
            {
                MyMsg.Exclamation(ex.Message);
                return -1;
            }
        }
        /// <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 = 0)
        {
            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 > 30) cmd.CommandTimeout = cmdTimeOut;  //設置一個超時時間,需時過長的應該放在存儲過程當中處理
                            //開始
                            if (dicSqls != null && dicSqls.Count >= 0)
                            {
                                object tmpO = null;
                                int runRstRows = 0;
                                foreach (KeyValuePair<string, SqlParameter[]> sqls in dicSqls)
                                {
                                    int m = sqls.Key.IndexOf("||||||");
                                    if (m >= 0)
                                    {
                                        rtnValue = sqls.Key.Substring(0, m);
                                        cmd.CommandText = sqls.Key.Substring(m + 6);
                                    }
                                    else
                                    {
                                        rtnValue = "未指定的做業";
                                        cmd.CommandText = sqls.Key;
                                    }
                                    cmd.Parameters.Clear();
                                    if (sqls.Value != null) cmd.Parameters.AddRange(sqls.Value);
                                    if (cmd.CommandText.Trim().Substring(0, 6) == "SELECT")
                                    {
                                        tmpO = cmd.ExecuteScalar();
                                        if (tmpO == null)
                                        {
                                            tran.Rollback();//事務回滾
                                            return "{error:RunSeqSqlsInTran-" + rtnValue + "}";
                                        }
                                    }
                                    else
                                    {
                                        runRstRows = cmd.ExecuteNonQuery();
                                        if (runRstRows <= 0)
                                        {
                                            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[0].Clear();    //先清除再填充,若有創建主從關聯的會出錯,可在調用端先處理清除.
                            adapter.Fill(tagDS.Tables[0]);
                        }
                        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[0];
                    }
                }
            }
            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[0];
                        if (DTTmp == null) return null;
                        if (DTTmp.Rows.Count < 1) return null;
                        return DTTmp.Rows[0];
                    }
                }
            }
            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 >= 0)
                            {
                                foreach (KeyValuePair<string, string> pair in columnMap)
                                {
                                    bulkCopy.ColumnMappings.Add(pair.Key, pair.Value);
                                }
                            }
                            bulkCopy.BulkCopyTimeout = 0;
                            bulkCopy.BatchSize = 5000;
                            bulkCopy.NotifyAfter = 100000;
                            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 >= 0)
                        {
                            foreach (KeyValuePair<string, string> pair in columnMap)
                            {
                                bulkCopy.ColumnMappings.Add(pair.Key, pair.Value);
                            }
                        }
                        bulkCopy.BulkCopyTimeout = 0;
                        bulkCopy.BatchSize = 800;
                        bulkCopy.NotifyAfter = 80000;
                        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 >= 0)
                            {

                                foreach (KeyValuePair<string, string> pair in columnMap)
                                {
                                    bulkCopy.ColumnMappings.Add(pair.Key, pair.Value);
                                    columnsList += pair.Value + ",";
                                }
                                columnsList = columnsList.Substring(0, columnsList.Length - 1);
                            }
                            bulkCopy.BulkCopyTimeout = 0;
                            bulkCopy.BatchSize = 800;
                            bulkCopy.NotifyAfter = 80000;
                            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 >= 0)
                            {
                                foreach (KeyValuePair<string, string> pair in columnMap)
                                {
                                    bulkCopy.ColumnMappings.Add(pair.Key, pair.Value);
                                }
                            }
                            bulkCopy.BulkCopyTimeout = 0;
                            bulkCopy.BatchSize = 800;
                            bulkCopy.NotifyAfter = 80000;
                            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, 4000);
                        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[0];
                    }
                }
            }
            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:") >= 0))
                {
                    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 = 0;
            if (HasRecord(Sqlsearch))
            {
                ret = RunSql(sqlUpdate);
            }
            else
            {
                ret = RunSql(sqlInsert);
            }
            if (ret > 0) 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;
            }
        }

  

前提是引用 :app

using System.Data;
using System.Data.SqlClient;框架

  關於參數SqlParameter[]的傳遞:ide

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

而後調用:性能

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

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

大部分操做均可以經過這個類的方法來直接調用,咱們須要的是編寫優秀的SQL語句,那是一門更須要鑽研的技能。

這個類的實例能夠查看上一章登陸窗體的代碼。

相關文章
相關標籤/搜索