從零開始編寫自己的C#框架(6)——SubSonic3.0插件介紹(附源碼)


  前面幾章主要是概念性的東西為主,向初學者們介紹項目開始前的一些知識與內容,從本章開始將會進入實操階段,希望跟着本系統學習的朋友認真按說明做好每一步操作(對於代碼最好是直接照着文檔內容在你的IDE中打一次出來,而不是使用復制粘貼),這樣對你理解后面的章節會有較好的幫助,如果你對我這種書寫方式有什么建議或支持,也希望在評論中留言,謝謝你的支持。

 

  SubSonic3.0簡介

  SubSonicRob Conery用c#語言寫的一 個ORM開源框架,使用BSD軟件授權許可(The BSD 3-Clause License)。它是一個實用的快速開發框架,通過非常簡單的配置,以及附帶的T4模板,就可以幫我們生成功能強大的數據訪問層工具,讓開發人員遠離SQL語句的拼接,專注於業務邏輯的開發。

  SubSonic3.0適合短、平、快的中小型項目開發,支持MsSql、MySql與SQLite三種數據庫,支持Linq和支持事務。對數據庫操作靈活,對生成的SQL語句會自動進行優化,雖然是ORM框架,但在性能上並沒有太大的損失。它上手容易,是一個非常棒的ORM開發框架。

  3.0版本最大的缺點是框架未開發完善,對多表關聯查詢支持的不是很好,只支持一個多表關聯條件(復雜的多表關聯只能使用存儲過程或SQL語句拼接方式來實現);條件語句對In與Not In不支持(需要在數據層重新封裝處理才行);如果使用Redis緩存的話,存儲數據時對subsonic3.0生成的實體有兼容問題,需要做一次轉換封裝后才能使用。

  不過總的來說,這些缺點都是可以克服的,在開發效率、二次開發、軟件維護上來說,優點也是非常明顯的,請大家耐心學完本系列,你就能很容易的掌握SubSonic3.0這個開發利器。

 

  SubSonic3.0安裝說明

  SubSonic3.0安裝練習相關附件下載

 

  在MsSql中新建一個數據庫SubSonicTest,並設置好登陸帳號與密碼為SubSonicTest。

  運行下載包里的“SQL語句.txt”文件里的語句,生成數據表、記錄與測試用的存儲過程。

  

 

  創建一個空白解決方案

  

  在解決方案中創建一個空Web應用程序項目

  

  將SubSonic文件夾復制進項目文件夾中

  

  刷新項目就可以看到隱藏的SubSonic文件夾

  

  打開Web.config,添加數據庫鏈接字串

  

  

<connectionStrings>
    <!-- 連接數據庫的字符串 -->
    <add name="procom" connectionString="server=.;Initial Catalog=SubSonicTest;uid=SubSonicTest;pwd=SubSonicTest"/>
  </connectionStrings>
View Code

 

  將Dll和SubSonic.Core復制到解決方案中

  

  添加SubSonic3.0項目(直接使用源碼項目,方便在使用時調試及修改)

  

  

  

  添加SubSonic.Core項目和Castle.Core.dll引用(大神TerryLee的博客里有Castle 開發系列文章 有興趣的朋友可以進去學習一下)

 

  

  

  

 

  將SubSonic包含進項目中

  

  如果你的數據庫名稱、帳號和密碼設置同面前要求一樣的話,T4模板將會直接運行生成相關實體類,如果設置不一樣的,請按下面要求來進行設置

  打開Settings.ttinclude配置文件

  

  

 

  設置好以后,選擇全部T4模板文件,運行生成代碼

  

  

 

  SubSonic3.0模板介紹說明

   本文只介紹附件中SubSonic文件夾模板(MsSql),不適用官方發布的模板

文件名稱 說明
ActiveRecord.tt 按數據表生成對應名稱的類實體(Model),以及支持lambda表達式的各種常用函數(包括增、改、查、刪、Exists等)
Context.tt 生成常用公共模版函數:Select、Insert、Avg、Count、Max、Min、Variance、StandardDeviation、Sum、Delete、GetQuery、Update等
CreateModel.tt  新增模板(原SubSonic3.0沒有這個模板),主要功能是數據表生成對應名稱的類實體(Model),這是普通的類實體,不附任何多余的內容(函數),主要用於存儲到Redis緩存或做C/S接口通訊時轉Json使用。非必須項
EntityTable.tt 新增模板(原SubSonic3.0沒有這個模板,里面的功能從Structs.tt模板中分離出來的),主要功能是可直接獲取數據表名稱與字段名稱,減少開發中硬編碼的存在
Settings.ttinclude 模版參數配置
SQLServer.ttinclude MsSql數據庫讀取、生成的相關配置
StoredProcedures.tt 生成存儲過程調用函數(本模板生成的函數調用存儲過程非常方便,詳情請關注例子)
Structs.tt 生成表結構模版,提供給SubSonic插件調用

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  SubSonic3.0使用例子

  點擊下載本文本例子的解決方案源碼

  之前發布過《SubSonic3.0使用例子》,當時剛開始接觸寫得有點亂,現在重新整理一下,使用上面生成的類來進行操作,可以在項目中直接運行。對於下面的例子,可以直接在解決方案中Debug運行,查看運行結果,以加深理解,當然大部分功能在正式開發中很少使用,所以簡單了解一下就可以了,只要會用Lambda,那么后面相關章節介紹時你就會使用。

  下面例子只適用於本文所附帶的模板,特此說明

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using Solution.DataAccess.DataModel;
using SubSonic.Linq.Structure;
using SubSonic.Query;

namespace SubSonicTest
{
    public partial class Test : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //-------------------------------------------------------------------------------
            // 新增記錄
            //-------------------------------------------------------------------------------
            var branch = new Branch();
            branch.DeptCode = SPs.P_Branch_GetMaxBranchCode(2, 1).ExecuteScalar() + "";
            branch.Name = "客服部";
            branch.Comment = "客戶售后服務維護部門";
            branch.ParentId = 1;
            branch.Sort = 7;
            branch.Depth = 2;
            //AddDate這個屬性不用賦值,ORM框架生成更新語句時會自動過濾該字段,更新時將會使用數據庫中設置的默認值
            //branch.AddDate = DateTime.Now;

            //保存進數據庫
            branch.Save();

            WriteLine("記錄添加成功,新增Id為:" + branch.Id);


            //-------------------------------------------------------------------------------
            // 修改記錄
            //-------------------------------------------------------------------------------
            //從數據庫中讀出剛添加的記錄
            var branchModel = Branch.SingleOrDefault(x => x.Id == branch.Id);
            //也可以用這個
            //var branchModel = new Branch(x => x.Id == branch.Id);
            //打印讀取出來的數據
            WriteLine(branchModel.ToString());

            //修改名稱為“售后服務部”
            branchModel.Name = "售后服務部";
            //保存進數據庫
            branchModel.Save();

            //重新從數據庫中讀取出來並打印到輸出窗口
            WriteLine((new Branch(x => x.Id == branch.Id)).ToString());


            //-------------------------------------------------------------------------------
            // 判斷剛剛修改的記錄是否存在
            //-------------------------------------------------------------------------------
            if (Branch.Exists(x => x.Id == branch.Id))
            {
                WriteLine("Id為" + branch.Id + "的記錄存在!");
            }
            else
            {
                WriteLine("Id為" + branch.Id + "的記錄不存在!");
            }



            //-------------------------------------------------------------------------------
            // 刪除記錄
            //-------------------------------------------------------------------------------
            //刪除當前記錄
            Branch.Delete(x => x.Id == branch.Id);
            //也可以使用這種方法刪除
            //branchModel.Delete(); 
            WriteLine("刪除Id為" + branch.Id + "的記錄成功!");
            //除了上面兩種刪除方法外,還有好幾種其它方法,不過都不常用,這里就不詳細羅列出來,大家如果有興趣可以查看我之前發布的博客


            //-------------------------------------------------------------------------------
            // 判斷剛剛刪除的記錄是否存在
            //-------------------------------------------------------------------------------
            if (Branch.Exists(x => x.Id == branch.Id))
            {
                WriteLine("Id為" + branch.Id + "的記錄存在!");
            }
            else
            {
                WriteLine("Id為" + branch.Id + "的記錄不存在!");
            }






            //-------------------------------------------------------------------------------
            // 使用類實體附帶的函數查詢
            //-------------------------------------------------------------------------------
            //查找出所有記錄——使用All()
            var list = Branch.All();
            foreach (var tem in list)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }


            //查詢指定條件的記錄——使用Find()
            IList<Branch> il = Branch.Find(x => x.Id > 0);
            foreach (var tem in il)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }


            //獲取第2頁記錄(每頁3條記錄)
            il = Branch.GetPaged("Id Desc", 2, 3);
            foreach (var tem in il)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }


            //使用Id倒序排序,獲取第3頁記錄(每頁3條記錄)
            il = Branch.GetPaged("Id Desc", 3, 3);
            foreach (var tem in il)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }



            //-------------------------------------------------------------------------------
            // 使用Select類查詢
            //-------------------------------------------------------------------------------
            //創建Select對象
            //var select = new Select();
            //顯示指定的列
            var select = new Select(new string[] { BranchTable.Id, BranchTable.Name, BranchTable.DeptCode });
            //指定查詢表
            select.From<Branch>();


            //運行完上面這條語句后,SQL已經生成出來了,大家在Debug狀態將鼠標指向select就可以看到,往下繼續執行時,每添加一個屬性都會添加在生成的SQL語句中


            //添加查詢條件——Id大於2且編號頭兩位為01的部門
            select.Where(BranchTable.Id).IsGreaterThanOrEqualTo(2).And(BranchTable.DeptCode).StartsWith("01");
            //查詢時括號添加例子
            //select.Openexpression_r().Where("").IsEqualTo(0).Or("").IsEqualTo(11).Closeexpression_r().And("").IsEqualTo(3);

            //設置去重復——SubSonic沒有去重復選項,需要自己手動修改Dll源碼
            select.Distinct(true);
            ////select.IsDistinct = true;

            //設置查詢數量
            select.Top("5");

            //添加排序——倒序
            select.OrderDesc(BranchTable.Sort);
            ////List<string> orderbyList = new List<string>();
            //orderbyList.Add(BranchTable.Sort + " Desc");
            //orderbyList.Add(BranchTable.Id + " Desc");
            //select.OrderBys = orderbyList;

            //設置分頁,獲取第一頁記錄(每頁10條記錄)
            select.Paged(1, 10);


            //執行查詢——返回DataTable
            var dt = select.ExecuteDataTable();
            if (dt != null && dt.Rows.Count > 0)
            {
                for (int i = 0; i < dt.Rows.Count; i++)
                {
                    //打印到輸出窗口
                    WriteLine(dt.Rows[i][BranchTable.Id] + " " + dt.Rows[i][BranchTable.Name]);
                }
            }

            //執行查詢——返回List
            var bl = select.ToList<Branch>();
            foreach (var tem in bl)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }


            //查詢總記錄數
            var recordCount = select.GetRecordCount();
            //打印到輸出窗口
            WriteLine("記錄數量:" + recordCount.ToString());

            //select提供了很多接口,可以返回很多不同的數據,具體大家可以根據需求來獲取
            //Select與SqlQuery 主要用於條件等屬性不確定時拼接查詢,如果大家需要使用相關內容,可以留意后面的章節源碼,我已將相關的功能封裝到一些類中了,大家可以直接調用




            //-------------------------------------------------------------------------------
            // HotelDBDB查詢類的使用方式
            //-------------------------------------------------------------------------------
            //使用數據庫名稱+DB作為名稱的類,可以直接調用聚合函數
            var db = new SubSonicTestDB();
            //平均值
            WriteLine("平均值:" + db.Avg<Branch>(x => x.Id).Where<Branch>(x => x.Id < 10).ExecuteScalar() + "");
            //計算數量
            WriteLine("計算數量:" + db.Count<Branch>(x => x.Id).ExecuteScalar() + "");
            //計算合計數量
            WriteLine("計算合計數量:" + db.Sum<Branch>(x => x.Id).ExecuteScalar() + "");

            //最大值
            WriteLine("最大值:" + db.Max<Branch>(x => x.Id).ExecuteScalar() + "");
            //最小值
            WriteLine("最小值:" + db.Min<Branch>(x => x.Id).ExecuteScalar() + "");


            //-------------------------------------------------------------------------------
            // 存儲過程調用方法
            //-------------------------------------------------------------------------------
            //使用SPs.存儲過程名稱(參數1, 參數2, 參數3);就可以調用存儲過程
            var obj = SPs.P_Branch_GetMaxBranchCode(1, 0).ExecuteScalar();
            WriteLine(obj + "");
            //可根據存儲過程返回的數據,調用不同的Execute來獲取
            //大家試試在SPs.P_Branch_GetMaxBranchCode(1, 2)后面.一下,就可以看到很多調用接口,使用對應的接口可以返回不同的內容





            //-------------------------------------------------------------------------------
            // 直接執行QueryCommand的方式
            //-------------------------------------------------------------------------------
            //獲取數據源——主要用於綁定連接的服務器,如果有多台服務器多個數據庫時,可使用不同的數據源來進行綁定查找
            var provider = SubSonic.DataProviders.ProviderFactory.GetProvider();
            //定義事務,給后面的事務調用
            var batch = new BatchQuery(provider);

            var sql = string.Format("select * from {0}", BranchTable.TableName);
            //例一,獲取影響記錄數
            QueryCommand qcommand = new QueryCommand(sql, provider);
            WriteLine(qcommand.Provider.ExecuteQuery(qcommand) + "");

            //例二,獲取DataTable
            var q = new SubSonic.Query.QueryCommand(sql, provider);
            var table = q.Provider.ExecuteDataSet(q).Tables[0];
            if (dt != null && table.Rows.Count > 0)
            {
                for (int i = 0; i < table.Rows.Count; i++)
                {
                    //打印到輸出窗口
                    WriteLine(table.Rows[i][BranchTable.Id] + " " + table.Rows[i][BranchTable.Name]);
                }
            }


            //例三,使用事務執行
            batch.QueueForTransaction(qcommand);
            batch.ExecuteTransaction();


            //例四,直接使用數據源執行
            provider.ExecuteQuery(qcommand);
            //-------------------------------------------------------------------------------



            //-------------------------------------------------------------------------------
            // Linq查詢方式
            //-------------------------------------------------------------------------------
            //Linq查詢方式
            var query = new Query<Branch>(db.Provider);
            var posts = from p in query
                        where p.DeptCode.StartsWith("0101")
                        select p;
            foreach (var tem in posts)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }



            query = db.GetQuery<Branch>();
            posts = from p in query
                    where p.Id > 3 && p.Id < 6
                    select p;

            //獲取查詢結果1
            foreach (var tem in posts)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }


            //獲取查詢結果2
            List<Branch> li2 = query.ToList<Branch>();
            foreach (var tem in li2)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }


            //-------------------------------------------------------------------------------
            // Linq多表關聯查詢方法
            //-------------------------------------------------------------------------------
            //方法一
            var query5 = from p in Position.All()
                         join b in Branch.All() on p.Branch_Id equals b.Id
                         where b.DeptCode == "0101"
                         select p;
            foreach (var tem in query5)
            {
                //打印到輸出窗口
                WriteLine(tem.ToString());
            }


            //方法二
            var qry = (from p in db.Position
                       join b in db.Branch on p.Branch_Id equals b.Id
                       where b.DeptCode == "0101"
                       select new ListView
                          {
                              PositionName = p.Name,
                              BranchName = p.Branch_Name,
                              DeptCode = b.DeptCode
                          });


            foreach (var view in qry)
            {
                WriteLine(view.ToString());
            }




            //-------------------------------------------------------------------------------
            // 使用事務
            //-------------------------------------------------------------------------------
            //例一
            //從部門表中查詢出編號為0102的Id、名稱與說明三列
            var query1 = new SubSonic.Query.Select(provider, BranchTable.Id, BranchTable.Name, BranchTable.Comment).From(BranchTable.TableName).Where<Branch>(x => x.DeptCode == "0102");
            //加入事務
            batch.QueueForTransaction(query1);

            //查詢部門編號為0102且職位名稱后面兩個字為主管的所有職位
            var query2 = new SubSonic.Query.Select(provider).From<Position>().Where<Position>(x => x.Branch_DeptCode == "0102").And(PositionTable.Name).EndsWith("主管");
            //加入事務
            batch.QueueForTransaction(query2);
            //運行事務,不返回任何信息
            batch.ExecuteTransaction();

            //例二
            batch = new BatchQuery();
            batch.Queue(query1);
            batch.Queue(query2);
            //執行事務,並返回數據
            using (IDataReader rdr = batch.ExecuteReader())
            {
                if (rdr.Read())
                {
                    //query1 results
                    for (int i = 0; i < rdr.FieldCount; i++)
                    {
                        WriteLine(rdr[i] + "");
                    }
                }
                //rdr.MoveNext();
                rdr.NextResult();
                if (rdr.Read())
                {
                    //query2 results
                    for (int i = 0; i < rdr.FieldCount; i++)
                    {
                        WriteLine(rdr[i] + "");
                    }
                }
            }



            //例三
            batch = new BatchQuery(provider);

            var query3 = from p in db.Branch
                         where
                            p.Id > 1 && p.Id < 10
                         select p;
            batch.Queue(query3);

            var query4 = from p in db.Position
                         where p.Branch_DeptCode == "0103"
                         select p;
            batch.Queue(query4);
            //執行事務,並返回數據
            using (var rdr = batch.ExecuteReader())
            {
                if (rdr.Read())
                {
                    //query1 results
                    for (int i = 0; i < rdr.FieldCount; i++)
                    {
                        WriteLine(rdr[i] + "");
                    }
                }
                //rdr.MoveNext();
                rdr.NextResult();
                if (rdr.Read())
                {
                    //query2 results
                    for (int i = 0; i < rdr.FieldCount; i++)
                    {
                        WriteLine(rdr[i] + "");
                    }
                }
            }


        }




        /// <summary>
        /// DeBug時,在輸出窗口打印出指定內容
        /// </summary>
        /// <param name="str">要在輸出窗口顯示的內容</param>
        private void WriteLine(string str)
        {
            System.Diagnostics.Debug.WriteLine(str);
        }


        //內部類
        class ListView
        {
            public string PositionName { get; set; }

            public string BranchName { get; set; }

            public string DeptCode { get; set; }

            public string ToString()
            {
                StringBuilder sb = new StringBuilder();
                sb.Append("PositionName = " + PositionName + "\r\n");
                sb.Append("BranchName = " + BranchName + "\r\n");
                sb.Append("DeptCode = " + DeptCode + "\r\n");

                return sb.ToString();
            }
        }
    }
}
View Code

 

 

 

 

 版權聲明:

  本文由AllEmpty原創並發布於博客園,歡迎轉載,未經本人同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,否則保留追究法律責任的權利。如有問題,可以通過1654937@qq.com 聯系我,非常感謝。

  發表本編內容,只要主為了和大家共同學習共同進步,有興趣的朋友可以加加Q群:327360708 或Email給我(1654937@qq.com),大家一起探討。

  更多內容,敬請觀注博客:http://www.cnblogs.com/EmptyFS/

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM