支持运行时模型扩展的对象关系映射***和方法
技术领域
本发明涉及对象关系映射(ORM)***,具体地说,涉及支持运行时模型扩展的对象关系映射***和方法。
背景技术
随着面向对象的程序设计变为企业软件开发的范例,对象关系映射(ORM)已成为一种越来越受欢迎的实现对象持久性的技术。在面向对象的(OO)的程序设计中,数据管理任务一般是通过操纵对象来实现的。然而,关系数据库例如DB2、Oracle只能存储和操纵关系数据,这些关系数据被组织在表中。因此,为了将对象保存到数据库中,程序员必须手动设计对象的关系数据库模式(schema)并把对象转换成关系记录。对于比较小的对象模型而言,这可能比较容易。但是在应用大规模对象模型的情况下,需要使用的对象模型越来越多,为对象模型手工设计数据库会变得困难。
对象关系映射(ORM)被用于将面向对象的程序设计模型映射到由Oracle、DB2、Sybase和其它关系数据库管理器(RDBMS)管理的关系数据库模型。从程序员的角度看,ORM***应当看起来象一个永久的对象存储库。程序员只需生成对象并将它们传送到ORM***。ORM***自动地将这些对象保存到关系数据库中。目前有很多流行的ORM产品,例如Websphere Metadata Server(XMeta)、Apache OJB、Hibernate、Oracle’s TopLink等。
下面参考图1介绍ORM***的基本组成和工作原理。
图1示出了现有技术的ORM***10的结构框图,它包括模型注册模块11、对象关系(OR)映射模块12和关系数据库(RDB)13。在ORM***10以外还有代码生成器17和应用程序18。代码生成器17用于识别面向对象的模型中的类和属性,根据识别结果生成应用程序接口(API)并将生成的API传递给应用程序18。应用程序18利用从代码生成器17传递来的API生成对象。关于代码生成器17和应用程序18的操作是本领域的技术人员公知的,这里不再详细描述。
为了使用ORM***10,用户需要将面向对象的模型注册到ORM***10。该***10利用对象关系映射模块12产生适于已注册的模型的关系数据库模式。然后,应用程序18可以将符合已注册模型的对象串行送入ORM***10。对象关系映射模块12把这些对象自动翻译成SQL(结构化查询语言)语句。通过使用ORM***10,程序员可以以面向对象的方式将注意力集中于商业逻辑,而不需要花费时间手动处理对象进行关系数据库翻译,这将大大减轻程序员的工作负担。下面举例说明应用ORM***的典型步骤。
(1)由设计人员根据所需的商业逻辑设计适于具体应用的面向对象的模型,例如在一个机票预订***中,可以声明一个类“TicketOrder”,它包含例如三个属性:时间“Time”、客户姓名“Name”、航班号“Flight”,当然在实际中可以包含更多的属性,例如价格、航空公司名称、退票/改签等等,这里只是举例说明。当然,如果模型已经存在,则可以跳过这个步骤。
(2)将步骤(1)中的数据模型分别输入到代码生成器17和ORM***10中的模型注册模块11,在模型注册模块11中注册该数据模型并将其输入到对象关系映射模块12。对象关系映射模块12根据数据模型产生关系数据库模式,这里的关系数据库模式例如是指在关系数据库13中的表的结构。另一方面,如上所述,代码生成器17根据面向对象的模型生成相应的API。
(3)对象关系映射模块12在步骤(2)中产生的关系数据库模式被部署到关系数据库13中。
(4)应用程序18利用生成的API产生数据对象,对象关系映射模块12使用SQL语言将该数据对象保存/加载到关系数据库13中。在上述例子中,每次有一个客户提出机票预订请求,应用程序18就生成一个数据对象,它含有与“Time”、“Name”、“Flight”相对应的三个属性值。这个数据对象被保存到关系数据库13中,成为表的一个条目。
以上例子可以参考下面的表,在该表中还附加了一个“ID”列,这可以在生成关系数据库模式时由对象关系映射模块12自动加入。当然,这一列也可以不存在。
类:TicketOrder
与传统的关系数据库相比,ORM***具有很多优势。然而,在应用ORM***时也有一些限制。大多数ORM***方案使用水平存储模式,例如,在关系数据库中每个类具有一个相关的表,类的每个属性在该表中都具有一个相关的列,而类的每个实例(一个对象)对应于表的一行记录。当模型不变时这没有任何问题。但是,数据模型确实会发生改变,特别在SOA(面向业务的体系结构)环境中更是如此。例如,当税收条例修改时,航空公司需要向机票预订表中附加一个“燃油附加税”项。在这样的情况下,用于售票***的数据模型只需要向“TicketOrder”类附加一个“FuelCompTax”属性。但是,为了适应这个微小的改变,用户需要(1)使ORM***停止运行;(2)重新注册新的模型,生成新的关系数据库模式,并将关系数据库13中适于旧模型的数据迁移到新的模型下;3)适于旧的API版本的应用程序18也需要升级到新的API。
可见,目前的ORM***不支持运行时的模型扩展,因为一旦模型被注册,关系数据库模式就被产生并被部署到关系数据库。为了升级ORM***,即使是很小的变化,也需要使***停止运行,注册新的模型并迁移数据,还要产生新的API并升级应用程序,这在时间和费用上都很不经济,还会影响商业***的正常运行,有时这是不能容忍的。现在需要一种在模型改变时不必使***停止运行,而是支持在运行时对部署在ORM***中的模型进行动态扩展的***和方法。
发明内容
为了解决以上问题,本申请提出一种通过添加元组存储子***而支持ORM***的运行时扩展的***和方法。这里的元组存储子***是指将数据划分成格式统一的多元组后进行存储管理的***。
为了在运行时扩展已经部署的模型,用户需要注册模型的扩展部分。当需要保存的数据到来时,***会自动地将与模型的扩展部分有关的数据转换成多元组并保存到元组存储子***中。与模型的扩展部分无关的数据仍按已部署的模型被保存到关系数据库中。通过这种方式,本发明就可以支持对已部署的模型的动态扩展,而不改变部署到关系数据库的关系数据库模式,也不用迁移关系数据库中的数据。
根据本发明的一个方面,提供了一种支持运行时模型扩展的对象关系映射***,包括用于以关系数据的格式存取对象的关系数据存储子***,其特征在于该***还包括:元组存储子***,用于以多元组的格式存取对象;和分派器/组装器,用于根据对象的模型信息,分别对关系数据存储子***和元组存储子***进行对象的存取。
在本发明的上述***中,还可以包括模型注册模块,用于注册对象的模型信息,以及响应于分派器/组装器的请求将注册的模型信息提供给分派器/组装器。其中,对象的模型包括原始模型和至少一个在原始模型扩展后形成的扩展模型。符合扩展模型的对象包括两个不同的组成部分:与原始模型有关的数据以及与扩展部分有关的数据。
在上述***中,关系数据存储子***可以包括:关系数据库,用于存储对象;和对象关系映射模块,耦合在所述分派器/组装器和所述关系数据库之间,用于对所述关系数据库进行对象的存取。元组存储子***可以包括:多元组存储库,用于存储多元组格式的数据;和对象-多元组翻译器,耦合在所述分派器/组装器和所述多元组存储库之间,用于将对象翻译成多元组格式的数据并保存到多元组存储库,或者从多元组存储库中取出多元组格式的数据并翻译成对象。
在上述***中,分派器/组装器可以包括:识别装置,用于识别要存取的对象符合原始模型还是在该原始模型扩展后形成的扩展模型,根据识别结果向模型注册模块请求相应的模型信息,以及根据从模型注册模块获得的模型信息在符合扩展模型的对象中区分与原始模型有关的数据以及与扩展部分有关的数据;分派装置,用于在保存数据时,将与原始模型有关的数据和与扩展部分有关的数据分别分派给关系数据存储子***和元组存储子***进行保存;和组装装置,用于在取出数据时,将分别从所述关系数据存储子***和所述元组存储子***取回的与原始模型有关的数据和与扩展部分有关的数据组装成符合所需模型的对象。
在本发明的上述方面中,分派器/组装器与位于该***外部的应用程序相关联,由应用程序请求分派器/组装器存取对象。在***外还存在一个代码生成器,它根据不同的对象模型产生不同版本的API并提供给所述应用程序,而分派器/组装器的识别装置通过识别对象的API版本来识别该对象符合的模型。
根据本发明的另一方面,提供了一种支持运行时模型扩展的对象关系映射方法,包括:根据请求存取的对象的模型信息,分别以关系数据格式和多元组格式存取该对象的不同组成部分。
本发明的上述方法还可以包括:注册对象的模型信息。对象的模型包括原始模型和至少一个在原始模型扩展后形成的扩展模型。
在本发明的上述方法中,所述存取对象的步骤还包括:在请求存取对象时,识别所请求的对象符合原始模型还是在该原始模型扩展后形成的扩展模型;如果所请求的对象符合原始模型,则以关系数据格式存取该对象;如果所请求的对象符合某种扩展模型,则:根据注册的模型信息,区分该对象中与原始模型有关的数据以及与扩展部分有关的数据;对于与原始模型有关的数据,以关系数据格式进行存取;对于与扩展部分有关的数据,以多元组格式进行存取。
在上述方法中,在请求取出对象的情况下,如果所请求的对象符合扩展模型,则将分别具有关系数据格式的与原始模型有关的数据和具有多元组格式的与扩展部分有关的数据组装成符合所需的扩展模型的对象。
在上述方法中,可以通过识别被请求存取的对象的API版本来识别该对象符合的模型。
根据以上简要介绍的发明内容可以知道,本发明通过将扩展的对象分成两部分,一部分仍符合原始模型并按原关系数据库模式保存,另一部分则被翻译成多元组的形式来保存。这样,模型扩展就可以在运行时动态地进行,不必修改关系数据库数据库中的模式,从而消除了使***停止运行、升级关系数据库模式和迁移数据的必要,减小了对***运行的影响,降低了成本。
附图说明
结合附图参考以下对本发明实施方式的详细描述,将会清楚本发明的特征和优点。图中相同的标号代表相同的元件,在附图中:
图1示出了传统的ORM***的总体框图。
图2示出根据本发明一种实施方式的扩展的ORM***的体系结构。
图3示出了扩展的ORM***在保存对象时的工作流程。
图4示出了扩展的ORM***在取出对象时的工作流程。
具体实施方式
本发明的目的是支持ORM***的运行时模型扩展。面向对象的模型的扩展或者说修改可能有多种,包括例如:
●向现有的类添加新的属性;
●从现有的类删除属性;
●在现有的类之间添加新的关系;
●删除现有的类之间的关系;
●添加新的类
-向新的类添加属性;
-在新的类和现有的类之间添加新的关系;
●删除新的类;
●重命名操作,该操作可以通过添加/删除操作来实现。
当然,可以理解,模型的扩展或者修改不限于以上列举的种类,这里只是举例说明。
图2示出根据本发明一种实施方式的扩展的ORM***20的体系结构。扩展的ORM***20包括模型注册模块11、分派器/组装器24、关系数据存储子***28和元组存储子***27。关系数据存储子***28包括对象关系映射模块12和关系数据库13,它们的功能与图1中所示的部件相同。元组存储***27包括对象-多元组翻译器25和多元组存储库26。
在传统的ORM***中,被指定为类的对象在关系数据库中以表的一个条目(一行记录)的形式存在,它包括对应于每个属性(每列)的属性值。例如,参考上面的TicketOrder类,第一行(1;17:20PM onMay 11,2007;王军;CZ1246)代表了一个对象,它有对应于“ID”、“Time”、“Name”和“Flight”四个属性的属性值。同样,在表的第2,3,......行中还可以有其它对象。
不同的是,多元组或者说n元组是指有n个(n是大于2的整数)组成部分的有限序列。元组数据是被用来描述多元组的组成部分的数据。一种典型的多元组是三元组,它是具有<主,谓,宾>格式的数据结构。在以三元组格式存储时,对象的每个属性被表示为一个三元组。例如被指定为TicketOrder类的对象A,它具有四个属性:ID、Time、Name和Flight,分别被表示为<A,ID,1>、<A,Time,17:20PM May 11,2007>、<A,Name,王军>和<A,Flight,CZ1246>。这里,对象名“A”是主语,对象的属性是谓语,具体的属性值是宾语。
在本申请中,元组存储***是指将数据划分成格式统一的多元组后进行存储管理的***。相应地,三元组存储***就是把数据划分为主谓宾的三元组结构来存储和取回数据的体系结构。在三元组存储***中,分别代表对象A的四个属性的四个三元组将顺序存储。同样,其它对象也可以表示成一组(例如四个)三元组,并且依次加载到三元组存储***中。
本领域的技术人员可以理解,这里的多元组不限于三元组,元组存储***也不限于三元组存储***,而是可以根据实际需要采用其他元组形式。例如,可以采用四元组,即在上述三元组结构的基础上增加一个新的组成部分,例如数据创建时间、数据创建路径等其它信息。
元组存储的优点就是它具有被扩展和修改的能力,而不需要重新设计。例如,假设对象增加一个新的属性,关系数据库就要重新设计和部署新的关系数据库模式,在表中增加一列,而在元组存储***中只需要在一个对象的原有多元组的后面顺序添加与新的属性相对应的新的多元组。例如在上述TicketOrder类的三元组存储的例子中,如果添加了“燃油附加税”的属性,则可以在三元组存储***中加入新的三元组<A,FuelCompTax,50>即可,而无需改变原有的三元组。可见,关系数据库是一种基于列的存储方式,而多元组是一种基于行的存储方式。元组存储***的扩展能力强,但存储效率不如关系数据库。目前,已经存在很多成熟的元组存储产品,例如IBM公司的SOR、Webify Triple Store和Oracle公司的Oracle 10g。
现在返回图2,进一步描述扩展的ORM***20的组成和功能。模型注册模块11是用户用于注册对象模型以及声明模型扩展的组件。它将记录两种类型的信息,一种是首次注册的模型,另一种是有关每个版本的扩展模型的信息。模型注册模块11的一种可能的实施方式是:对于每个版本的新模型,模型注册模块11将记录它与原始版本的模型相比的变化部分。例如模型从model_v1升级到model_v2,模型注册模块11将记录增加的属性attribute1(domain:Class1,range:string)和删除的属性attribute2(domain:Class2,range:int)。在上述属性的表达中,“domain”是指属性的拥有者,例如,attribute1的拥有者是类Class1;“range”是指属性的取值范围,例如attribute1的取值范围是字符串(string),attribute2的取值范围是整数(int)。当然,可以理解,模型注册还有多种可能的方式,例如记录每个新模型的全部信息,而不只是记录变化部分。无论是什么方式,只要使ORM***20能够区分模型的哪个部分与原始模型有关,哪个部分与扩展部分有关即可。
下面介绍图2中的分派器/组装器24。在保存/加载对象时,分派器/组装器24起到分派器的作用,识别输入的对象符合的模型版本,然后根据该模型版本向模型注册模块11请求相应的模型注册信息,接着根据获得的模型注册信息从输入的对象中分别提取与原始模型有关的数据和与扩展部分有关的数据。在一个例子中,分派器/组装器24通过识别被请求存取的对象的API版本来识别该对象的模型版本。
此后,分派器/组装器24将与原始模型有关的数据“克隆”到(或者说复制到)一个新的对象中并提供给关系数据存储子***28,由对象关系映射模块12按照与现有技术相同的方式保存到关系数据库13中。另一方面,分派器/组装器24将与扩展部分有关的数据传送到元组存储子***27。在该元组存储子***27中,对象-多元组翻译器25将对象的扩展部分翻译成多元组格式,然后保存到多元组存储库26中。从ORM***20取出数据的过程与上述保存过程相反,分派器/组装器24起到组装器的作用,具体过程将在下面详细讨论。
分派器/组装器24可以被实施为包括多个装置,例如识别装置,用于识别要存取的对象符合的模型版本,根据该模型版本向模型注册模块11请求相应的模型信息,以及根据从模型注册模块11获得的模型信息在符合扩展模型的对象中区分与原始模型有关的数据以及与扩展部分有关的数据;分派装置,用于在保存数据时,将与原始模型有关的数据和与扩展部分有关的数据分别分派给关系数据存储子***28和元组存储子***27进行保存;组装装置,用于在取出数据时,将分别从关系数据存储子***28和元组存储子***27取回的与原始模型有关的数据和与扩展部分有关的数据组装成符合所需模型版本的对象。本领域的技术人员可以理解,这些装置可以用硬件、软件或者软硬件结合的方式来实现,但在图中没有具体示出。
下面参考图2和图3举例说明向包含“Time”、“Name”、“Flight”三个属性的TicketOrder类的对象添加新的属性“FuelCompTax”的过程。图3示出了ORM***20在保存对象时的工作流程。
假设原始的对象模型包含“Time”、“Name”、“Flight”三个属性,且已被注册在模型注册模块11中,同时代码生成器17生成了与原始模型相对应的原始API,应用程序18产生符合原始API版本的对象并将它提供给分派器/组装器24。另外,用户设计出增加了“FuelCompTax”属性的扩展模型并把它注册到模型注册模块1l。同样,代码生成器17生成与扩展模型相对应的升级的API并将它提供给应用程序18′。注意,应用程序18和应用程序18′之间的唯一差别就是采用了不同的API,在图中示为分开的两个模块是为了清楚起见,实际上应用程序18′只是升级后的应用程序18,而不一定是两个物理上分开的模块。应用程序18′采用升级的API,产生符合升级后的API的对象并把它提供给分派器/组装器24。
参考图3,在步骤S31,需要保存的对象被输入到ORM***20。在步骤S32,分派器/组装器24判断输入的对象符合的模型版本。如果符合原始模型,则在步骤S35,分派器/组装器24将输入的对象直接传送到关系数据存储子***28,由对象关系映射模块12按照原有的关系数据库模式将对象保存到关系数据库13中。如果在步骤S32判断要保存的对象符合某个扩展的模型,则在步骤S33,分派器/组装器24向模型注册模块11请求该对象的模型注册信息,并根据从模型注册模块11返回的模型注册信息从输入的对象中提取与原始模型有关的数据并“克隆”或者说复制到一个符合原始模型的新对象中,并将该新对象提供给关系数据存储子***28,由对象关系映射模块12按照原有的关系数据库模式将这个新的对象保存到关系数据库13中。在步骤S34,分派器/组装器24根据从模型注册模块11返回的模型注册信息从输入的对象中提取与扩展部分有关的数据并提供给元组存储子***27,由对象-多元组翻译器25翻译成多元组格式的数据并保存到多元组存储库26中。
参考前面的预订机票的例子举例说明保存对象的过程。当增加了“FuelCompTax”属性的对象送入ORM***20时,分派器/组装器24识别并提取出“Time”、“Name”、“Flight”三个属性的信息并复制到一个符合原始模型的新对象中。由于这个新的对象与原始模型一致,所以按照原有的关系数据库模式保存到关系数据库13中是没有任何问题的,关系数据库13不需要重新设计和升级。另一方面,分派器/组装器24从输入对象中提取出与扩展的“FuelCompTax”属性有关的数据,对象-多元组翻译器25将它翻译成多元组,例如<A,FuelCompTax,Value>这样的三元组,并将它保存在多元组存储库26中。
在另一个例子中,模型修改是删除属性/关系,这时在图3的步骤S33中,在复制出的新对象中,被删除的属性对应的属性值为“空”,仍可以按原有的关系数据库模式将该新对象保存到关系数据库13中。
从以上过程可以看出,本发明是将扩展的对象分成两部分,一部分仍符合原始模型则按原关系数据库模式保存到关系数据库中,另一部分则被翻译成多元组的形式后保存到元组存储子***中。这样,模型扩展就可以在运行时动态地进行,不必修改关系数据库中的模式,从而消除了使***停止运行、升级关系数据库模式和迁移数据的必要,减小了对***运行的影响,降低了成本,节省了时间。
与保存/加载对象相对的是对象数据的取出,图4示出了扩展的ORM***20在取出对象时的工作流程。首先,在步骤S41,应用程序18(18′)向ORM***20请求需要取出的对象。在步骤S42,分派器/组装器24判断所请求的对象符合哪个模型版本。如果所请求的对象符合原始模型,则在步骤S46,分派器/组装器24直接向关系数据存储子***28请求该对象,对象关系映射模块12接到请求后向关系数据库13发出查询,如果在关系数据库13中找到该对象的话,则取出所请求的对象并经由分派器/组装器24返回给发出请求的应用程序18。另一方面,如果在步骤S42判断所请求的对象符合某个扩展的模型版本,则在步骤S43,分派器/组装器24根据从模型注册模块11获得的模型注册信息,向关系数据存储子***28请求与原始模型有关的数据,如果在关系数据库13中找到该数据的话,则由对象关系映射模块12取出该数据并返回给分派器/组装器24。在步骤S44,分派器/组装器24根据从模型注册模块11获得的模型注册信息,向元组存储子***27请求与扩展部分有关的数据,如果在多元组存储库26中找到该数据的话,则由对象-多元组翻译器25取回该数据,翻译成对象形式的数据后返回给分派器/组装器24。然后,在步骤S45,分派器/组装器24将分别从关系数据存储子***28和元组存储子***27返回的数据组装成一个新的对象,该对象符合所请求的扩展模型版本,然后将这个新对象返回给发出请求的应用程序18′。
还是参考前面的例子举例说明取回对象的过程。当请求取出包含“FuelCompTax”属性的对象时,分派器/组装器24识别出该对象符合一个扩展模型,并从模型注册模块11获得相应的模型注册信息。然后,分派器/组装器24根据该模型注册信息从关系数据存储子***28取回符合原始模型的数据部分,其包含“Time”、“Name”、“Flight”三个属性,再从元组存储子***27取回包含扩展属性“FuelCompTax”的多元组,例如<A,FuelCompTax,Value>这样的三元组,并将它翻译成对象格式。最后,分派器/组装器24将符合原始模型的数据部分和包含扩展属性的数据部分组装成包含全部四个属性的对象,其格式符合在模型注册模块11中注册的模型信息。
图中的框图和流程图描述了根据本发明的***和方法的某些可能实施方式的体系结构、功能和操作。为此,流程图或框图中的每个方框可以代表一个模块、装置、代码段或代码的一部分,其包括用于实现指定逻辑功能的一个或多个可执行指令。此外可以理解,在图3和图4中示出的步骤只是示意性的,可以添加、删除、修改图中的步骤或改变它们的顺序,图中顺序执行的步骤也可以同时执行,甚至以相反顺序执行,这是本领域的技术人员能够理解的。
本发明可以采用完全硬件的实施方式、完全软件的实施方式或包含硬件和软件成分的实施方式。
此外,本发明可以采用计算机程序产品的形式,该计算机程序产品可以从提供程序代码供计算机或任何指令执行***使用或与之结合使用的计算机可用介质或计算机可读介质来访问。对于本申请,计算机可用介质或计算机可读介质可以是可包含、存储、传送、传播或输送程序供计算机或任何指令执行***、装置或设备使用或与之结合使用的任何装备。
介质可以是电的、磁的、光的、电磁的、红外或半导体***(或设备或器件)或传播媒体。计算机可读介质的例子包括半导体或固态存储器、磁带、可拆卸的计算机盘、随机访问存储器(RAM)、只读存储器(ROM)、硬磁盘和光盘。光盘的当前的例子包括压缩盘-只读存储器(CD-ROM)、压缩盘-读/写(CD-R/W)和DVD。
适于存储和/或执行程序代码的数据处理***将包括至少一个通过***总线直接或间接耦合到存储器单元的处理器。存储器单元可包括在程序代码执行期间所使用的局部存储器、大容量存储装置和缓存,缓存提供至少某些程序代码的临时存储,以便减小代码在执行期间必须从大容量存储装置取回的次数。
输入/输出或者说I/O设备(包括但不限于键盘、显示器、指针设备等等)可直接或通过居中的I/O控制器被耦合到***。
网络适配器也可以被耦合到***,使得数据处理***能够通过居中的专用网或公共网被耦合到其它数据处理***或远程存储装置。调制解调器、有线调制解调器和以太网卡仅仅是几种当前可用类型的网络适配器。
虽然上面参照附图解释了本发明的具体实施方式,但这些描述只是为了举例说明,而不是限制性的。本领域的技术人员在阅读以上内容后,可以作出上述实施方式的变型和修改,这些都落入本发明的真实精神和范围内。