前面几章主要是概念性的东西为主,向初学者们介绍项目开始前的一些知识与内容,从本章开始将会进入实操阶段,希望跟着本系统学习的朋友认真按说明做好每一步操作(对于代码最好是直接照着文档内容在你的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>

  将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(, ).ExecuteScalar() + "";
branch.Name = "客服部";
branch.Comment = "客户售后服务维护部门";
branch.ParentId = ;
branch.Sort = ;
branch.Depth = ;
//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 > );
foreach (var tem in il)
{
//打印到输出窗口
WriteLine(tem.ToString());
} //获取第2页记录(每页3条记录)
il = Branch.GetPaged("Id Desc", , );
foreach (var tem in il)
{
//打印到输出窗口
WriteLine(tem.ToString());
} //使用Id倒序排序,获取第3页记录(每页3条记录)
il = Branch.GetPaged("Id Desc", , );
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().And(BranchTable.DeptCode).StartsWith("");
//查询时括号添加例子
//select.Openexpression_r().Where("").IsEqualTo(0).Or("").IsEqualTo(11).Closeexpression_r().And("").IsEqualTo(3); //设置去重复——SubSonic没有去重复选项,需要自己手动修改Dll源码
select.Distinct(true);
//或
//select.IsDistinct = true; //设置查询数量
select.Top(""); //添加排序——倒序
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(, ); //执行查询——返回DataTable
var dt = select.ExecuteDataTable();
if (dt != null && dt.Rows.Count > )
{
for (int i = ; 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 < ).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(, ).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[];
if (dt != null && table.Rows.Count > )
{
for (int i = ; 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("")
select p;
foreach (var tem in posts)
{
//打印到输出窗口
WriteLine(tem.ToString());
} query = db.GetQuery<Branch>();
posts = from p in query
where p.Id > && p.Id <
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 == ""
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 == ""
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 == "");
//加入事务
batch.QueueForTransaction(query1); //查询部门编号为0102且职位名称后面两个字为主管的所有职位
var query2 = new SubSonic.Query.Select(provider).From<Position>().Where<Position>(x => x.Branch_DeptCode == "").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 = ; i < rdr.FieldCount; i++)
{
WriteLine(rdr[i] + "");
}
}
//rdr.MoveNext();
rdr.NextResult();
if (rdr.Read())
{
//query2 results
for (int i = ; i < rdr.FieldCount; i++)
{
WriteLine(rdr[i] + "");
}
}
} //例三
batch = new BatchQuery(provider); var query3 = from p in db.Branch
where
p.Id > && p.Id <
select p;
batch.Queue(query3); var query4 = from p in db.Position
where p.Branch_DeptCode == ""
select p;
batch.Queue(query4);
//执行事务,并返回数据
using (var rdr = batch.ExecuteReader())
{
if (rdr.Read())
{
//query1 results
for (int i = ; i < rdr.FieldCount; i++)
{
WriteLine(rdr[i] + "");
}
}
//rdr.MoveNext();
rdr.NextResult();
if (rdr.Read())
{
//query2 results
for (int i = ; 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();
}
}
}
}

 版权声明:

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

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

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

从零开始编写自己的C#框架(6)——SubSonic3.0插件介绍(附源码)的更多相关文章

  1. 基于netty框架的轻量级RPC实现(附源码)

    前言 Rpc( Remote procedure call):是一种请求 - 响应协议.RPC由客户端启动,客户端向已知的远程服务器发送请求消息,以使用提供的参数执行指定的过程.远程服务器向客户端发送 ...

  2. 从零开始编写自己的C#框架(1)——前言

    记得十五年前自学编程时,拿着C语言厚厚的书,想要上机都不知道要用什么编译器来执行书中的例子.十二年前在大学自学ASP时,由于身边没有一位同学和朋友学习这种语言,也只能整天混在图收馆里拼命的啃书.而再后 ...

  3. 从零开始编写自己的C#框架 ---- 系列文章

    目录: 从零开始编写自己的C#框架(1)——前言从零开始编写自己的C#框架(2)——开发前的准备工作从零开始编写自己的C#框架(3)——开发规范从零开始编写自己的C#框架(4)——文档编写说明从零开始 ...

  4. 从零开始编写自己的C#框架(26)——小结

    一直想写个总结,不过实在太忙了,所以一直拖啊拖啊,拖到现在,不过也好,有了这段时间的沉淀,发现自己又有了小小的进步.哈哈...... 原想框架开发的相关开发步骤.文档.代码.功能.部署等都简单的讲过了 ...

  5. 从零开始编写自己的C#框架(20)——框架异常处理及日志记录

    最近很忙,杂事也多,所以开发本框架也是断断续续的,终于在前两天将前面设定的功能都基本完成了,剩下一些小功能遗漏的以后发现再补上.接下来的章节主要都是讲解在本框架的基础上进行开发的小巧. 本框架主要有四 ...

  6. 从零开始编写自己的C#框架(17)——Web层后端首页

    后端首页是管理员登陆后进入的第一个页面,主要是显示当前登陆用户信息.在线人数.菜单树列表.相关功能按键和系统介绍.让管理员能更方便的找到息想要的内容. 根据不同系统的需要,首页会显示不同的内容,比如显 ...

  7. 从零开始编写自己的C#框架(11)——创建解决方案

    这段时间一直在充电,拜读了园子中大神们的博文(wayfarer的<设计之道>.TerryLee的<.NET设计模式系列文章>.卡奴达摩的<设计模式>还有其他一些零散 ...

  8. 从零开始编写自己的C#框架(2)——开发前准备工作

    没想到写了个前言就受到很多朋友的支持,大家的推荐就是我最大的动力(推荐得我热血沸腾,大家就用推荐来猛砸我吧O^-^O),谢谢大家支持. 其实框架开发大家都知道,不过要想写得通俗点,我个人觉得还是挺吃力 ...

  9. 从零开始编写自己的C#框架(9)——数据库设计与创建

    对于千万级与百万级数据库设计是有所区别的,由于本项目是基于中小型软件开发框架来设计,记录量相对会比较少,所以数据库设计时考虑的角度是:与开发相结合:空间换性能:空间换开发效率:减少null异常.... ...

随机推荐

  1. Redis安装配置(Windows版)

    近期项目中引入Redis,故记录下来,方便日后查看. 可参考(http://www.cnblogs.com/happyday56/p/3916388.html)不说废话,直奔主题. 一.安装前的准备: ...

  2. iOS8沙盒路径的变化

    iOS8中的的沙盒路径发生了变化 之前是这样的路径,通过NSHomedictionary()获取的家路径 /Users/wupeng/Library/Application Support/iPhon ...

  3. Jenkins部署配置简介

    前段时间研究了一下自动化测试,因而接触到了Jenkins,今天有时间进行一下Jenkins部署配置相关知识的总结分享 前言:由于本次只是实验性研究,采用Windows环境,因此Jenkins可以通过下 ...

  4. 加载跨域的HTML页面AJAX

    //下面是谷歌浏览器处理方式,微信端,直接使用微信链接不作处理,,火狐浏览器另行处理... 借鉴地址:http://stackoverflow.com/questions/15005500/loadi ...

  5. Expert 诊断优化系列------------------内存不够用么?

    现在很多用户被数据库的慢的问题所困扰,又苦于花钱请一个专业的DBA成本太高.软件维护人员对数据库的了解又不是那么深入,所以导致问题迟迟不能解决,或只能暂时解决不能得到根治.开发人员解决数据问题基本又是 ...

  6. Lesson 13 The Greenwood Boys

    Text The Greenwood Boys are group of pop singers. At present, they are visiting all parts of the cou ...

  7. 删除Mysql数据表中多余的重复记录的sql语句

    数据表 sniper_tb 中存在主键 id,字段url,现需要在url字段上添加 unique,但由于url存在重复记录,导致添加失败. 如何删除表中多余的url重复记录,仅保持一条? 思路一 将 ...

  8. .NET中提升UAC权限的方法总结

    [题外话] 从Vista开始,由于增加了UAC(用户账户控制,User Account Control)功能,使得管理员用户平时不再拥有能控制所有功能的管理员权限了,所以在调用很多比较重要的功能时需要 ...

  9. ASP.NET MVC 过滤器(五)

    ASP.NET MVC 过滤器(五) 前言 上篇对了行为过滤器的使用做了讲解,如果在控制器行为的执行中遇到了异常怎么办呢?没关系,还好框架给我们提供了异常过滤器,在本篇中将会对异常过滤器的使用做一个大 ...

  10. .NET组件程序设计之线程、并发管理(二)

    .Net组件程序设计之线程.并发管理(二) 2.同步线程 手动同步 监视器 互斥 可等待事件 同步线程 所有的.NET组件都支持在多线程的环境中运行,可以被多个线程并发访问,如果没有线程同步,这样的后 ...