您的位置:首页 > 移动开发 > Objective-C

Websharp——开源.Net应用系统框架

2006-12-26 15:20 786 查看

一. 前言

Websharp的目标,是开发一个开源的基于Microsoft.Net的轻量级的应用软件系统开发框架,包含以下内容:
Ø 一个轻量级的O/R Mapping框架
Ø 一个轻量级的AOP框架
Ø 一个轻量级的ServiceLocator,主要目的是为整合不同服务端技术的客户端编程。
说来惭愧的是,这个框架从三年前就开始做了,但是因为工作的原因,具体的开发过程一直是断断续续,中间因个人对编程思想认识的变化,在结构方面也一直有点变化。在这个过程中,一直有人来Mail询问相关的情况,也有很多朋友发信来鼓励我,使我感到愧疚的是,我一直都没有很好的回复这些邮件。在国内,做开源项目真的是很难,首先要养活自己和老婆孩子,才能够挤出一点点时间来做自己的事情。
最近,因为工作的变化,使我从繁复的开发工作中脱离出来,使我有更多的时间来支配我自己,因此,又把这个工作继续了下去,经过一段时间的“虾米”生活,终于把O/R Mapping做的比较像样了。AOP和ServiceLocator部分,是以前做好的,一直都没有动过。现在我把所有的代码都公开出来,并写了一个简单的使用说明,希望能够对大家有所帮助。在这里,需要感谢的是徐芳波,在Websharp的开发过程中,也做了很多的工作,付出了很多。
本文主要说明Websharp O/R Mapping部分使用的内容。关于Websharp的设计理念,以及其他方面的内容,可以访问我的Blog:http://sunnyym.cnblogs.com/
从此处下载全部源代码

二. Websharp O/R Mapping起步

Websharp ORM是一个轻量级的O/R Mapping框架,主要特点是抛弃了Java中常见的,也是其他一些O/R Mapping产品中使用XML文件来做映射描述的方法,而使用Attribute作为描述映射的方法,简单明了,并且,对开发人员来说,只有PersistenceManager、Query、Transaction等极少数接口需要掌握,上手快,使用非常方便。
因为在某些地方使用了范型,所以目前版本的Websharp需要.Net Framework2.0。
下面的例子给出了使用Websharp进行ORM操作的基本过程。
使用Visual Studio.Net2005建立一个Windows Console项目,然后,定义如下一个类:

[TableMap("Product", "ID")]

public class Product
{
private int m_ID;
private string m_Name;
private decimal m_Price;

public Product() { }
public Product(string name,decimal price)
{
//m_ID = id;
m_Name = name;
m_Price = price;
}

[ColumnMap("ID", DbType.Int32)]
[AutoIncrease(1)]
public int ID
{
get { return m_ID; }
set { m_ID = value; }
}

[ColumnMap("Name", DbType.String)]
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}

[ColumnMap("Price", DbType.Decimal)]
public decimal Price
{
get { return m_Price; }
set { m_Price = value; }
}
}
类中第一行[TableMap("Product", "ID")]的意思是说,这个Product类映射到数据库中的Product表,主键为属性ID。在属性ID上,[ColumnMap("ID", DbType.Int32)]的意思是说,这个属性映射到数据库中的ID字段,数据类型是Int32,[AutoIncrease(1)]表明这是一个自动增长列,增长的幅度为1。其他属性的可以据此类推。
因此,上面这个Produc类对应的数据库表的结构应该是:

字段名

数据类型
ID
int(自动增长)
Name
Nvarchar(50)
Price
Decimal
下面的代码演示了Websharp是如何把Product对象新增到数据库中的。

public static void Main(string[] args)

{
//设定环境
DatabaseProperty dbp = new DatabaseProperty();
dbp.DatabaseType = DatabaseType.MSSQLServer;
dbp.ConnectionString = "Data Source=(local);Initial Catalog=WebsharpTest;Integrated Security=True";

//操作数据
PersistenceManager pm = PersistenceManagerFactory.Instance().Create(dbp);
Product p0 = new Product("Name0", 100);
pm.PersistNew(p0);
Product p1 = new Product("Name1", 101);
pm.PersistNew(p1);
pm.Flush();
pm.Close();
}
在代码的开始部分,先设定了数据库的一些参数,然后,通过PersistenceManagerFactory创建了一个PersistenceManager,用这个PersistenceManager就可以对对象进行操作了。在上面的代码里面,我们把两个Product对象保存到了数据库中。注意,因为Product类的ID属性是自动增长的,因此,在保存这两个对象之前,是不必对ID属性赋值的,在这两个对象被保存到数据库中后,PersistenceManager会根据数据库中的自动增长的值自动给ID赋值。
当然,为了使上面的代码能够顺利运行,我们还需要做一些配置。新建一个App.config文件,把下面的配置代码Copy进去就可以了:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
<configSections>
<section name="cachingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings, Microsoft.Practices.EnterpriseLibrary.Caching, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
<section name="WebsharpExpirationPolicy" type="Websharp.ORM.Service.WebsharpCofigurationHandler,Websharp.ORM.Service" />
</configSections>
<cachingConfiguration defaultCacheManager="Cache Manager">
<cacheManagers>
<add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
name="Cache Manager" />
<add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
name="EntityCache" />
<add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
name="SqlCache" />
</cacheManagers>
<backingStores>
<add encryptionProviderName="" type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.NullBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name="Null Storage" />
</backingStores>
</cachingConfiguration>

<WebsharpExpirationPolicy>
<ExpirationPolicy ExpirationCheckInterval="60" AssemblyName="Microsoft.ApplicationBlocks.Cache" ClassName="Microsoft.ApplicationBlocks.Cache.ExpirationsImplementations.SlidingTime" />
</WebsharpExpirationPolicy>
</configuration>
配置文件只是用来说明缓存的使用的,基本上所有的项目需要的配置文件对于Websharp来说都不需要改变。当然,有一些细微的参数还是可以调整的,这个在后面描述。
可以看出,相对于其他一些O/R Mapping框架来说,Websharp不需要写一大堆的XML映射文件,代码简洁明了。

三. 映射方法说明

映射部分,完成对象和关系型数据库之间映射关系的表达。Websharp使用Attribute来描述映射关系,设计了以下Attribute来描述对象和关系型数据库之间的映射。
Ø TableMapAttribute
这个Attribute描述对象和数据库表的映射关系,这个类有两个属性,TableName属性指明和某个类所对应的数据库表,PrimaryKeys用来描述表的主关键字。这个类的定义如下:

[AttributeUsage(AttributeTargets.Class)]

public class TableMapAttribute : Attribute
{
private string tableName;
private string[] primaryKeys;
public TableMapAttribute(string tableName,params string[] primaryKeys)
{
this.tableName = tableName;
this.primaryKeys = primaryKeys;
}
public string TableName
{
get{return tableName;}
set{tableName = value;}
}

public string[] PrimaryKeys
{
get{return primaryKeys;}
set{primaryKeys = value;}
}
}
Ø ColumnMapAttribute
这个Attribute描述对象属性和数据库中表的字段之间的映射关系,这个类有三个属性,ColumnName属性指明和某个属性所对应的字段,DbType属性指明数据库字段的数据类型,DefaultValue指明字段的默认值。这个类的定义如下:

[AttributeUsage(AttributeTargets.Property)]

public class ColumnMapAttribute : Attribute
{
private string columnName;
private DbType dbtype;
private object defaultValue;
public ColumnMapAttribute(string columnName,DbType dbtype)
{
this.columnName = columnName;
this.dbtype = dbtype;
}

public ColumnMapAttribute(string columnName,DbType dbtype,object defaultValue)
{
this.columnName = columnName;
this.dbtype = dbtype;
this.defaultValue = defaultValue;
}

public string ColumnName
{
get{return columnName;}
set{columnName = value;}
}

public DbType DbType
{
get{return dbtype;}
set{dbtype = value;}
}

public object DefaultValue
{
get{return defaultValue;}
set{defaultValue = value;}
}
}
Ø ReferenceObjectAttribute
ReferenceObjectAttribute指示该属性是引用的另外一个对象,因此,在执行持久化操作的时候,需要根据参数进行额外的处理。默认情况下,当持久化实体对象的时候,ReferenceObjectAttribute指示的属性,不进行操作。这个类有三个属性,ReferenceType指明所引用的对象的类型,PrimaryKey和ForeignKey用来指明两个类之间进行关联的主键和外键。这个类的定义如下:

[AttributeUsage(AttributeTargets.Property)]

public class ReferenceObjectAttribute : Attribute
{
private Type referenceType;
private string primaryKey;
private string foreignKey;
public ReferenceObjectAttribute(Type referenceType,string primaryKey,string foreignKey)
{
this.referenceType = referenceType;
this.primaryKey = primaryKey;
this.foreignKey = foreignKey;
}

public ReferenceObjectAttribute(){}

public Type ReferenceType
{
get{return referenceType;}
set{referenceType = value;}
}

public string PrimaryKey
{
get{return primaryKey;}
set{primaryKey = value;}
}

public string ForeignKey
{
get{return foreignKey;}
set{foreignKey = value;}
}
}

Ø SubObjectAttribute
SubObjectAttribute指示该属性是引用的是子对象,因此,在执行持久化操作的时候,需要根据参数进行额外的处理。默认情况下,当持久化实体对象的时候,SubObjectAttribute指示的属性,不进行操作。
这个类的定义如下:

[AttributeUsage(AttributeTargets.Property)]

public class SubObjectAttribute : Attribute
{
private Type subObjectType;
private string primaryKey;
private string foreignKey;
public SubObjectAttribute(Type subObjectType, string primaryKey, string foreignKey)
{
this.subObjectType = subObjectType;
this.primaryKey = primaryKey;
this.foreignKey = foreignKey;
}

public SubObjectAttribute(){}

public Type SubObjectType
{
get { return subObjectType; }
set { subObjectType = value; }
}

public string PrimaryKey
{
get{return primaryKey;}
set{primaryKey = value;}
}

public string ForeignKey
{
get{return foreignKey;}
set{foreignKey = value;}
}
}
Ø AutoIncreaseAttribute
AutoIncreaseAttribute指示该属性是自动增长的。自动增长默认种子为1。需要指出的是,自动增长的属性只适用于MS SqlServer,Websharp目前不支持其他数据库的自动增长列。
这个类的定义如下:

[AttributeUsage(AttributeTargets.Property)]

public class AutoIncreaseAttribute : Attribute
{
private int step = 1;

public AutoIncreaseAttribute(){}

public AutoIncreaseAttribute(int step)
{
this.step = step;
}

public int Step
{
get{return step;}
set{step = value;}
}
}
设计好映射的方法后,我们就可以来定义实体类以及同数据库之间的映射。下面是一个例子:

//订单类别

[TableMap("OrderType","ID")]
public class OrderType
{
private int m_ID;
private string m_Name;

[ColumnMap("ID",DbType.Int32)]
public int ID
{
get { return m_ID; }
set { m_ID = value; }
}
[ColumnMap("Name", DbType.String)]
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}
}

//订单
[TableMap("PurchaseOrder", "OrderID")]
public class Order
{
private int m_OrderID;
private OrderType m_OrderType;
private string m_Title;
private DateTime m_AddTime;
private bool m_IsSigned;
private List<OrderDetail> m_Details;

[ColumnMap("OrderID",DbType.Int32)]
[AutoIncrease]
public int OrderID
{
get { return m_OrderID; }
set { m_OrderID = value; }
}
[ReferenceObject(typeof(OrderType),"ID","TypeID")]
[ColumnMap("TypeID",DbType.String)]
public OrderType OrderType
{
get { return m_OrderType; }
set { m_OrderType = value; }
}
[ColumnMap("Title", DbType.String)]
public string Title
{
get { return m_Title; }
set { m_Title = value; }
}
[ColumnMap("AddTime", DbType.DateTime)]
public DateTime AddTime
{
get { return m_AddTime; }
set { m_AddTime = value; }
}
[ColumnMap("AddTime", DbType.Boolean)]
public bool IsDigned
{
get { return m_IsSigned; }
set { m_IsSigned = value; }
}
[SubObject(typeof(OrderDetail),"OrderID","OrderID")]
public List<OrderDetail> Details
{
get { return m_Details; }
set { m_Details = value; }
}
}

//订单明细
public class OrderDetail
{
private int m_DetailID;
private int m_OrderID;
private string m_ProductName;
private int m_Amount;

[ColumnMap("ID", DbType.Int32)]
[AutoIncrease]
public int DetailID
{
get { return m_DetailID; }
set { m_DetailID = value; }
}
[ColumnMap("OrderID", DbType.Int32)]
public int OrderID
{
get { return m_OrderID; }
set { m_OrderID = value; }
}
[ColumnMap("ProductName", DbType.String)]
public string ProductName
{
get { return m_ProductName; }
set { m_ProductName = value; }
}
[ColumnMap("Amount", DbType.Int32)]
public int Amount
{
get { return m_Amount; }
set { m_Amount = value; }
}
}
Order中

[ReferenceObject(typeof(OrderType),"ID","TypeID")]

[ColumnMap("TypeID",DbType.String)]
public OrderType OrderType
{
get { return m_OrderType; }
set { m_OrderType = value; }
}
这段代码表明,OrderType这个属性,引用了OrderType这个对象,同OrderType相关联的,是OrderType的主键ID和Order的外键TypeID。

[SubObject(typeof(OrderDetail),"OrderID","OrderID")]

public List<OrderDetail> Details
{
get { return m_Details; }
set { m_Details = value; }
}
这段代码表明,Details这个属性,由子对象OrderDetail的集合组成,其中,两个对象通过Order类的OrderID主键和OrderDetail的外键OrderID相关联。

四. 对继承的支持

Websharp框架在设计的时候,要求能够支持面向对象语言中的继承。Websharp支持三种继承模式:ONE_INHERITANCE_TREE_ONE_TABLE、ONE_INHERITANCE_PATH_ONE_TABLE和ONE_CLASS_ONE_TABLE。以如下的类结构为例:



ONE_INHERITANCE_TREE_ONE_TABLE
这种映射模式将具有相同父类的所有类都映射到一个数据库表中。数据库结构如下图:

Websharp中,只需要对每个类都指明具有相同值的TableMap特性就可以了。如下面的代码:

[TableMap("Table1", "Property1")]

public class Parent
{
private string property1;
private string property2;

[ColumnMap("Column1", DbType.String)]
public string Property1
{
get { return property1; }
set { property1=value; }
}

[ColumnMap("Column2", DbType.String)]
public string Property2
{
get { return property2; }
set { property2 = value; }
}
}

[TableMap("Table1", "Property1")]
public class Child1 : Parent
{
private string property3;

[ColumnMap("Column3", DbType.String)]
public string Property3
{
get { return property3; }
set { property3 = value; }
}
}

[TableMap("Table1", "Property1")]
public class Child2 : Parent
{
private string property4;

[ColumnMap("Column4", DbType.String)]
public string Property4
{
get { return property4; }
set { property4 = value; }
}
}
此时,当按照如下的代码初始化一个Child1对象,

Child1 c1 = new Child1();

c1.Property1 = "P11";
c1.Property2 = "P12";
c1.Property3 = "P13";
并保存到数据库中的时候,数据库中的记录应该是:

Column1

Column2
Column3
Column4
P11
P12
P13
NULL
如果按照如下的代码初始化一个Child2对象:

Child2 c1 = new Child2();

c2.Property1 = "P21";
c2.Property2 = "P22";
c2.Property4 = "P24";
并保存到数据库中的时候,数据库中的记录应该是:

Column1

Column2
Column3
Column4
P21
P22
NULL
P24
ONE_INHERITANCE_PATH_ONE_TABLE
这种映射模式将一个继承路径映射到一个表,这种情况下的数据库的结构是:



这种情况下,实际上Parent类并不映射到实际的表,Child1和Child2类分别映射到Child1和Child2表。因此,在这种情况下,需要把Parent类的TableMap特性设置为Null,而Child1和Child2类的TableMap特性分别设置为Child1和Child2,代码如下面所示:

[TableMap(null, "Property1")]

public class Parent
{
private string property1;
private string property2;

[ColumnMap("Column1", DbType.String)]
public string Property1
{
get { return property1; }
set { property1=value; }
}

[ColumnMap("Column2", DbType.String)]
public string Property2
{
get { return property2; }
set { property2 = value; }
}
}

[TableMap("Child1", "Property1")]
public class Child1 : Parent
{
private string property3;

[ColumnMap("Column3", DbType.String)]
public string Property3
{
get { return property3; }
set { property3 = value; }
}
}

[TableMap("Child2", "Property1")]
public class Child2 : Parent
{
private string property4;

[ColumnMap("Column4", DbType.String)]
public string Property4
{
get { return property4; }
set { property4 = value; }
}
}
此时,当按照如下的代码初始化一个Child1对象,

Child1 c1 = new Child1();

c1.Property1 = "P11";
c1.Property2 = "P12";
c1.Property3 = "P13";
并保存到数据库中的时候,数据库中应该只在Child1表中添加下面的数据:

Column1

Column2
Column3
P11
P12
P13
如果保存的是一个Child2对象,那么,应该只在Child2表中添加数据。Child1表和Child2表是互相独立的,并不会互相影响。

ONE_CLASS_ONE_TABLE
这种映射模式将每个类映射到对应的一个表,对于上面的类结构,数据库的结构是:



这种映射模式,我们只需要分别对每个类设定各自映射的表就可以了。代码如下面所示:

[TableMap("Parent", "Property1")]

public class Parent
{
private string property1;
private string property2;

[ColumnMap("Column1", DbType.String)]
public string Property1
{
get { return property1; }
set { property1=value; }
}

[ColumnMap("Column2", DbType.String)]
public string Property2
{
get { return property2; }
set { property2 = value; }
}
}

[TableMap("Child1", "Property1")]
public class Child1 : Parent
{
private string property3;

[ColumnMap("Column3", DbType.String)]
public string Property3
{
get { return property3; }
set { property3 = value; }
}
}

[TableMap("Child2", "Property1")]
public class Child2 : Parent
{
private string property4;

[ColumnMap("Column4", DbType.String)]
public string Property4
{
get { return property4; }
set { property4 = value; }
}
}
此时,当按照如下的代码初始化一个Child1对象,

Child1 c1 = new Child1();

c1.Property1 = "P11";
c1.Property2 = "P12";
c1.Property3 = "P13";
并保存到数据库中的时候,数据库中的记录应该是:
Parent表:

Column1

Column2
P11
P12
Child1表:

Column1

Column3
P11
P13
同样的,如果保存的是一个Child2对象,那么,将在Parent表和Child2表中添加记录。

五. PersistenceManager

Websharp O/R Mapping框架的操作核心,在于PersistenceManager接口,对实体对象的操作,包括增、删、改的操作,都是通过这个接口来进行的。
PersistenceManager的定义如下:

/**

* 这个接口定义持久化操作的方法
*
*/
public interface PersistenceManager : IDisposable
{
/*
* 关闭一个PersistenceManager。当一个PersistenceManager被关闭的时候,需要做如下的工作
* 1、释放它所管理的实体类,以及相关的状态。如果不释放,可能造成内存泄露
* 2、如果Flush方法没有被执行,则执行Flush方法。
* 3、释放数据库联接等资源。
* 4、从PersistenManagerfactroy中清除自己
*/
void Close();

/**
* 判断一个PersistenceManager是否已经关闭了。
*/
bool IsClosed{get;}

/**
* 获取PersistenceManager当前所处的事务
*/
Transaction CurrentTransaction{ get;}

/**
* 指示在默认的情况下,所有的操作是否忽略缓存。如果忽略缓存,那么,有的时候会存在一些不一致的情况,除非系统被禁止了缓存的使用
*/
bool IgnoreCache{get;set;}

/**
* 将一个新的实体对象转换成可持续对象,这个对象在事务结束的时候,会被Insert到数据库中
* 调用这个方法后,该对象的状态为EntityState.New
* 如果一个对象的状态为EntityState.Persistent,则本方法将抛出一个EntityIsPersistentException异常
*/
void PersistNew(object entity);
void PersistNew(object entity,PersistOptions options);

/*
* 将一个新的实体对象转换成可持续对象,并且指明要保存的属性
*
*/
void PersistNew(object entity, params string[] properties);
void PersistNew(object entity, PersistOptions options, params string[] properties);

/**
* 将一个实体对象保存到数据库中。
* 如果一个对象是Trasient的,则将其转换为EntityState.New状态。在事务结束的时候,会被Insert到数据库中
* 否则,其状态就是EntityState.Persist,就更新到数据库中。
* 如果一个Trasient对象实际上已经存在于数据库中,由于Persist方法并不检查实际的数据库,因此,
* 调用这个方法,将会抛出异常。这个时候,应该使用先使用Attach方法,然后调用Persist。
* Persist方法主要用于已受管的对象的更新
*/
void Persist(object entity);
void Persist(object entity,PersistOptions options);

/**
* 将一个实体对象保存到数据库中,并且指明要保存的属性
*
*/
void Persist(object entity,params string[] properties);
void Persist(object entity,PersistOptions options,params string[] properties);

/**
* 强制将一个实体更新到数据库中。
* 执行这个方法,将把对象的状态强制变为EntityState.Persist。
* 由于Update方法并不检查实际的数据库,因此如果一个对象实际上不存在于数据库中,那么,这个方法实际上
* 不会对数据库造成变化。
* 如果不能确认对象已经存在于数据库中,那么,应该使用先使用Attach方法。
*/
void Update(object entity);
void Update(object entity, PersistOptions options);

/**
* 将一个实体对象更新到数据库中,并且指明要保存的属性
*
*/
void Update(object entity, params string[] properties);
void Update(object entity, PersistOptions options, params string[] properties);

/**
* 删除一个对象。
* 一个对象被删除后,其状态变成EntityState.Deleted,在事务结束的时候,会被从数据库中删除。
* 如果一个对象不是持久的,那么,这个方法将抛出异常。
*
*/
void Delete(object entity);
void Delete(object entity,PersistOptions options);

/**
* 将一个对象标记为可持续的。如果这个对象已经存在于实际的数据库中,那么,这个对象的状态就是
* EntityState.Persistent,否则,这个对象的状态就是EntityState.New。
* 注意:这个方法不会导致对数据库实际数据的更改
*/
void Attach(object entity);
void Attach(object entity,PersistOptions options);

/**
* 重新从数据库中载入这个对象,这意味着重新给对象的各个属性赋值。
*
*/
void Reload(ref object entity);
void Reload(ref object entity,PersistOptions options);

/**
* 从缓存中把某个对象移除。
*
*/
void Evict (object entity);
void EvictAll (object[] pcs);
void EvictAll (IEnumerable pcs);
void EvictAll ();

/**
* 根据主键查找某个对象,如果主键是多个字段的,顺序必须同TableMapAttribute中的顺序相同,否则将有不可预测的事情发生
*/
object FindByPrimaryKey(Type entityType,params object[] id);
object FindByPrimaryKey(Type entityType, PersistOptions options, params object[] id);
T FindByPrimaryKey<T>(params object[] id);
T FindByPrimaryKey<T>(PersistOptions options, params object[] id);

/**
*获取某个对象的状态。这个对象必须是受该PersistenceManager管理的,否则,抛出异常
*/
EntityState GetState(object entity);
ICollection GetManagedEntities();

/**
* 本操作使对实体对象所作的更改立即生效。
*/
bool Flush();

/// <summary>
/// 该方法撤销前面所做的所有操作。
/// </summary>
void Cancel();
/**
* 创建Query对象。
*
*/
Query NewQuery();
Query NewQuery(Type entityType);
Query NewQuery(Type entityType,string filter);
Query NewQuery(Type entityType,string filter,QueryParameterCollection paramColletion);

Query<T> NewQuery<T>();
Query<T> NewQuery<T>(string filter);
Query<T> NewQuery<T>(string filter, QueryParameterCollection paramColletion);
}
PersistenceManager接口的相应的方法的说明已经在上面列出了,也是一目了然的。额外需要说明的是,这些对对象的操纵,都是暂存在内存中,只有在调用了Flush方法后才生效,才会把对数据的改变保存到数据库中。调用Cancel方法,可以撤销这些操作。

六. 事务处理

Websharp框架提供了简单的事务处理的能力,这是通过Transaction接口来实现的。
Transaction接口的定义如下:

public interface Transaction

{
void Begin();
void Commit();
void Rollback();
PersistenceManager PersistenceManager{get;}
}
这个接口定义的非常简单,就是提供了开始事务、提交或者回滚事务的方法。下面的例子说明了在Websharp里面如何使用事务:

public void TransactionTest()

{
//设定环境
DatabaseProperty dbp = new DatabaseProperty();
dbp.DatabaseType = DatabaseType.MSSQLServer;
dbp.ConnectionString = "Data Source=(local);Initial Catalog=WebsharpTest;Integrated Security=True";

//操作数据
PersistenceManager pm = PersistenceManagerFactory.Instance().Create(dbp);
Product p0 = new Product("Name0", 100);
pm.PersistNew(p0);
Product p1 = new Product("Name1", 101);
pm.PersistNew(p1);
Transaction t = pm.CurrentTransaction; //获取当前事务对象
t.Begin(); //开始事务
pm.Flush();
t.Commit(); //提交事务
pm.Close();
}

七. 对象查询

Websharp框架通过Query接口,提供对象查询的功能。Query接口的定义如下:

public interface Query

{
Type EntityType{get;set;}
string EntityTypeName{get;set;}
string Filter{get;set;}

QueryParameterCollection Parameters{get;set;}
string Ordering{get;set;}

bool IgnoreCache{get;set;}

ICollection QueryObjects();
DataSet QueryDataSet();

PersistenceManager PersistenceManager{get;}

bool IsClosed{get;}
void Close();
//void Open();
}
同时,Websharp提供了一个范型的版本,定义如下:

public interface Query<T> : Query

{
new ICollection<T> QueryObjects();
}
使用Query的一般步骤是:
1、 从PersistenceManager获得一个Query接口
2、 设定Query接口要查询的类型、条件(Filter)和相应的参数
3、 执行QueryObjects方法,得到相应的对象集合。
下面的例子说明了使用Query的过程:

public void NormalQuery()

{
DatabaseProperty dbp = new DatabaseProperty();
dbp.DatabaseType = DatabaseType.Oracle;
dbp.ConnectionString = "Data Source=ORACLE1453;User Id=websharp;Password=websharp";
ApplicationConfiguration.FrameworkUssage = FrameworkUssage.Normal;
ApplicationConfiguration.DefaultDatabaseProperty = dbp;

PersistenceManager pm = PersistenceManagerFactory.Instance().Create();
Query<Pencil> q = pm.NewQuery<Pencil>();
q.Filter = "Owner like :Owner";
QueryParameterCollection qpm = new QueryParameterCollection(1);
QueryParameter qm = new QueryParameter(":Owner", "sunny");
qpm.Add(qm);
q.Parameters = qpm;
ICollection<Pencil> pencils = q.QueryObjects();
pm.Close();
}

八. 配置文件

配置文件配置了Websharp运行时需要的一些信息,目前来说,在O/R Mapping部分,需要配置的是关于缓存的信息。在缓存部分,Websharp使用了微软的Enterprise工具中的缓存部分,因此,需要配置的信息同微软的Enterprise工具中的缓存部分一样。所需要添加的,就是缓存过期的策略部分,这个部分,在WebsharpExpirationPolicy中进行说明。配置文件的内容如下:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>
<configSections>
<section name="cachingConfiguration" type="Microsoft.Practices.EnterpriseLibrary.Caching.Configuration.CacheManagerSettings, Microsoft.Practices.EnterpriseLibrary.Caching, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null" />
<section name="WebsharpExpirationPolicy" type="Websharp.ORM.Service.WebsharpCofigurationHandler,Websharp.ORM.Service" />
</configSections>
<cachingConfiguration defaultCacheManager="Cache Manager">
<cacheManagers>
<add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
name="Cache Manager" />
<add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
name="EntityCache" />
<add expirationPollFrequencyInSeconds="60" maximumElementsInCacheBeforeScavenging="1000"
numberToRemoveWhenScavenging="10" backingStoreName="Null Storage"
name="SqlCache" />
</cacheManagers>
<backingStores>
<add encryptionProviderName="" type="Microsoft.Practices.EnterpriseLibrary.Caching.BackingStoreImplementations.NullBackingStore, Microsoft.Practices.EnterpriseLibrary.Caching, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null"
name="Null Storage" />
</backingStores>
</cachingConfiguration>

<WebsharpExpirationPolicy>
<ExpirationPolicy ExpirationCheckInterval="60" AssemblyName="Microsoft.ApplicationBlocks.Cache" ClassName="Microsoft.ApplicationBlocks.Cache.ExpirationsImplementations.SlidingTime" />
</WebsharpExpirationPolicy>
</configuration>
Websharp默认使用的是时间过期清除缓存的策略,过期的时间,可以修改,单位为秒。
有一点另自己不满意的是,在配置文件部分,我依然使用了.Net Framewoork1.1时期的配置文件操作方式,不过这对系统并无丝毫影响。

九. 后记

设计Websharp时,在考虑映射方法的时候,曾经为使用XML文件还是Attribute来映射考虑了很长时间,最终还是选择了Attribute。用XML文件来作为映射手段,虽然这种使用方法很常见,但是,感觉使用起来非常不方便,我个人也时常为EJB和Hibernate里面的配置文件烦恼不已,而使用Attribute,明显感觉清爽了很多。这似乎也是未来的一个方向,这从EJB3.0的变化也可以看出。
Websharp O/R Mapping的结构设计,参考了JDO的很多东西,感觉在编程思想和面向对象方法的使用和讨论方面,Java阵营真是活跃的多。实际上,对于一个程序员来说,在对数个不同的技术都有了深入的了解以后,会发现自己对软件系统开发的看法有一种融会贯通的感觉。实现是一个方面,但同样重要的是结构。这两年,一直在同时做Java和.Net的开发,很多时候是跨两个平台的开发,从两个平台中都收获不少。没有感觉Java或者C#对一个程序员来说有什么区别。那些关于Java和C#孰优孰劣的争论真是没有必要,也很肤浅。当然,C#作为一种后出的语言,在语法设计上的确有不小精妙的地方,这也是我崇拜Anders Hejlsberg的原因,也是我使用C#来实现Websharp的原因。但对于一个系统的开发来说,这种语言上的差异是可以忽略不计的。语言不是重要的,重要的是编程的思想。
一个人开发一个框架,是一件累人的事情,有的时候自己几乎就要放弃。现在虽然终于有了一个阶段的成果,但是,有些地方可能没有经过严格的测试,因此,希望各位同仁在使用的过程中,如果发现问题,能够及时告诉我,以便于我及时修正问题。也希望有人如果感兴趣,我们一起来发展这个项目。
从此处下载全部源代码



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐