• 从零开始编写自己的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 + "
    ");
                    sb.Append("BranchName = " + BranchName + "
    ");
                    sb.Append("DeptCode = " + DeptCode + "
    ");
    
                    return sb.ToString();
                }
            }
        }
    }
    View Code

    版权声明:
      本文由AllEmpty原创并发布于博客园,欢迎转载,未经本人同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。如有问题,可以通过1654937@qq.com 联系我,非常感谢。

      发表本编内容,只要主为了和大家共同学习共同进步,有兴趣的朋友可以加加Q群:327360708 或Email给我(1654937@qq.com),大家一起探讨。

      更多内容,敬请观注博客:http://www.cnblogs.com/EmptyFS/

    只有将自己置空,才能装进更多的东西
  • 相关阅读:
    Node.js安装及环境配置之Windows篇
    C++ STL中Map的按Key排序和按Value排序
    设计模式之观察者模式(c++)
    C/C++回调函数
    c++ string详解 assign
    C++ unsigned long 转化为 unsigned char*
    unsigned char 与unsigned long互换
    微信小程序的登陆流程详解
    谷歌帮:中国最牛的创业帮派
    创业公司打造顶级团队的七个方法
  • 原文地址:https://www.cnblogs.com/FinleyJiang/p/7600727.html
Copyright © 2020-2023  润新知