基于Grove实践ORM的感悟

转载 2004年07月01日 21:53:00

基于Grove实践ORM的感悟

名词解释<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

  • 数据访问层:基于逻辑分层(Layer)的应用程序中直接与数据库交互的应用程序代码。

  • 业务实体:应用程序中业务数据的载体,一般有DataSetxml文本、自定义类等表现形式。(详细信息

  • ORM:是Object Relation Mapping的所写。通俗的讲就是要建立业务实体与关系数据库的映射关系。(详细信息

Grove Develop Kit

        Grove Develop Kit是一套由国人开发的免费的数据持久层及相关工具,它包括Grove Develop Component和Grove Tool Kit 两部分
    Grove Develop Component是一套基于.NET的可重用开发组件,
为开发人员提供一个数据持久层并提供多种ORM方式,另外它也支持传统的ADO.Net式的数据库访问方式。
    Grove Tool Kit是基于微软VS的外接程序。通过使用Grove Tool Kit,开发人员能够在VS环境中直接从数据库表生成相应的业务实体类,极大的提高开发效率。

应用实例

说明

                本实例旨在说明Grove的应用要点,未提供操作细节。如果需要全部代码,请到这里下载。

创建环境

1)       Sql Server数据库中建立一个名为”Test”的数据库并建立如下两张表及对应关系(本实例所使用的业务数据类型非常简单,事实上Grove支持各种数据类型):

表名

字段

Customer

CustomerID     char(36)           PK
Name               varchar(50)

Addresse

AddressID       char(36)           PK
CustomerID     char(36)           FK
Location          varchar(200)

 

2)       VS中建立一个TestGrove的解决方案,它保护工程DALDataEntity,前者是数据访问层,后者是业务实体层。

3)       通过菜单工具-Grove Tool Kit”打开Grove的操作界面。通过点击该界面工具栏的”Set connection string”按钮来配置Grove的数据库操作环境。配置完成后连接数据库可看到AddressCustomer这两张表。(工具栏第二个按钮用于设置数据库连接字符串,第一个按钮用于连接数据库,第三个按钮用于创建业务实体类)

<?xml:namespace prefix = v ns = "urn:schemas-microsoft-com:vml" />grove.jpg

建立业务实体

        本实例使用自描述自定义类作为业务实体类。所谓自描述,就是在该类中用Attribute的形式包含了与数据库的映射关系。个人认为此种方式容易理解和维护。

4)       Grove界面选择Address表,点击代码生成按钮将得到以下代码:

                [DataTable("Address")]

                public class Address

                {

                                String _AddressID;

                                String _CustomerID;

                                String _Location;

 

                                [KeyField("AddressID")]

                                public String AddressID

                                {

                                                get{return this._AddressID;}

                                                set{this._AddressID=value;}

                                }

                                [ForeignKeyField("CustomerID")]

                                public String CustomerID

                                {

                                                get{return this._CustomerID;}

                                                set{this._CustomerID=value;}

                                }

                                [DataField("Location")]

                                public String Location

                                {

                                                get{return this._Location;}

                                                set{this._Location=value;}

                                }

                }

                注意:Grove对关键字字段进行映射时会将该字段看成自增类型。本实例未使用自增ID做关键字,所以需要手动调整。调整后AddressID属性的代码如下:

                                [KeyField("AddressID",KeyType = UniqueIDType.OtherDefinition)]

                public String AddressID

                {

                        get{return this._AddressID;}

                        set{this._AddressID=value;}

                }

        用同样的方法得到Customer业务实体类,代码如下:

        [DataTable("Customer")]

        public class Customer

        {

                String _CustomerID;

                String _Name;

                [KeyField("CustomerID",KeyType = UniqueIDType.OtherDefinition)]

                public String CustomerID

                {

                        get{return this._CustomerID;}

                        set{this._CustomerID=value;}

                }

                [DataField("Name")]

                public String Name

                {

                        get{return this._Name;}

                        set{this._Name=value;}

                }

        }

5)       生成业务实体强类型集合类:Grove暂时不支持直接生成业务实体集合类,好在这部分工作很简单(写完一个后用copyreplace就能搞定),代码如下(为使代码简单只实现了集合最基本的方法):

public class AddressCollection : CollectionBase

        {

                public Address this[Int32 index]

                {

                        set

                        {

                                this.List[index] = value;

                        }

                        get

                        {

                                return (Address)this.List[index];

                        }

                }

                public Int32 Add(Address value)

                {

                        return this.List.Add(value);

                }

   }

        public class CustomerCollection : CollectionBase

        {

                public Customer this[Int32 index]

                {

                        set

                        {

                                this.List[index] = value;

                        }

                        get

                        {

                                return (Customer)this.List[index];

                        }

                }

 

                public void Add(Customer value)

                {

                        this.List.Add(value);

                }

   }

6)       修改Customer类,为其添加一个Addresses的属性,访问该属性可获取Customer对象对应全部Address。添加如下代码:

                private AddressCollection _addresses;

                public AddressCollection Addresses

                {

                        get

                        {

                                if(this._addresses == null)

                                        this._addresses = new AddressCollection();

                                return this._addresses;

                        }

                }

 

建立数据访问层

7)       ORM功能:Grove 提供ORM功能最重要的两个接口是IObjectOperatorIObjectQuery,前者为业务实体提供InsertUpdateDelete的功能,后者主要负责业务实体的查询。Grove没有提供直接实现IObjectOperator接口的public的类型,但我们可以通过ObjectOperatorFactory这个工厂类来得到一个实现了IObjectOperator接口的实例。代码如下:

public class CustomerDB

{

        //插入一个Customer对象

        public static void Insert(Customer customer)

        {

                IObjectOperator objectOperator =

                        ObjectOperatorFactory.GetObjectOperator();

                objectOperator.BeginTranscation();//开始事务

                try

                {

                        //插入Customer对象与数据库有映射关系的属性值

                        objectOperator.InsertObject(customer);

                        //插入Customer对象对应的Address对象

                        objectOperator.InsertObjects(customer.Addresses);

                        objectOperator.Commit();//提交事务

                }

                catch

                {

                        objectOperator.Rollback();//回滚事务

                        throw;

                }

                finally

                {

                        objectOperator.Dispose();

                }      

        }

        //更新一个Customer对象

        public static void Update(Customer customer)

        {

                IObjectOperator objectOperator =

                        ObjectOperatorFactory.GetObjectOperator();

                objectOperator.BeginTranscation();

                try

                {

                        //更新Customer

                        objectOperator.UpdateObject(customer);

                        //删除Customer对象对应的Address

                        objectOperator.RemoveChildObjects(

                                customer.CustomerID, typeof(Address));

                                //插入Customer对象对应的Address对象

                        objectOperator.InsertObjects(customer.Addresses);

                        objectOperator.Commit();

                }

                catch

                {

                        objectOperator.Rollback();

                        throw;

                }

                finally

                {

                        objectOperator.Dispose();

                }

        }

        //删除一个Customer对象

        public static void Remove(Customer customer)

        {

                IObjectOperator objectOperator =

                        ObjectOperatorFactory.GetObjectOperator();

                objectOperator.BeginTranscation();

                try

                {

                        //删除Customer对象

                        objectOperator.RemoveObject(customer);

                        //删除Customer对象对应的Address

                        objectOperator.RemoveChildObjects(

                                customer.CustomerID,typeof(Address));

                        objectOperator.Commit();

                }

                catch

                {

                        objectOperator.Rollback();

                        throw;

                }

                finally

                {

                        objectOperator.Dispose();

                }              

        }

        //通过查询条件获取Customer集合

        public static CustomerCollection ReadCustomers(String filter)

        {

                IObjectOperator objectOperator =

                        ObjectOperatorFactory.GetObjectOperator();

                IObjectQuery objectQuery =

                        objectOperator.NewQuery(typeof(Customer));

                objectQuery.Filter = filter;//设置查询条件

 

                CustomerCollection customers =new CustomerCollection();

                ArrayList alCustomers;

                try

                {

                        alCustomers = objectQuery.Execute(typeof(Customer));

                        foreach(Object oCustomer in alCustomers)

                        {

                                Customer customer = (Customer)oCustomer;

                                //读取Customer对应的Address集合

                                ArrayList alAddresses = new ArrayList();

                                objectOperator.RetrieveChildObjects(

                                        customer.CustomerID,alAddresses,typeof(Address));

                                foreach(Object oAddress in alAddresses)

                                {

                                        customer.Addresses.Add((Address)oAddress);

                                }

                                customers.Add(customer);

                        }

                }

                finally

                {

                        objectOperator.Dispose();

                }

                return customers;

        }

}

以上代码随便比较长,但结构比较清晰,思路基本都是创建ObjectOperator > 开启事务 -> 操作数据库 -> 释放ObjectOperator,调用过程都使用了try来捕获异常。另外值得一提的是Grove返回数据实体集合的时候是以ArrayList形式保存的,需要进行一下类型转换,然后添加到自定义的业务实体集合种。

8)     使用SQL或存储过程:有时候上面这个数据访问类并不能完全满足我们的要求,比如我们需要知道当前数据库种Customer的数量,当然这可以通过Ado.net来实现,但用Grove来实现的话更简便,代码如下(添加到CustomerDB类种):

//读取所有Customer的数量

        public static Int32 GetCustomerCount()

        {

                IDbOperator dbOperator = DbOperatorFactory.GetDbOperator(

                        Grove.AppSettingManager.getAppSetting("DBConnString"));

                try

                {

                        return Convert.ToInt32(

                                dbOperator.ExecScalar("Select count(*) from customer"));

                }

                finally

                {

                        dbOperator.Dispose();

                }

     }

意见和建议

  • Grove所需的配置信息只能通过应用程序配置文件进行设置,不能用属性直接设置,不利于进行单元测试。

  • ArrayListDataSet形式返回数据实体集合,最好再能以CollectionBase的形式返回数据实体集合,这有利于操作强类型的数据实体集合。

  • 支持自动生成强类型的数据实体集合。

  • 能够在VS英文环境下生成代码文件。

参考资料

面向对象编程的实践感想

经过这次TOP(Thinking Oriented Programming)的相关学习之后,觉得TOP对我的启发是很大的。         这次作业可以在CoffeeScript和LiveScrip...
  • huangxiongbiao
  • huangxiongbiao
  • 2015年04月05日 09:21
  • 722

尝试使用Grove Starter Kit for Arduino的LCD模块(彩色背光)

首先下载示例程序到本机。采用世界公认的GitHub。Grove Starter Kit for Arduino的代码库也在上面。 直接在GitHub客户端(那只小猫)不能直接输入代码库的网址。它提示你...
  • qxd100
  • qxd100
  • 2015年10月01日 09:20
  • 662

介绍几种ORM框架

ORM(object relation mapping) 对象关系映射关系 ,面向对象的对象模型和关系型数据之间的相互转换。基于关系型数据库的数据存储,实现一个虚拟的面向对象的数据访问接口。理想状态下...
  • changyinling520
  • changyinling520
  • 2017年02月24日 22:44
  • 4519

【Java进阶】实现自己的ORM框架

【Java进阶】实现自己的ORM框架本文将介绍简单的ORM框架的实现过程。为了能够顺利的读懂本文,你需要有JDBC、注解和反射的基础知识。01 创建数据库和表说明,这里使用的是MySQL数据库,版本号...
  • liyazhou0215
  • liyazhou0215
  • 2017年08月20日 18:58
  • 2017

一个超轻量级的 ORM 框架

在上集里,我与大家分享了有关“数据访问层”的相关解决方案。这里是上集的链接: http://my.oschina.net/huangyong/blog/265378 数据访问层说得专业一点就是 D...
  • rdhj5566
  • rdhj5566
  • 2016年10月18日 21:05
  • 1917

c++课程学习心得

/*  *Copyright (c) 2016,烟台大学计算机学院  *All rights reserved.  *文件名称 :  *作 者 : 徐聪  *完成日期 : 2016年6月23...
  • ccxucong
  • ccxucong
  • 2016年06月23日 08:51
  • 493

Android数据库Realm实践

Android开发中常用的数据库有5个: 1. OrmLite OrmLite 不是 Android 平台专用的ORM框架,它是Java ORM。支持JDBC连接,Spring以及Androi...
  • xiangzhihong8
  • xiangzhihong8
  • 2016年08月05日 17:44
  • 1577

Android Orm框架分析

笔记摘要:最近准备使用数据库做个缓存,以前因为项目中的实时性要求比较高,所以在整体的框架中就没有加缓存,有些地方只是简单的将对象保存到了Preference中,所以并没有对数据库方面有所研究,既然准备...
  • DDK837239693
  • DDK837239693
  • 2016年05月05日 13:51
  • 2881

自已动手写ORM框架(3)——封装JdbcUtil

JDBC常用功能封装
  • fanwenjieok
  • fanwenjieok
  • 2015年07月16日 16:26
  • 863

自己动手写ORM框架(五):关系映射配置—Column属性

这次将完成最后一个自定义属性功能Column,在讲Column实现之前先看看Student表的结构如下: create table student ( studentid VARCHAR...
  • sundacheng1989
  • sundacheng1989
  • 2013年02月25日 14:32
  • 2172
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:基于Grove实践ORM的感悟
举报原因:
原因补充:

(最多只允许输入30个字)