一. 前言
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 { //设定环境 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= <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= 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;} |







