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

一.     前言

Websharp的目标,是开发一个开源的基于Microsoft.Net的轻量级的应用软件系统开发框架,包含以下内容:

Ø         一个轻量级的O/R Mapping框架

Ø         一个轻量级的AOP框架

Ø         一个轻量级的ServiceLocator,主要目的是为整合不同服务端技术的客户端编程。

说来惭愧的是,这个框架从三年前就开始做了,但是因为工作的原因,具体的开发过程一直是断断续续,中间因个人对编程思想认识的变化,在结构方面也一直有点变化。在这个过程中,一直有人来Mail询问相关的情况,也有很多朋友发信来鼓励我,使我感到愧疚的是,我一直都没有很好的回复这些邮件。在国内,做开源项目真的是很难,首先要养活自己和老婆孩子,才能够挤出一点点时间来做自己的事情。

最近,因为工作的变化,使我从繁复的开发工作中脱离出来,使我有更多的时间来支配我自己,因此,又把这个工作继续了下去,经过一段时间的“虾米”生活,终于把O/R Mapping做的比较像样了。AOPServiceLocator部分,是以前做好的,一直都没有动过。现在我把所有的代码都公开出来,并写了一个简单的使用说明,希望能够对大家有所帮助。在这里,需要感谢的是徐芳波,在Websharp的开发过程中,也做了很多的工作,付出了很多。

本文主要说明Websharp O/R Mapping部分使用的内容。关于Websharp的设计理念,以及其他方面的内容,可以访问我的Bloghttp://sunnyym.cnblogs.com/  

从此处下载全部源代码

 

二.     Websharp O/R Mapping起步

Websharp ORM是一个轻量级的O/R Mapping框架,主要特点是抛弃了Java中常见的,也是其他一些O/R Mapping产品中使用XML文件来做映射描述的方法,而使用Attribute作为描述映射的方法,简单明了,并且,对开发人员来说,只有PersistenceManagerQueryTransaction等极少数接口需要掌握,上手快,使用非常方便。

因为在某些地方使用了范型,所以目前版本的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指明所引用的对象的类型,PrimaryKeyForeignKey用来指明两个类之间进行关联的主键和外键。这个类的定义如下:

         [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 SqlServerWebsharp目前不支持其他数据库的自动增长列。

这个类的定义如下:

         [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的主键IDOrder的外键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_TABLEONE_INHERITANCE_PATH_ONE_TABLEONE_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对象,

    Child 1 c 1 = new Child1();

    c1.Property1 = "P11";

    c1.Property2 = "P12";

    c1.Property3 = "P13";

并保存到数据库中的时候,数据库中的记录应该是:

Column1

Column2

Column3

Column4

P11

P12

P13

NULL

如果按照如下的代码初始化一个Child2对象:

    Child 2 c 1 = 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类并不映射到实际的表,Child1Child2类分别映射到Child1Child2表。因此,在这种情况下,需要把Parent类的TableMap特性设置为Null,而Child1Child2类的TableMap特性分别设置为Child1Child2,代码如下面所示:

    [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对象,

    Child 1 c 1 = 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对象,

    Child 1 c 1 = 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文件来作为映射手段,虽然这种使用方法很常见,但是,感觉使用起来非常不方便,我个人也时常为EJBHibernate里面的配置文件烦恼不已,而使用Attribute,明显感觉清爽了很多。这似乎也是未来的一个方向,这从EJB3.0的变化也可以看出。

Websharp O/R Mapping的结构设计,参考了JDO的很多东西,感觉在编程思想和面向对象方法的使用和讨论方面,Java阵营真是活跃的多。实际上,对于一个程序员来说,在对数个不同的技术都有了深入的了解以后,会发现自己对软件系统开发的看法有一种融会贯通的感觉。实现是一个方面,但同样重要的是结构。这两年,一直在同时做Java.Net的开发,很多时候是跨两个平台的开发,从两个平台中都收获不少。没有感觉Java或者C#对一个程序员来说有什么区别。那些关于JavaC#孰优孰劣的争论真是没有必要,也很肤浅。当然,C#作为一种后出的语言,在语法设计上的确有不小精妙的地方,这也是我崇拜Anders Hejlsberg的原因,也是我使用C#来实现Websharp的原因。但对于一个系统的开发来说,这种语言上的差异是可以忽略不计的。语言不是重要的,重要的是编程的思想。

一个人开发一个框架,是一件累人的事情,有的时候自己几乎就要放弃。现在虽然终于有了一个阶段的成果,但是,有些地方可能没有经过严格的测试,因此,希望各位同仁在使用的过程中,如果发现问题,能够及时告诉我,以便于我及时修正问题。也希望有人如果感兴趣,我们一起来发展这个项目。

从此处下载全部源代码

 

 


    在
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页