当前位置: 首页 > 工具软件 > Gentle.NET > 使用案例 >

Gentle.NET Users' Guide

汤弘文
2023-12-01

------------------------------------------------------------
用户指南 - Gentle.NET 概述
------------------------------------------------------------
1. 什么是持续框架(PersisitenceFramework)?
    将对象映射到关系数据库的一种快速开发框架
    理论背景,可参考
        ·持续化思想http://www.ambysoft.com/downloads/persistenceLayer.pdf
        ·OR映射:http://www.agiledata.org/essays/impedanceMismatch.html
        ·NULL值处理:
    附加信息
        ·微软进行持续框架研究(ObjectSpaces)已经好几年了,但很不幸的是,它被无限期延后了(最新的消息是在Loghorn服务器在2007年发布时,它将随WinFS一起被提供)
        ·然而,关于持续框架是什么,为什么你需要使用它,微软提供了比较有用的背景信息,可以参看http://www.15seconds.com/issue/040112.htm
2. Gentle概述
    ·metadata(attributes and database schema analysis)
    ·business object(base classes and interfaces)
    ·architecture (framework and database access)
    ·encapsulating parameters (criteria and object identifiers)
    ·custom queries
    ·query results(and object construction)
    ·presentation (custom dataview generation)
    ·transactions

3. 使用 Gentle.NET
3.1 基本例程
    using Gentle.Framework;

    [TableName("Users")]
    public class User : Persistent
    {
        private int userId;
        private string userName;
        // this is used by clients to construct new users
        public User( string userName ) : this( 0, userName ) {}
        // this is used by Gentle to reconstruct objects read from the database
        public User( int userId, string userName )
        {
            this.userId = userId;
            this.userName = userName;
        }
        [TableColumn("UserId"), PrimaryKey(AutoGenerated=true)]
        public int Id
        {
            get{ return userId; }
            set{ userId = value; }
        }
        [TableColumn(NotNull=true)]
        public string Name
        {
            get{ return userName; }
            set{ userName = value; }
        }

        //----------------------------------------------------------       
        // this is used by client to fetch users from the database
        static public User Retrieve( int userId )
        {
            Key key = new Key( typeof(User), true, "Id", userId );
            return Broker.RetrieveInstance( typeof(User), key ) as User;
        }
    }

    User user = new User( 42, "Ford Prefect" );
    Broker.Insert( user ); // 把user对象保存到数据库
    Key key = new Key( typeof(User), true, "Id", 42 ); // 使用单项选择限制条件值来创建关键字(create a key with a single selection criteria value)
    user = Broker.RetrieveInstance( typeof(User), key ) as User; // 重数据库获取指定user对象(load the specified user from the database)

    // 若User继承至Persistent,可以简化为:
    User ford = new User( "Ford Prefect" );
    ford.Persist(); // 保存新user并分配了id
    User prefect = User.Retrieve( ford.Id ); // 获取指定user

 

3.2 获取列表
    获取所有user对象实例
        static public IList ListAll
        {
            get{ return Broker.RetrieveList( typeof(User) ); }
        }
    定制查询
        static public IList ListByNameStartsWith( string partialName )
        {
            SqlBuilder sb = new SqlBuilder( StatementType.Select, typeof(User) );
            // note: the partialName parameter must also contain the %'s for the LIKE query!
            sb.AddConstraint( Operator.Like, "Name", partialName );
            // passing true indicates that we'd like a list of elements, i.e. that no primary key
            // constraints from the type being retrieved should be added to the statement
            SqlStatement stmt = sb.GetStatement( true );
            // execute the statement/query and create a collection of User instances from the result set
            return ObjectFactory.GetCollection( typeof(User), stmt.Execute() );
        }

3.3 用GentleList来处理关联
    GentleList继承至从ArrayList,与普通的list很相似,并添加了持续化保存得特性.
    它支持以下类型的关联: StandAlone, OneToMany, ManyToMany
        ·standAlone
            GentleList list = new GentleList( typeof(User) );
        ·OneToMany
            GentleList list = new GentleList( typeof(User), parentInstance );
        ·ManyToMany
            GentleList list = new GentleList( typeof(User), role, typeof(UserRole) );


3.4 关联
    获取与account相关联的account对象列表
    public IList Accounts
    {
        get{ return RetrieveList( typeof(Account), "Id" ); }
    }

    外键关联
    [TableColumn("SubscriberId"), PrimaryKey, ForeignKey("User","UserId")]
    public int SubscriberId
    {
        get{ return subscriberId; }
        set{ subscriberId = value; }
    }

3.5 用MagicValue来处理NULL值
    int等类型不允许赋null值,而数据库中对应的字段是允许的,如何处理这种映射?
    注:c#2.0中提供允许空的数值类型
    在Gentle.Net中使用MagicValue来处理这种转化
        数值类型.null<-->null字段
        DateTime.Min <-->null字段,但很多数据库不支持datatime类型,很可能被截断。比较危险
    例程
        [TableColumn("id", NotNull=true), PrimaryKey(AutoGenerated=true)]
        protected int id;
        [TableColumn("name", NullValue="")]
        protected string name;
        [TableColumn("remark", NullValue="")]
        protected string remark;
 
    例程http://www.mertner.com/svn/repos/projects/gentle/Source/Gentle.Framework.Tests/BusinessObjects/PropertyHolder.cs
        [TableColumn( NotNull=false, NullValue=-1 )]
        public int TInt
        {
            get { return _int; }
            set { _int = value; }
        }

        [TableColumn( NotNull=false, NullValue=NullOption.MinValue )]
        public decimal TDecimal
        {
            get { return _decimal; }
            set { _decimal = value; }
        }

        // note: this field can be null
        // setting here is wrong for the purpose of testing SqlAnalyzer override
        [TableColumn( NotNull=true, NullValue=0 )]
        public double TDouble
        {
            get { return _double; }
            set { _double = value; }
        }
       
        [TableColumn( NotNull=false )]
        public DateTime TDateTime
        {
            get { return _datetime; }
            set { _datetime = value; }
        }
    对可空类型的支持尚在日程表中,但还不是很紧迫。可以到JIRA查看开发进度
    http://www.mertner.com/jira/browse/GOPF-30


3.6 创建DataView
    不再推荐使用ObjectView类。请在数据绑定时使用TypedArrayList和TypedArrayItemBase来定制对象的展示
 
3.7 同步控制
    Gentle.Net提供行级别得同步控制,来取保数据完整性
    为了使用同步控制功能,需要添加一个integer类型字段,并在代码中赋予Concurrency特性。
    当你尝试更新一个过期数据时,gentle会抛出异常Error.Recordchanged。故必须封装所有更新操作捕获该错误。
    如果你使用Persistent作为基类,通过创建自己的基类并重载更新方法来实现它?
    可以使用Refresh方法来修复同步错误(在Persistent,PersistenceBroker和Broker类中),它会重新获取新数据,再重新调用更新操作
 
3.8 缓存(Caching)和 唯一性(Uniqing)
    (1)出于提高性能考虑而采取的策略
    (2)缓存配置
            DefaultStragegy = Temporary | Never | Permanent
            CacheStatements = true | false
            CacheObjects    = false | true
            SkipQueryExecution = false | true
            UniqingScope    = Thread | Application | WebSession
         缓存配置例子
            <Cache>
                <DefaultStrategy>Temporary</DefaultStrategy>
                <CacheStatements>true</CacheStatements>
                <CacheObjects>true</CacheObjects>
                <SkipQueryExecution>false</SkipQueryExecution>
                <UniqingScope>Thread</UniqingScope>
            </Cache>
         SqlStatement对象的缓存:GentleNet自动缓存所有statement对象
         对象的缓存
         QuerySkipping
            当开启SkipQueryExecution时,Gentle将缓存查询结果信息
            若该信息在先前已被缓存,则gentle使用已缓存的对象来构建查询结果,这样就免去了数据库操作,大大改善了查询性能。严重推荐。
    (3)对象唯一性(Object Uniqing)
        使用对象唯一性,就不必操作多个内存对象来描述同一数据库行。
        这不仅是一种节省内存的机制,也有助于防止数据不一致
    (4)对象缓存和唯一性带来的线程安全问题
        然而,既然使用了对象缓存和唯一性,某个线程就可以使用另外一个线程使用的对象引用,这就引进了线程安全性问题
        为了解决这种问题,gentle提供了UniqingScope设置,用于将缓存和唯一性特性限制到应用程序范畴(Application Scope)或线程范畴(Thread Scope)
            ·应用程序范畴:在统一AppDomain中的对象使用相同的缓存
            ·线程范畴:每个线程使用自己的缓存
        线程范畴保证了线程安全,当如果在每个线程中都创建很多对象的话,缓存机制就没有什么意义了
        故,通常对于ASP.NET应用程序使用线程范畴,而其它使用应用程序范畴。
    (5)监控缓存使用情况(Monitoring)
        GentleStatistics.LogStatistics( LogCategory.Cache )
    (6)提示和窍门
        使用Gentle.Common.CachedManager类
            例如,可以使用它将对象永久保存在内存。
            该类非常有用,例如缓存custom IGentleProvider或PersistenceBroker对象,Gentle自动确保它们不会被垃圾收集所释放
            在ASP.NET应用程序中,需要维护一个键用于保存缓存中的项目,例如创建一个guid并将它保存在session中或保存在页面的ViewState变量中。
            当然,必须小心使用永久缓存对象功能,要是你不告诉CacheManager,它们将永久保存在缓存中

3.9 验证Validation
    Gentle验证框架提供了程序验证公用层(common layer)
    提供的验证器
        RegexValidator         [RegexValidator(Express=@"[A-Z]+[a-..."]
        RequiredValidator      [RequiredValidator()]
        RangeValidator         [RangeValidator(Min=20.5, Max=100.5)]
    自定义验证器
        需要扩展ValidatorBaseAttribute或实现在Validate方法中被调用的IValidationPersistent接口
        该方法在更新和新建时被调用

4 OR 映射技术
    遗传映射(Inheritance Mapping)
        Gentle使用“一个类,一张表”的方法来实现对象层次映射
            这种方法最早被实现并很好的实现了,是最主要的方法
            这意味着任何类都对应一种表
            当对象无关联并不共享字段时,这种方法干得不错
            是一种“平”对象继承(flat object hierachy)
            可参考这篇非常棒的文章:http://www.agiledata.org/essays/mappingObjects.html#MapEachClassToTable
        也可以使用多个类映射到单张表
            用一个字段来存储记录类型,该字段必须标注TableColumn和Inheritance特性
            如果你有许多有共享字段且相关联的类,这种方法是比较有用的。
            When you select the classes, gentle will filter out rows that are not the specified type itself or a descendant of it.
            可以查看测试项目中的MultiType.cs 和 TestMultiType.cs 文件,看看他们是如何工作的:
            [TableName( "MultiType" )]
            public abstract class MultiType : Persistent
            {
                [TableColumn, PrimaryKey( AutoGenerated=true ), SequenceName( "MULTITYPE_SEQ" )] protected int id = 0;
                [TableColumn, Inheritance] protected string type;
                [TableColumn] protected int field1 = 1;
                [TableColumn] protected decimal field2 = 2;
                [TableColumn] protected double field3 = 3;
                [TableColumn] protected string field4 = "4";
       
                public MultiType()
                {
                }
       
                public static object Retrieve( Type t, int id )
                {
                    Key key = new Key( t, true, "id", id );
                    return Broker.RetrieveInstance( t, key );
                }
       
                public static MultiType Retrieve( int id )
                {
                    Key key = new Key( typeof(MultiType), true, "id", id );
                    return Broker.RetrieveInstance( typeof(MultiType), key ) as MultiType;
                }
       
                public int Id
                {
                    get { return id; }
                }
                public string Type
                {
                    get { return type; }
                }
            }
       
            [TableName( "MultiType" )]
            public class Animal : MultiType
            {
                new public static Animal Retrieve( int id )
                {
                    return Retrieve( typeof(Animal), id ) as Animal;
                }
            }
       
            [TableName( "MultiType" )]
            public class Dog : Animal
            {
                new public static Dog Retrieve( int id )
                {
                    return Retrieve( typeof(Dog), id ) as Dog;
                }
            }
       
            [TableName( "MultiType" )]
            public class Cat : Animal
            {
                new public static Cat Retrieve( int id )
                {
                    return Retrieve( typeof(Cat), id ) as Cat;
                }
            }           
        Aggeregated Object
            将单个类映射到一个或多个父类的字段
            例子:Money类具有Currency和Amount属性
            不太明白p34
        动态表映射
            在类中通过实现ITableName接口来重载表名(在TableName特性中设置)
            若你的类中实现了该接口,Gentle会检测到,以访问不同的表
性能考虑
    数据库分析
        gentle使用特性attributes(曾用xml来支持)来映射metadata和数据库
    对象创建
        gentle可以使用几乎所有有效的构造器来创建对象,并且,对于列数组,gentle将自动的采用最低成本的构造方式。
        创建成本是以下方面的总和:p36
    缓存(Caching)
    性能比较

                           
------------------------------------------------------------
使用MyGeneration-Gentle.NET 业务实体模板
------------------------------------------------------------
MyGeneration:http://www.mygenerationSoftWare.com
BusinessEntity.csgen(Gentle.NET Business Entity $Rev:942$)


 

 类似资料:

相关阅读

相关文章

相关问答