听棠.NET

用积极乐观的心态,面对压力
posts - 307, comments - 10812, trackbacks - 112, articles - 5
  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理

公告

SmartPersistenceLayer 3 快速入门

Posted on 2005-12-05 17:49 听棠.NET 阅读(...) 评论(...) 编辑 收藏

  SmartPersistenceLayer 3 快速入门

前言

SmartPersistenceLayerSPL)自在博客园发布开始,就一直受到广大朋友的认可,那一套SPL的系列文档对SPL的使用与功能以及原理都作了充分的介绍,而这些系列文章有利于大家理解SPL的思想,将作为一个优秀的.NET系统框架持久层。

而那些文章由于比较分散,而且论述了一些架构思想,对一些初学者感觉有些困难,也应广大朋友的要求,写一份简单的、实用的SPL应用手册,所以我接下来从实际场景模拟开发。SPL强调是框架带来的灵活性与扩展性。

一、             引用

SPL的发布形式是一个名为PersistenceLayer.DllDLL文件,可以在我的BLOG上下载目前最新版:SmartPersistenceLayer3.2,因此只需要在项目中“添加引用”即可:



 

若要使用ODP.NET连接Oracle数据库,则用以上方式添加Oracle.DataAccess.dll

若要使用SPL连接MySql数据库,则用以上方式添加MySql.Data.dll

二、             配置文件与实体类

SPL的配置文件与实体类可以使用我提供的SmartRobot进行生成(SPL_Robot已经公开源码,请看这里),这可以大大加快开发效率,但工具毕竟是工具,不属于SPL持久层的必选部分。

连接数据库:


  目前SmartRobot支持Ms Sql ServerMs AccessOracle数据库,如果是其他数据库只能只好手写实体类了或者等我升级喽;)

 

确定好要生成的实体类存放的地址,到时生成时会生成到相应的目录里。


配置每个表对应的实体类属性,默认实体类名称为“表名”加“Entity”字符,属性名默认与列名相同,上图中的“2”“3”操作对每个表都要重复一次的。

 

这时就会生成勾上的实体类到指定的目录下了。只要把指定的实体类引用到项目中即可,实体类默认使用的是BusinessEntity命名空间。因此在开发时,只要用到实体类的地方使用:using BusinessEntity就可以了。

 

保存两个配置文件,放到你的项目中:ClassMap.xmlDatabaseMap.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

小计

 

以下为模拟情况:

在界面上选择了客户,并在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();   
//事务提交即可

在查询界面要根据订单编号、订单时间段、客户进行综合查询

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

选中一条档后要显示主档信息与明细清单

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();//绑定
}

进行订单主档与明细的修改,点击保存时

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);        //把订单明细对象加到事务中

}
}

删除订单与订单明细

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


本文下载:点此下载

 

 

                                                                                        听棠    
                                                                                          2005-12-5