SmartPersistenceLayer 3 快速入门
前言
SmartPersistenceLayer ( SPL )自在博客园发布开始,就一直受到广大朋友的认可,那一套 SPL 的系列文档对 SPL 的使用与功能以及原理都作了充分的介绍,而这些系列文章有利于大家理解 SPL 的思想,将作为一个优秀的 .NET 系统框架持久层。
而那些文章由于比较分散,而且论述了一些架构思想,对一些初学者感觉有些困难,也应大家的要求,写一份简单的,实用的 SPL 应用手册,所以我接下来从实际场景模拟开发。
一、 引用
SPL 的发布形式是一个名为 PersistenceLayer.Dll 的 DLL 文件 , 可以在我的 BLOG(http://www.cnblogs.com/tintown/ ) 上下载,因此只需要在项目中“添加引用”即可:
若要使用 ODP.NET 连接 Oracle 数据库,则用以上方式添加 Oracle.DataAccess.dll
若要使用 SPL 连接 MySql 数据库,则用以上方式添加 MySql.Data.dll
二、 配置文件与实体类
SPL 的配置文件与实体类可以使用我提供的 SmartRobot 进行生成,这可以大大加快开发效率,但工具毕竟是工具,不属于 SPL 持久层的必选部分。
连接数据库:
目前 SmartRobot 支持 Ms Sql Server 、 Ms Access 、 Oracle 数据库,如果是其他数据库只能只好手写实体类了或者等我升级喽 ;)
确定好要生成的实体类存放的地址,到时生成时会生成到相应的目录里。
配置每个表对应的实体类属性,默认实体类名称为“表名”加“ Entity ”字符,属性名默认与列名相同,上图中的“ 2 ”“ 3 ”操作对每个表都要重复一次的。
这时就会生成勾上的实体类到指定的目录下了。只要把指定的实体类引用到项目中即可,实体类默认使用的是 BusinessEntity 命名空间。因此在开发时,只要用到实体类的地方使用: using BusinessEntity 就可以了。
保存两个配置文件,放到你的项目中: ClassMap.xml 与 DatabaseMap.xml
ClassMap.xml 为数据库表与实体类的映射关系
DatabaseMap.xml 为数据库连接配置:
Ms Sql Server 例如下:
< database name ="Northwind" type ="MsSqlServer">
< parameter name ="Provider" value ="SQLOLEDB.1" />
< parameter name ="Password" value ="tintown" />
< parameter name ="Initial Catalog" value ="Northwind" />
< parameter name ="User ID" value ="sa" />
< parameter name ="Data Source" value ="(local)" />
< classMapFile path ="ClassMap.xml" />
</ database >
Ms Access 例如下:
< database name ="DMBCN" type ="MsAccess">
< parameter name ="Provider" value ="Microsoft.Jet.OLEDB.4.0" />
< parameter name ="Data Source" value ="dmbcn.mdb" />
< classMapFile path ="ClassMap.xml" />
</ database >
Oracle 例如下:
< database name ="EDI" type ="Oracle">
< parameter name ="Provider" value ="MSDAORA.1" />
< parameter name ="Password" value ="tintown" />
< parameter name ="User ID" value ="EDI" />
< parameter name ="Data Source" value ="EDI.LIHINSOFT.COM" />
< classMapFile path ="ClassMap.xml" />
</ database >
ODP.NET 方式连接Oracle 例如下:
< database name ="Acci2004" type ="ODP">
< parameter name ="Password" value ="tintown" />
< parameter name ="User ID" value ="acci" />
< parameter name ="Data Source" value ="oradb" />
< parameter name ="Persist Security Info" value ="False" />
< classMapFile path ="ClassMap.config" />
</ database >
MySql 数据库例如下:
< database name ="MySql" type ="MySql">
< parameter name ="User Id" value ="root"/>
< parameter name ="Data Source" value ="localhost"/>
< parameter name ="Database" value ="mysql"/>
< parameter name ="password" value ="tintown"/>
< classMapFile path ="ClassMap.xml" />
</ database >
ClassMap.xml 的地址是相对于 DatabaseMap.xml 地址的,象例子中都是放在同一目录下,所以直接使用文件名即可 .
如果是连接多数据库,则可以配置多个 <database> 节 如:
<? xml version ="1.0" encoding ="utf-8"?>< map >
< database name ="Northwind" type ="MsSqlServer">
< parameter name ="Provider" value ="SQLOLEDB.1" />
< parameter name ="Password" value ="tintown" />
< parameter name ="Initial Catalog" value ="Northwind" />
< parameter name ="User ID" value ="sa" />
< parameter name ="Data Source" value ="(local)" />
< classMapFile path ="ClassMap.xml" />
</ database >
< database name ="MySql" type ="MySql">
< parameter name ="User Id" value ="root"/>
< parameter name ="Data Source" value ="localhost"/>
< parameter name ="Database" value ="mysql"/>
< parameter name ="password" value ="tintown"/>
< classMapFile path ="ClassMap2.xml" />
</ database >
</ map >
所示为同时连接Ms Sql Server 数据库与MySql 数据库
三、 初始化数据连接
在页面的 Page_Onload 中使用如下进行初始化 ( 假设 DatabaseMap.xml 放在 Config 目录下 ) :
string DatabaseXml="Config/DatabaseMap.xml";
PersistenceLayer.Setting.Instance().DatabaseMapFile=Server.MapPath(DatabaseXml);
以上的初始化只需要执行一次即会放在应用项目中,但 Web 会经常性的丢失 Application ,导致初始信息丢失,因此在每次执行数据库操作前都最好能进行初始化。
建议大家可以放在 BasePage 中 , 采用 Appliction 进行控制:
if (Application["DatabaseSetting"]==null || Application["DatabaseSetting"].ToString()!="Y")
{
string DatabaseXml="Config/DatabaseMap.xml";
PersistenceLayer.Setting.Instance().DatabaseMapFile=Server.MapPath(DatabaseXml); Application["DatabaseSetting"]="Y";
}
因为生成的实体类都是在BusinessEntity 命名空间下的,所以在要使用数据库访问的页面上加上:
Using PersistenceLayer;
Using BusinessEntity;
就可以直接使用SPL 的类与实体类了。
好了,非常简单,现在就可以开始体验 SPL 了。
四、 开发
假设我们目前有订单对象 SaleOrder( 字段名与属性名相同 ) :
字段名 | 类型 | 描述 |
Id | Varchar(50) | GUID 主键 |
No | Varchar(50) | 订单编号 |
CustomId | Varchar(50) | 客户 ID |
CreateDate | DateTime | 下单日期 |
|
|
|
订单明细对象 SaleOrderDetail( 字段名与属性名相同 ) :
Id | Varchar(50) | GUID 主键 |
OrderId | Varchar(50) | 订单的 ID (外键) |
ProductId | Varchar(50) | 产品 ID( 外键 ) |
Quantity | Int | 需求数量 |
Price | Decimal | 单价 |
Amount | Decimal | 小计 |
以下为模拟情况:
1) 在界面上选择了客户,并在 Grid 里选择了产品并输入了单价与数量,生成新订单:
Transaction t=new Transaction(); // 这肯定是要使用事务处理了
SaleOrderEntity Soe=new SaleOrderEntity();
Soe.Id=Guid.NewGuid().ToString(); // 生成新 GUID
Soe.No=this.txtNo.Text; // 取文本框里值
Soe.CustomId=this.ddlCustom.SelectedValue; // 取界面上客户下拉框里值
Soe.CreateDate=System.DateTime.Now; // 取当前日期
t.AddSaveObject(Soe); // 把订单主档加到事务中
for(int i=0;i<this.Grid.Rows.Count;i++) // 编历整个 Gruid 生成一条条明细保存
{
SaleOrderDetailEntity Sode=new SaleOrderDetailEntity();
Sode.Id=Guid.NewGuid().ToString();// 生成新的 GUID
Sode.OrderId=Soe.Id; // 取订单主档的 GUID
Sode.ProductId=…// 从 Grid 上取商品 ID 值
Sode.Quantity= // 从 Grid 上取商品数量值
Sode.Price=… // 从 Grid 上取商品单价值
Sode.Amount=Sode.Quantity*Sode.Price; // 汇总小计
t.AddSaveObject(Sode); // 把订单明细对象加到事务中
}
t.Process(); // 事务提交即可
2) 在查询界面要根据订单编号、订单时间段、客户进行综合查询
RetrieveCriteria rc=New RetrieveCriteria(typeof(SaleOrderEntity)); // 创建一个针对订单主档的查询
Condition c=rc.GetNewCondition();// 创建一个条件 ( 由于是综合查询,条件之间是 AND 关系 )
If(this.txtNo.Text!=””) // 如果在编号文本框中输入了查询条件
c.AddEqualTo(SaleOrderEntity.__NO,this.txtNo.Text);// 添加 ”=” 条件 (SaleOrderEntity.__NO 是实体类中的常量,其值就是 ”No” ,为了减少去查对象属性的麻烦和输错的可能性,采用常量是最好的方式 )
if(this.ddlCustom.SelectedValue!=””) // 如果选择了某一客户
c.AddEqualTo(SaleOrderEntity.__CUSTOMID, this.ddlCustom.SelectedValue);
if(this.txtDateFrom.Text!=””) // 如果开始日期不为空 , 则添加 ”>=” 比较
c. AddGreaterThanOrEqualTo(SaleOrderEntity.__CREATEDATE,DateTime.Parse(this.txtDateFrom.Text);
if(this.txtDateEnd.Text!=””)// 如果结束日期不为空,则添加 ”<” 比较
c. AddLessThan(SaleOrderEntity.__CREATEDATE,DateTime.Parse(this.txtDateEnd.Text).AddDays(1);
rc.OrderBy(SaleOrderEntity.__CREATEDATE,false);// 按创建时间的逆顺排
DataTable dt=rc.AdDataTable(); // 返回 DataTable 以便绑定 Grid
3) 选中一条档后要显示主档信息与明细清单
SaleOrderEntity Soe=new SaleOrderEntity();
Soe.Id=Request[“Id”].ToString(); // 取得页面传过来的订单 ID 值
Soe.Retrieve(); // 通过主键值获取对象
If(Soe.IsPersistent) // 如果数据库里存在的话
{
// 给界面上的控件赋值显示
this.txtNo.Text=Soe.No;
this.txtCreateDate.Text=Soe.CreateDate.ToString();
….
// 绑定订单的所有明细信息
RetrieveCriteria rc=new RetrieveCriteria(typeof(SaleOrderDetailEntity));
Condition c=rc.GetNewCondition();
c.AddEqualTo(SaleOrderDetailEntity.__ORDERID,Soe.Id);// 指定的订单 ID
DataTable dt=rc.AsDataTable(); // 返回明细 DataTable
this.Grid.DataSource=dt;
this.Grid.DataBind();// 绑定
}
4) 进行订单主档与明细的修改 , 点击保存时:
Transaction t=new Transaction(); // 这里肯定又要用到事务处理了
SaleOrderEntity Soe.new SaleOrderEntity();
Soe.Id=Request[“Id”].ToString(); // 取得订单 ID
Soe.Retrieve();// 通过主键获取对象
If(Soe.IsPersistent) // 如果对象存在的话进行修改操作
{
Soe.No=this.txtNo.Text;
Soe.CreateDate=DateTime.Parse(this.txtCreateDate.Text);
….
t.AddSaveObject(Soe); // 自动判断 IsPersistent 就进行 Update 而不是 Insert
// 选删除所有的明细记录,然后再重新把明细添进去,这样比较方便,避免了要判断是否进行修改,是否要进行删除与新增的麻烦
DeleteCriteria dc=new DeleteCriteria(Typeof(SaleOrderDetailEntity));// 创建一个针对 SaleOrderDetail 的删除标准
dc.GetNewCondition().AddEqualTo(SaleOrderDetailEntity.__ORDERID,Soe.Id);// 删除所有本订单 ID 的明细
t.AddDeleteCriteria(dc);// 把这个删除标准加到事务中
for(int i=0;i<this.Grid.Rows.Count;i++) 循环 Grid 重新添加到明细表中
{
SaleOrderDetailEntity Sode=new SaleOrderDetailEntity();
Sode.Id=Guid.NewGuid().ToString();// 生成新的 GUID
Sode.OrderId=Soe.Id; // 取订单主档的 GUID
Sode.ProductId=…// 从 Grid 上取商品 ID 值
Sode.Quantity= // 从 Grid 上取商品数量值
Sode.Price=… // 从 Grid 上取商品单价值
Sode.Amount=Sode.Quantity*Sode.Price; // 汇总小计
t.AddSaveObject(Sode); // 把订单明细对象加到事务中
}
}
5) 删除订单与订单明细
Transaction t=new Transaction(); // 这里肯定又要用到事务处理了
SaleOrderEntity Soe.new SaleOrderEntity();
Soe.Id=Request[“Id”].ToString(); // 取得订单 ID
Soe.Retrieve();// 通过主键获取对象
If(Soe.IsPersistent) // 如果对象存在的话进行修改操作
{
t.AddDeleteObject(Soe); // 把要删除的对象加到事务中
// 选删除所有的明细记录
DeleteCriteria dc=new DeleteCriteria(Typeof(SaleOrderDetailEntity));// 创建一个针对 SaleOrderDetail 的删除标准
dc.GetNewCondition().AddEqualTo(SaleOrderDetailEntity.__ORDERID,Soe.Id);// 删除所有本订单 ID 的明细
t.AddDeleteCriteria(dc);// 把这个删除标准加到事务中
t.Process();// 提交删除
}
以上是我模拟的最常见的一些情况,以此让大家对 SPL 的使用有个初步的了解,至于 SPL 的更多的详细资料请访问我的 BLOG 专题: http://tintown.cnblogs.com/category/12787.html