用于任意数据模型的映射体系结构
技术领域
本发明涉及在数据源之间的数据映射。
发明的背景
现在以有线和无线的状态盛行的自由信息流要求源和接收站可兼容到能存储和翻译用到的数据的程度。这个世界充满了许多信息源,其中,在许多情况下在不同的源中的数据是的表示也不同。今天,公司和个人面对的一个非常严重的问题是,为了另一种用途,需要以一种格式存在的数据的另一种格式。然而,这样的处理正受很大程度上不同并一直在变化的数据集的联系所牵制。一个这样的例子可以在数据仓库中找到,其中接收来自用于存储来来自其它源的快速访问的许多不同源的数据。将一种数据表达方式转换为另一种,不仅仅费时和资源密集,还充满了转换难题,而在一些情况下,因为复杂度而完全做不到。
发明概要
为了提供对该发明的一些方面的基本理解,接下来给简化的发明概要。这个概要并不是发明详尽的综述。它不是用来规定发明的关键/关键性要素或是描绘发明的范围。它的唯一目是以简化的形式给出一些本发明的原理作为后面更加详细说明的前奏。
在这里公开和要求的本发明,在其中一个方面,包括一个设计用来支持两个(或更多)数据源而不修改数据源它们本身的元数据或结构地互相映射的情况映射格式。例如,提供在Object空间和关系数据库之间、Object空间和XML数据模型之间、XML数据模型和Relational数据模型之间的映射或是可以提供在任何其它可能的数据模型与XML、关系数据模型、或其它数据模型之间的映射。该映射格式支持更新,也支持两个正在映射的数据源都是特定的,它们的模式是预定义的并且不能改变(例如,只读)的情况。例如,过去用来映射XML数据到关系数据库的方法,为了加入批注,需要改变XML模式定义(XSD)文件。本发明中的映射格式工作时,好像该XSD文件是外部实体固有的而且是不能改变的。它也允许在没有编辑过的情况下对不同数据源的多个映射再使用同样的XSD文件。
每一个数据模型呈现三个用来映射的概念(或表达式):结构、字段和关系中的至少一个。所有这些概念都可以在数据模型之间映射。有可能,一个数据模型也许仅有一个或两个被映射到另一个具有三个表达式数据模型中的表达式。映射结构是映射模式的基础组件,并起到用于相关映射字段的容器的作用。字段是容纳已分类的数据的数据模型概念。关系是在相同的数据模型中的两个结构之间的链接和关联,说明在相同域中的结构与彼此是如何相互联系的。关系是通过两个结构的共用字段和/或一种结构包含另一种结构的容器/索引建立的。这些仅仅是关系的例子,因为可以建立其它的关系(例如,同属、功能......)。本发明允许建立任意的关系。一个数据模型的成员可以作为不同的映射概念来呈现,这取决于该映射前后关系。
在语义上,映射相当于一个具有附加元数据的视图(而视图实际上是一个询问),该附加元数据包括可逆性提示和关于这两个被映射域的附加信息。当一个数据源被映射到另一个的时候,真正正在请求的是想要该目标模式成为该源模式的一个视图。映射是以在另一个数据域的上面的数据域的形式表示的视图,并自身定义了该视图转换。映射可以创建数据结构变换的复杂视图,该转换创建或折叠层次,将属性从一个元素移动到另一个,并且引进新的关系。
映射将两个以上的映射模型之间的相同可映射的概念联系和连接起来。映射也是定向的。从而,将一个域作为一个源来分类,而将其它的作为一个目标来分类。映射的方向对于映射的执行和语意非常重要,因为,作为源被映射的模型和作为目标被映射的模型相比具有不同的特性。目标拥有该源模型的视图,其中,用目标域的询问语言物化了该映射。源是数据的持久的位置,而映射将以目标域的询问语言写的询问转换成源域的询问语言。源和目标之间的一个区别是来自源或目标模型的结构或字段,有一些关于能够适用于结构和字段的映射的数目的限定。在目标域中,一个结构和一个字段只能被映射一次,而在源域中,一个结构和一个字段可以被映射若干次。例如,一个用户表可以被映射到目标域中的一个购买用户元素和一个参考用户元素。然而,一个局部元素或局部类只能被映射仅仅一次。源于映射的方向属性的另一个区别是,映射允许用户通过目标域的询问语言操作被映射的模型(例如,使用用于映射Relational模型到XML模型的XQuery,以及用于映射Relational模型到Object模型的OPath)。
另一个映射体系结构的重要属性是可更新的属性。过去,开发者不得不写代码来传播和同步域之间的变化。然而,根据本发明,现在由映射引擎完成这些任务。也就是说,当用户在目标域中创建、删除或修改结构的时候,目标API和映射引擎自动地将这些变化同步(持续)到源域。
在它的另一方面,该映射体系结构是可堆栈的,从一个源到一个目标可以发生若干级的映射。
为了完成上述以及相关的目的,在这里结合下面的说明和附图说明该发明的某些直观的方面。这些方面是指示性的,尽管仅仅关于本发明的原理不同使用方式中的一些,本发明是用来包括所有这样的方面以及它们的相等物。当结合附图的时候,由接下来的关于该发明的详细的说明,该发明的优点和新颖的特征可以变得明显。
附图的简要说明
图1示出了一个本发明的映射系统的框图。
图2示出了一个根据本发明的处理的流程图。
图3示出了一个呈现来简化从源到目标的映射的概念上的元数据实体的图。
图4示出了一个用于映射一个源模式到一个目标模式的映射文件的普通例子。
图5示出了一个在一个源域和一个目标域之间的示范性的映射。
图6A示出了一个映射部件独立地安排在网上的一个源数据源和目标数据源的网络图。
图6B示出了一个该映射部件可以位于源位置或是目标位置,或是这两个位置的网络图。
图7示出了一个可用来操作公开的体系结构的计算机的框图。
图8示出了一个根据本发明的示范性的计算环境的示意框图。
图9示出了一个根据本发明执行映射的串级链的框图。
图10示出了一个本发明的映射体系结构的执行的中心-和-辐。
图11示出了根据本发明的一个方面的可堆栈的结构。
发明的详细说明
现在参考附图来说明本发明,其中相同的参考数字始终用来指相同的组件。在接下来的说明中,出于解释的目的,陈述了许多具体的细节来提供对本发明的全面理解。但是显然,没有这些具体的细节也可以实际操作本发明。在其它的例子里,为了便于描述本发明,以框图的方式示出了公知的结构和装置。
在这个申请中使用的时候,术语“组件”和“系统”用来指一个计算机相关的实体硬件、硬件和软件的结合、软件或在执行的软件。例如,一个组件可以是,但不是限制为,在处理器上运行的处理、处理器、对象、可执行的东西、执行的线程、程序、和/或计算机。通过用图说明,在服务器上运行的应用程序和服务器可以是一个组件。一个或以上的组件可以驻留在一个处理和/或执行的线程中,而组件可以定位在一台计算机上和/或分布在两台或以上的计算机上。
在这里使用时,术语“推断”一般指从一组经由事件和/或数据捕获的观察结果中推导或推理系统、环境、用户的状态的处理。例如,推断可以用来识别一个特定的前后关系或动作,或可以生成有关状态的概率分布。这个推断可以是用概率统计的——也就是,基于对数据和事件的考虑,计算有关对感兴趣的状态的概率分布。推断也可以指用来从一组事件和/或数据组成更高层次事件的技术。这样的推断导致,不论事件是否与紧密的时间接近相关,以及事件和数据是否来自一个或数个事件和数据源,构建来自一组观察到的事件和/或存储的事件数据的新的事件或动作,。
定义
下面的术语是在整个说明书中使用的,这里提供它们的定义来帮助理解从属发明的不同方面。
模型——一个复杂的离散结构,表示人工设计的典型产物,例如XML模式、关系模式以及对象模式。
域——一个或以上的基于特定数据模型来管理数据的应用程序。
对象域——对象图形数据模型的对象空间的实现。
XML域——基于XML数据模型的对象的堆询问语言。
关系域——基于该关系数据模型的DBMS(Database Management System)。
IDomainSchema——将模型作为可映射的结构的可串行化的、标记的有向的图形来呈现的模型管理对象模型。将该模型图形中的“边”称为“关系”。例如,XSOM(呈现XML模式的XSD(XML Schema Definition)的对象模型)、RSOM(呈现关系模式的RSD(Relational Schema Definition)的对象模型)以及OSOM(呈现对象模式的OSD(Object Schema Definition)的对象模型)。
映射结构——数据模型模式的基础组件,用作相关映射字段的容器(例如,在关系域中的表、在XML域中复型元素以及在对象域中的类)。
字段——保存已分类的数据的数据模型概念。在概念上,字段保存纯量值,虽然在一些情况中字段可以保存复杂数据(例如,XML数据类型和UDT)。进一步的例子包括关系数据模型的列、在XML域中的属性和简单类型元素、以及在对象域中的特性。
关系——在相同的数据模型中的两个结构之间的链接和关联,其说明在相同域中的结构与彼此之间是如何联系的。通过两个结构的共用字段和/或一种结构中包含另一种结构的容器/索引建立关系(例如,XML保存层次以及通过它的字段引用另一个对象的对象)。
现在参考图1,示出了一个本发明的映射系统100的框图。这个结构提供了数据模型在它们的域中使用它们各自的询问语言或API(ApplicationProgrammable Interfaces)执行CRUD(Create、Read、Update以及Delete)操作的能力,其中将该询问语言或API转换成操作。例如XML和对象数据可以在它们的域中用它们的询问语言(例如,分别地,XQuery和OPath)执行CRUD操作,CRUD操作转换成了在关系域中使用其询问语言(如SQL)的操作。
系统100包括一个源数据模型102和一个目标数据模型104,由映射组件106发生从源数据模型102到目标数据模型104的映射。每一个数据模型(102和104)与呈现一个或更多可相关的实体的元数据相互关联。。也就是,源数据模型102呈现源元数据108,而目标数据模型104呈现目标元数据110,其中元数据(108和110)各自包括经由映射组件106可直接相关的概念实体。该元数据实体包括结构、字段以及关系的概念(或表达式)。
映射在来自至少两个被映射模型的相同、不同、相同和不同的结合的可映射的概念(在下文中更详细地说明了)之间联系和连接。映射是定向的。因此,将一些域分类为源102,而将另一些域则分类为目标104。公开的映射体系结构的方向性方面提供了对于映射的执行和语义的显著优越性。另外,作为源102被映射的模型可以具有与作为目标104的模型不同的特性。
目标数据模型104拥有源数据模型102的视图。也就是,用目标域的询问语言物化该映射。源数据模型102是数据的持久的位置,而映射组件将以目标域的询问语言写的询问转换成源域的询问语言。
源102和目标104之间的一个区别是来自源或目标模型(102或104)的结构或字段,具有一些适用于结构和字段的映射的数目的限定。在目标域中,一个结构和一个字段只能被映射一次,而在源域中,一个结构和一个字段可以被映射若干次。例如,一个Customers表可以被映射到Target域中的一个BuyingCustomer元素和一个ReferringCustomer元素。然而,一个局部元素或局部类只能被映射仅仅一次。这里就例子、语法和语义来提供更详细的说明。
源于映射的方向属性的源和目标之间的另一个区别是,映射允许用户通过目标域的询问语言操作被映射的模型(例如,与XML相关的XQuery,与对象映射相关的OPath)。
现在参考图2,示出了一个根据本发明的处理的流程图。虽然,为了简化解释,这里示出了一个以上的方法,例如,以流程图的形式,示出和说明作为一系列的动作,可以很容易地理解,本发明不受动作的顺序的限制,因为根据本发明,一些动作可以以不同的顺序与/或来自己示出和说明了的其它的动作同时地发生。例如,本领域的技术人员可以理解,换句话说,可以将一个方法表示为一系列的相关联的状态或事件,像在状态图中那样。此外,根据本发明,不是需要所有说明了的动作来执行一个方法。
在200,识别用于数据映射的数据模型。在202,一旦识别了数据模型后,就识别用于每一个模型的相应的元数据。在204,开始从该源模型到目标模型的数据映射。在206,系统确定是否发生了映射差错。如果YES,流程到208来报告这个差错。然后流程回到204的输入来继续映射处理。另一方面,如果没有发生映射差错,流程从206到210来继续映射处理直到结束。然后处理到达结束块。
现在来参考图3,说明了一个呈现来简化从源到目标的映射的概念上的元数据实体的图。映射组件包括一个映射文件300,用于对齐源元数据108和目标元数据110之间的映射功能。在这个特定的实施例中,源元数据108和目标元数据110各自包括三个可以用来建立映射关系的实体:结构、字段和关系。从而源元数据108包括一个STRUCTURES实体302、FIELDS实体304以及RELATIONSHIPS实体306。同样地,目标元数据110包括相应的STRUCTURET实体308、FIELDT实体310以及RELATIONSHIPT实体312。
结构是数据模型模式的基础组件,作为用于相关映射字段的容器。例子包括在关系域中的表、在XML域中复型元素以及在对象域中的类。字段是保存已分类的数据的数据模型概念。在概念上,字段保存纯量值,虽然在一些情况中字段可以保存复型数据(例如,XML数据类型和UDT)。关于映射字段的例子包括关系数据模型的列、在XML域中的属性和简单类型元素、以及在对象域中的特性。关系是在相同的数据模型中的两个结构之间的链接和关联,说明在相同域中的结构与彼此是如何联系的。关系是通过两个结构的共用字段和/或一种结构包含另一种结构的容器/索引建立的,例如,XML保存层次以及通过自身的字段引用另一个对象的对象。
一个数据模型的成员可以作为不同的映射概念来呈现,这取决于该映射前后关系。例如,一个XML元素可以作为字段和结构来呈现(例如,简单型元素和复型元素)。由映射和ID域模式确定把该成员作为一个具体概念给出是否有效。另一个例子中,数据模型可以作为包括一个关系域的不同映射概念来呈现,其中,表述式也可以是一个概念。例如,一个顾客表。
映射语义
在语义上,映射相当于一个视图/询问,其具有包括可逆性提示和关于这两个被映射域的附加信息的附加元数据。将一个数据源映射到另一个时,真正正被请求的是想要该目标模式成为该源模式的一个视图。映射定义了该视图变换本身。例如,当将关系数据库映射到XML的时候,正在定义视图,在这里由XSD最终定义外观(或模式),而映射文件定义怎样生成(通过处理和执行)这个在用RSD文件表示的关系数据库之上的视图。
映射是逐个地以在另一个数据域的上面的数据域的形式表示的视图。明白映射是这样一个视图(而视图实际上是询问)对于理解映射的语义非常重要。
我们可以把映射视图和SQL视图做比较。SQL Server允许在关系数据库的上面定义关系视图。这个视图是由SQL询问来定义的,SQL询问主要结合了三个东西:结果(语句的SELECT条目)的模式、源(一般说来,语句的FROM条目)的子模式的相关部分以及允许从源模式(WHERE条目)生成结果模式的变换。
公开的映射格式具有相同的三个部分,但是是明显分离的(像在XSD、Mapping、RSD中那样)。
映射是一个复杂的跨域的视图。映射允许创建跨域视图。视图的一个显著特征(例如,来自SQL视图或XSLT视图的)是源和目标模式可以属于不同数据模型域。映射可以在关系模式上建立分级视图(XML)、或在分级模式上建立图形视图(Object)。
这个公开的映射结构提供了在结合映射的情况下,使用像XQuery或XSLT这样的其它语言来变换目标或源域的能力。例如转换可以按照操作添加到映射。典型的操作是Insert、Update、Delete以及Query。
示例的编码:
<Map Source=”Customers”Target=”Cust”>
<FieldMap SourceField=”cid”TargetField=”CustomerID”/>
<FieldMap SourceField=”street”TargetField=”st”/>
<FieldMap SourceField=”zip”TargetField=”zip”/>
<MapTransform TransforLanguage=”XQquery”
TransformLocation=”myxquery.xqr”Operation=”Query”/>
</map>
TransforLanguage是用来转换正在被映射的数据的语言。TransformLocation是在驱动器或互联网上,提供转换的文件位置。如果没有指定位置,则可以在MapTransform元素的文字中提供该转换。Operation基于使用该映射的应用程序来定义这个转换。
映射可以创建具有在数据上的结构转换的复杂视图。它可以创建或折叠层次、将属性从一个元素移动到另一个、并且引进新的关系。映射的结果(目标模式)可以是一个复杂的模式。这与主要把多表数据库模式转换成一个单独的表的传统的体系结构形成对比。映射可以在输出中产生与关系相关的多个表(元素,等等)。
映射定义了一个视图,这意味着为了使用它,用户可以在视图上运行询问和更新。映射不是一个操作,如果没有在它上面的的询问和更新操作,不能用它来生成某些数据。然而,询问可以是不重要的(例如,结构化查询语言:view(“filename”))并检索所有的由映射视图描述的数据(物化该视图)。映射支持(有一些例外)对它的视图(可更新的视图)的询问和更新。
技术上来说,映射类似于询问。经由一个询问以同样的方式定义SQL视图,映射也隐含有生成这个视图的询问。映射定义一个可重复使用可更新的静态视图,用户可以用这视图来在该视图上形成若干特定的询问/更新。
例如,用户可以用相关的订货单和订货单详情,使用该公开的映射格式来定义一个所有拥有七天内的订货单的顾客(称为“Active Customers”)的视图(模式)。然后,用户可以使用这个视图来运行在它上面的询问。例如,在一个域中,可以用负平衡来形成检索所有“Active Customers”的XQuery。在执行步骤,映射处理器形成映射信息,当映射信息与XQuery结合时,SQLGen引擎会用其形成对应于映射的相关部分的询问,类似于SQLServer在关系视图上对SQLQuery所做的。
检索和更新操作在本质上是不同的。以一种方式支持一个单独的检索操作,而以另一种方式支持三种操作(插入、更新和删除)。例如,定义一个映射,将作为源的SQLServer上的数据映射到目标XML模式,生成关系数据的XML视图。XQuery不能在SQLServer的表上运行。另外,同样的映射不能用来在XML数据源上提供关系视图。该公开的映射格式不是对称的,不能容易地反向。可以从作为XML的SQLServer上检索数据,使用XML询问语言来询问它。因为映射支持通过其的视图的更新,也可以同相同的映射来执行更新。
映射提供必要的双向信息在两个被映射的模型之间施行双向(Read andWrite)转换。执行跨数据模型域的询问、更新、插入、和删除操作需要的信息是:存在(当同步这些域的时候,在一个域中的一个结构的存在是基于在其它域中的一个结构存在的);复制(在源和目标模型中被映射的域之间复制数据,其中,复制操作可以包括在从一个域到另一个域的值上的有限转换,例如,空值和数据类型变换);以及联系映射(映射关系,存在于目标域中两个映射结构和源域中两个单独映射结构的关系之间)。关系之间的映射允许在两个数据模型中的并行导航,例如,在一个域中从一个结构到另一个基于特定关系的结构的移动,能够转换为在其它的域中的两个被映射的结构之间的移动。
关系映射是一个比存在或复制的语意更不直观的概念。关系映射需要能够同时在两个被映射的域中“走图”。如果来自目标模型(例如,Object、XML)的两个被映射的结构之间有一个关系,或将一个目标结构映射到一个以上的源结构(例如,在一个表中),就必须将目标域中的隐式或显式的关系映射为源(例如,关系)域中的匹配的关系。注意,必须将目标域中的每一个关系映射为源域中的关系而不是与之相反,这源于目前作为源域之上的一个视图的目标域。因此需要映射创建这个视图的最小限度的信息。源域可以包括更多不与映射相关的结构(表)和关系。
域中的结构之间的关系可以是引用关系(一个类型具有对另一个类型的引用,而对一个类型的删除/更新不会重叠到另一个类型上,只是删去这个引用)或所有权(Composit)(其中结构拥有另一个结构和在一个结构实例上的操作的关系重叠到一个相关结构实例上)。例如,删除一个特定的顾客的操作会删除了它的订货单,但是删除订货单详情不会删除该产品。
任何具体映射都适用于读和写操作。从而认为映射是可以更新的(双向的)。为了指定不同的行为(例如,只读或将一个目标结构写入到多个表脚本中),用户可以利用每一个域的可扩展性机制。例如,关系域呈现一个顾客表格,它具有询问、更新、插入和删除命令,当基于映射调用这个命令的时候,用户可以指定任何要执行的SQL语句。另一个例子是关系域中列和表上的只读标志。试图更新这样的列和表会导致错误,然而,是在域中而不是在映射中规定这个信息。
现在来参考附图4,一个映射文件的例子,其使用映射文件400将一个源关系模式映射到一个目标XML模式。根据本发明的一些方面,不论怎样都不需要为了执行映射而被调整源模式402和目标模式404。因此,由于没有对任一方的编辑,源关系模式402和目标XML模式404可以是只读的。本发明的这个特性是显著的,因为在应用程序中,许多客户数据模式会不允许编辑操作来执行映射。
该公开的映射格式可以视为由三个或以上的组件组成:源描述组件406,用于连同源数据源402中遗漏的信息一起,来定义源数据源402的模式;目标描述组件408,用于连同目标数据源404中遗漏的信息一起,来定义目标数据源404的模式,以及一个中央映射组件410。源描述组件406扩展关系源模式402,目标描述组件408扩展XML目标模式404,而中央映射组件410则执行实际的映射。
然后该任务将定义这两个模式(402和404)之间的映射,以致能够询问关系数据库来产生由目标模式404的XSD定义的格式的XML数据,而在其它方面,能够接收XML数据作为源,并将它载入关系表,根据映射将XML数据分解成关系数据。
按照惯例,一个在定义映射时可能存在的问题是数据源模式不完全。例如,关系模式也许会遗漏一些事实上确实存在于数据库中的关系。不幸的是,数据库设计者的共有惯例是不像主码(PK)-外码(FK)约束那样正式地定义关系。虽然外码本身出现在子表中,但是其不像在模式中那样标记。但是,在公开的映射体系结构中,主/外码关系是更优越的,所以需要定义它。另一种常见的情况是该表没有标记主码作为主码。
有时,可能会想要将自定义的关系加入到模式中。例如,显示所有具有以“J”开始的VIN号码汽车是以关系“制造于”与“国家”表中的“日本”条目相联系的。由于在最坏的情况下,不允许编辑关系模式文件的脚本,这时需要在映射文件400中定义概念,否则其会在模式文件中遗漏。
下面的源和目标描述组件(406和408)对应于“DataSource”元素。
映射语义——关系模型(域)
关系域中的可映射的结构是自定义的表(表示为CustomTable)。自定义的表可以表示以下物理关系结构中的一种:物理表;视图:UDF或存储的程序;SQL语句(询问的结果集);以及已过滤的表(其中应用了条件的表)。注意,每一个数据表都是自定义的表。如果用户引用数据库表,映射就在后台透明地创建一个自定义的表。每一个自定义的表具有四个命令:Query、Update、Insert以及Delete。这些命令由用户显式地创建或是由映射引擎自动地创建。如果自定义的表是基于数据库表的,那么它就继承数据库表的关系(这不能反方向地发生)。
每一次映射自定义的表时,在关系域中创建一组实例(可以归类为记录集合、行集合,等等)。每一次映射自定义的表的时候,映射创建一个新的实例组,除非用户显式地指定他或她想映射在一组不同的映射中创建的实例。
关系——关系域
可以在任意两个自定义的表之间定义关系。一个基于常规表的自定义的表继承所有来自该基表的关系。这意味着由于相似的关系已经存在于基库和其它库之间,用户不需要创建自定义表和其它任何表(或另一个CustomTable)之间的关系。然而,在基表之间已经存在关系的情况下,在自定义的表之间创建相似的关系并不是一个错误。创建这样一个关系可能是冗余的,而用户可以重用在基表上定义的关系。
一个继承关系的例子是单个表继承的情况,其中可以从基于一个列值的相同的表中创建若干目标结构。现在来参考图5,考虑在源域500和目标域502之间的映射。源域500包括一个Department表504和一个Employee表506的源域500。定义在Department表504和Employees表506之间的关系508。Employees表506具有一个来自Department表504的外码,以便于将来在目标域502中构造类似的关系。Employees表506具有一个命名为EmployeeType的列,它存储了三个值“M”、“HE”和“SE”。从源域500到目标域502的映射如下:Department表504映射为目标域502中的Department表510;“M”512映射为Manager表514(M Manager);“HE”值516映射为HourlyEmployee表518(HE HourlyEmployee);以及“SE”值520映射为SalaryEmployee表522(SE SalaryEmployee)。源域500中的外码关系508,目标域502中的Department表510链接到Manager表514、HourlyEmployee表518以及SalaryEmployee表522。
使用外码来建立和加强源表和目标表中的数据之间的链接的一个列或列的组合。通过将保存主码值的源表中的列加入到目标表中,来创建源表和目标表之间的链接。然后这些列变成目标表中的外码。
在图5的例子中,由于三个自定义表(512、516和520)继承从Department表504到Employees表506的关系508,不需要创建这些自定义的表(514、518和522)之间的显式关系,虽然这是可能的而且这样做不是错误。自定义的表(例如,自定义的表514)共享基表(Employees506)上的关系508,这样用户就可以定义自定义的表514和另一个表之间的更多关系。
接下来的规则解释对于一个基于表的自定义的表是怎样共享关系。如果于一个物理表和一个自定义的表之间存在一个映射,并且在这两个表之间引用一个关系,那么认为在该自定义的表和该表之间的关系有效,因为它是该物理表和该自定义的表所基于的物理表之间的关系。注意,相反的情况不行,例如,如果两个自定义的表具有一个关系,这些自定义的表所基于的表不共享这些关系。如果映射是两个自定义的表之间的,那么引用的关系可以是自定义的表1和自定义的表2之间的,或自定义的表1和自定义的表2的基表之间的,或自定义的表1的基表和自定义的表2之间的,或是这两个基表之间的。
使用RSD(Relational Schema Definition)的关系元素来定义关系域中的关系。在物理上,关系可以是基于在数据库中定义的物理的外码约束,或是用于映射需要的关系的新定义。每一个关系必须具有一个唯一的名字,这样就可以明确地引用它。考虑下面的例子。
<re:Relationship name=”Cust_Ord”From=”Customers”To=”Orders”CascadeDelete=”Server”>
<re:ColumnJoin Column=”id”RelatedColumn=”customerid”/>
<re:Relationship>
因为用名字明确地引用关系,关系域可以具有若干被定义在相同的一对表之间的关系,其中区别是每一个关系具有一个不同的列连接组。关系元素提供所有需要用于映射引擎在关系域中执行接下来的操作的信息,这些操作是:在用于询问操作的一个自定义的表之间联结;是否穿过相关的自定义的表重叠更新操作;更新操作的顺序(先从哪一个表开始删除,等等);以及确认更新操作与关系的基数的匹配。
映射语义——对象域
对象域呈现类型(类)作为映射的可映射的结构。基于路径表达式,可以整体地或局部地识别类型。例如,Target=”Address”的是指整体类“Address”,而Target=”Customer/Address”的是指是Customer类的一个字段的Address类。(用Map元素)可以直接地把每一个类型(整体的或局部的)映射为关系域中的一个而且仅仅一个自定义的表。类型可以具有另一个类型的成员,这意思是它正引用基于类型映射而创建的类型的实例。基于对象关系信息来创建这个引用。
对象域的类型映射的语义是指,将为已有的源域中被映射组的实例,创建对象域中的一个类型的一个实例的最大值,并可以为那个基于对象域中的关系信息的类型创建不定数目的实例索引。为了说明这点来考虑顾客和地址类,其中,顾客具有一个关于地址类的类型的叫“我的地址”的成员。将顾客类映射为映射表,而把地址类映射为地址表。当用户通过映射发出一个询问来检索“地址”类时,基于该询问条件创建该类的一个新实例,除非已经存在具有相同标识的地址对象。当用户发出另一个询问来检索“顾客”类,这个范围包括“我的地址”特性,只有当该对象存储中不存在该实例时,会为“我的地址”成员创建新的地址对象。首先,会将这个实例加入到由对象空间前后关系(对象域)管理的“地址对象”对象集合。然后会用对“地址”实例的引用来更新“我的地址”字段。
映射语义——XML模型(域)
XML域呈现作为映射结构的元素以及,呈现作为映射字段的元素和属性。因为下面的原因,忽略XML模式中的类型定义而并不认为它是一种映射结构。XML模式提供有名类型和匿名类型。为了映射匿名类型,用户需要用路径表达式来识别它们。在XML域中为任何出现在文档中的类型创建新的副本。因为和对象域不一样,XML域没有一个XML文件存储器来管理基于它的类型的XML数据,并创建对一个已经创建了类型的实例的引用。为了使的XML高速缓存器成为这样一个存储器,当它们不是清楚地基于XML模式时,映射XML域需要加入;附加的元数据来清楚地定义类型。
类型名和元素名是在两个不同的值空间,这样以便于在映射中有区别一个类型名和一个元素名的方法。
用在XSD模式上的XPath的子集来识别可以被映射的实例。映射语法支持基于对象域中以及XML域中的映射类型。
映射元素和属性
设计映射语法来支持安排在映射设计部分的映射的设计和规则。选择映射模式的格式为XML。XML格式允许映射顾客来使用XML API来创建和保存映射文件,它对人来说是更易读的,而映射引擎可以使用XML模式来执行映射文件的确认。
下面说明一个具有一个或以上的元素和属性的映射Customers-Orders的完整映射的实例。
<m:MappingSchema XMLns:m=″http://www.microsoft.com/mapping/msd″><m:DataSources>
<m:DataSource Name=″Nwind″Default=″Northwind″>
<m:InlineSchema>
<r:Databases XMLns:r=″http://www.microsoft.com/mapping/rsd″>
<r:Database Name=″northwind″>
<r:Schema Name=″dbo″>
<r:Tables>
<r:Table Name=″Customers″>
<r:Columns>
<r:Column Name=″CustomerID″>
<r:DbStringType Name=″nchar″Length=″5″/>
</r:Column>
<r:Column Name=″CompanyName″>
<r:DbStringType Name=″nvarchar″Length=″40″/>
</r:Column>
<r:Column Name=″City″>
<r:DbStringType Name=″nvarchar″Length=″15″/>
</r:Column>
</r:Columns>
<r:Constraints>
<r:PrimaryKey Name=″PK_Customers″>
<r:ColumnRef Name=″CustomerID″/>
</r:PrimaryKey>
</r:Constraints>
</r:Table>
<r:Table Name=″Orders″>
<r:Columns>
<r:Column Name=″OrderID″AutoIncrement=″true″>
<r:DbNumericType Name=″Int″/>
</r:Column>
<r:Column Name=″CustomerID″>
<r:DbStringType Name=″nchar″Length=″5″/>
</r:Column>
<r:Column SqlType=″datetime″Name=″OrderDate″>
<r:DbDateType Name=″datetime″/>
</r:Column>
<r:Column SqlType=″nvarchar″Length=″15″Name=″ShipCity″>
<r:DbStringType Name=″nvarchar″Length=″15″/>
</r:Column>
</r:Columns>
<r:Constraints>
<r:PrimaryKey Name=″PK_Orders″>
<r:ColumnRef Name=″OrderID″/>
</r:PrimaryKey>
</r:Constraints>
</r:Table>
</r:Tables>
<r:Relationships>
<r:Relationship Name=″FK_Cust_Order″From=″Customers″To=″Orders″CascadeDelete=″true″CascadeUpdate=″true″ForeignKey=″true″Cardinality=″OneToMany″>
<ColumnJoin Column=″CustomerID″RelatedColumn=″CustomerID″/>
</r:Relationship>
</r:Relationships>
</r:Schema>
</r:Database>
</r:Databases>
</m:InlineSchema></m:DataSource><m:DataTarget Type=″XML″>
<m:InlineSchema>
<xsd:schema XMLns:xsd=″http://www.w3.org/date/XMLSchema″>
<xsd:element name=″Customer″>
<xsd:complexType>
<xsd:sequence>
<xsd:element name=″Order″>
<xsd:complexType>
<xsd:attribute name=″customerID″type=″xsd:string″/>
<xsd:attribute name=″orderid″type=″xsd:int″/>
<xsd:attribute name=″orderDate″type=″xsd:dateTime″/>
<xsd:attribute name=″shipCity″type=″xsd:string″/>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
<xsd:attribute name=″customerID″type=″xsd:string″/>
<xsd:attribute name=″name″type=″xsd:string″/>
<xsd:attribute name=″city″type=″xsd:string″/>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</m:InlineSchema>
</m:DataTarget></m:DataSources><m:Mappings><m:Map Source=″Customers″Target=″Customer″>
<m:RelationshipMap Source=″FK_Cust_Order″Target=″Order″/>
<m:FieldMap SourceField=″CustomerID″TargetField=″customerID″/>
<m:FieldMap SourceField=″CompanyName″TargetField=″name″/>
<m:FieldMap SourceField=″City″TargetField=″city″/>
</m:Map>
<m:Map Source=″Orders″Target=″Customer/Order″>
<m:FieldMap SourceField=″OrderID″TargetField=″orderID″/>
<m:FieldMap SourceField=″CustomerID″TargetField=″customerID″/>
<m:FieldMap SourceField=″OrderDate″TargetField=″orderDate″/>
<m:FieldMap SourceField=″ShipCity″TargetField=″shipCity″/>
</m:Map></m:Mappings></m:MappingSchema>
假定映射对象模式,其中,Coustomer和Order是类,Coustomer类具有特性MyOrders,而Order类具有特性MyCustomer,映射部分将变为下面这样:<m:Mappings>
<m:Map Source=″Customers″Target=″Customer″>
<m:RelationshipMap Source=″FK_Cust_Order″Target=″MyOrders″/>
<m:FieldMap SourceField=″CustomerID″TargetField=″customerID″/>
<m:FieldMap SourceField=″CompanyName″TargetField=″name″/>
<m:FieldMap SourceField=″City″TargetField=″city″/></m:Map><m:Map Source=″Orders″Target=″Order″>
<m:RelationshipMap Source=″FK_Cust_Order″Target=″MyCustomer″/>
<m:FieldMap SourceField=″OrderID″TargetField=″orderID″/>
<m:FieldMap SourceField=″CustomerID″TargetField=″customerID″/>
<m:FieldMap SourceField=″OrderDate″TargetField=″orderDate″/>
<m:FieldMap SourceField=″ShipCity″TargetField=″shipCity″/></m:Map></m:Mappings>
MappingSchema元素
MappingSchema是映射模式的根元素。它必须包括Mapping和DataSources元素才是有效的。可以基于元数据分段规则来对MappingSchema分段。Mapping格式是一个XML文档。它具有一个单独的根元素:MappingSchema。Mapping文件包含源和目标数据源、它们之间的映射以及可以传送到映射模式的参数的定义的编号的说明。因此,根元素中包括MappingParameters、DataSources和Mapping子元素。没有任何DataSources或Mapping子元素的映射模式仍然是有效映射模式。使用该模式的特定设备确定对这样的映射模式执行询问和更新的行为。用户可以独特地定义这个元素上的所有名字空间。在这个元素上没有属性。这些子元素的顺序很重要,必须像下表中那样排序。
标志 |
基数 |
注释 |
MappingParameters |
0-1 |
示出了整个映射的参数,包含MappingParameters元素,可以为空。 |
DataSources |
0-1 |
包含正被这个映射所映射的所有数据源的说明(DataSource和DataTarget) |
Mappings |
0-1 |
定义所有数据源之间的映射 |
实例:<m:MappingSchema xmlns:m=″http://www.microsoft.com/mapping/msd″><m:MappingParameters>...</m:MappingParameters><m:DataSources>...</m:DataSources><m:Mappings>...</m:Mappings></m:MappingSchema><m:MappingSchema>
<m:MappingParameters>
<m:MappingParameter>
...
</m:MappingParameter>
...
</m:MappingParameters>
<m:DataSources>
<m:DataSource name=″foo″>
...
</m:DataSource>
<m:DataTarget Type=″XML″>
...
</m:DataSource>
</m:DataSources>
<m:Mappings>
<m:Map>
...
</m:Map>
</m:Mappings></m:MappingSchema>
DataSource元素
DataSources元素保存被映射的数据源的模式信息。数据源可以包含若干提供模式的不同段的模式文件。DateSources元素提供一个SQL服务器。
属性:
标志 |
基数 |
注释 |
名字 |
Req |
这个DataSource的名字。外部API可以用这个名字,API用映射来把数据源和像用于关系域的连接这样的外部资源联系起来。 |
默认值 |
Opt |
传送到源域的默认标识符的名字。例如,给定RSD中默认数据库的名字。 |
子元素:
标志 |
基数 |
注释 |
Schema |
0+ |
通过它的@Location属性指向域模式。 |
InlineSchema |
0-1 |
联机地包含源域模式。 |
必须提供Schema元素或InlineSchema元素,但仅提供它们中的一个。至于实例,参见映射文件。该Schema/InlineSchema元素必须指向一个有效的RSD。
DataTarget元素
这个元素保存被映射的目标域的模式信息。扩展元素提供加入信息到域模式中的能力。在不能编辑模式或模式不是为了映射而特别地创建的情况下,这很有用。可以对目标模式进行分段。
属性:
标志 |
基数 |
注释 |
类型 |
Req |
Target域的类型。至少支持XML和对象。 |
子元素
标志 |
基数 |
注释 |
Schema |
0+ |
通过它的@Location属性指向域模式。 |
InlineSchema |
0-1 |
联机包含目标域模式。 |
出现具有来自不同域的目标域模式的字段是一个错误,例如,XML模式和Object模式的混合是一个错误。
至于实例,参见映射文件的实例。
模式元素
在DataSource元素中用Schema元素来定义数据源的模式。可以联机或在分开的文件中定义模式。如果在分开的XSD、RSD等文件中定义模式(在大多数的脚本中是这样的情况),那么应该使用Schema元素。用InlineSchema元素来在模式域(用于XML的XSD等)的名字空间中,联机地定义模式(包括在Schema元素正文体内)。这个元素没有子元素。注意下面的属性。
标志 |
基数 |
注释 |
Location |
Req |
这个属性是一个到定义数据源的模式的文件(用于XML的XSD、用于关系数据库、用于对象的OSD)的URL。 |
实例:
<m:DataSource Name=”NorthWindXML”Direction=”Target”Type=”XML”>
<m:Schema Location=”North Wind.xsd”/>
<m:DataSource>
InlineSchema元素
在DataSource元素中用Schema来定义数据源的模式。用InlineSchema元素来在模式域(用于XML的XSD等)的名字空间中,联机地定义模式(包括在Schema元素正文体内)。这个元素没有子元素。这个元素正文体包含一个模式定义(XSD、RSD或OSD)。
实例:<m:DataSource Name=″NorthWindSQL″Direction=″Source″Type=″SQL Server″>
<m:InlineSchema XMLns:r=″
http://www.microsoft.com/data/rsd″>
<r:Database name=″NW″>
<r:Tables>
<r:Table Name=″Customers″>
<r:Columns>
<r:Column Name=″CompanyName″DataType=″nvarchar″Precision=″40″/>
<r:Column IsNullable=″true″Name=″ContactName″DataType=″nvarchar″Precision=″30″/>
<r:Column Name=″CustomerID″DataType=″nchar″Precision=″5″/>
</r:Columns>
<r:Constraints>
<r:PrimaryKey Name=″PK_Customers″>
<r:ColumnRef Name=″CustomerID″/>
</r:PrimaryKey>
</r:Constraints>
</r:Table>
<r:Table Name=″Orders″>
<r:Columns>
<r:Column IsNullable=″true″Name=″OrderDate″DataType=″datetime″/>
<r:Column IsNullable=″true″Name=″Freight″DataType=″money″/>
<r:Column IsNullable=″true″Name=″CustomerID″DataType=″nchar″Precision=″5″/>
<r:Column Identity=″true″Name=″OrderID″DataType=″int″Increment=″1″Seed=″1″/>
</r:Columns>
<r:Constraints>
<r:PrimaryKey Name=″PK_Orders″>
<r:ColumnRef Name=″OrderID″/>
</r:PrimaryKey>
<r:ForeignKey ForeignTable=″Customers″Name=″FK_Orders_Customers″>
<r:ColumnMatch ForeignName=″CustomerID″Name=″CustomerID″/>
</r:ForeignKey>
</r:Constraints>
</r:Table>
</r:Tables>
</r:Database>
</m:InlineSchema></m:DataSource>
RelationshipMap元素
RelationshipMap是提供有关怎样在源和目标域中映射关系的信息的映射元素的子元素。需要它来识别在目标和源域中从一个结构移动到另一个结构的时候,使用哪一个关系。这个部分提供映射模式中这个元素的语法、语义以及识别的说明。阅读器应该熟悉RelationshipMap概念。当一个关系存在于两个被映射为不同源结构的被映射的结构(“Mapped结构”是指用“Map”元素来映射结构)之间的目标域中的时候需要RelationshipMap元素。这样的关系的实例是在另一个映射(Object)中映射其类型的对象的字段/特性,是另一个被映射的XML元素(XML)的字段的被映射XML元素。
注意,RelationshipMap必须匹配相关映射的源和目标。下面示范这个处理是怎样进行的:一个关系存在于两个目标结构之间(见上边的例子);用两个映射(两个映射元素)来映射这两个目标结构;以及在这些映射中适用的源拥有一个被指定为RelationshipMap中的源的有效关系。
注意,目标域中的其它类型的关系,例如被映射到另一个源的继承或字段,是通过不同的映射属性(在字段映射上,用于继承的BasedOnRelationship和用于字段的SourceRelationship)来处理的。
虽然在一些情况中,映射引擎可以通过识别目标域中的一个关系并找出源域中与之匹配的关系(在被映射的源(表)之间),来推断RelationshipMap,但是需要RelationshipMap是显式的,有两个原因。第一,显式RelationshipMap意味着将关系加入到RSD将不会破坏映射。如果由映射引擎推断RelationshipMap,而将RelationshipMap加入到RSD,这会破坏映射,这是由于加入的关系是两个被映射的表之间的唯一关系,加入关系后,映射引擎不知道挑选哪个关系,所以反馈一个“异常”。第二,它会是更适用的技巧,要求用户理解所有三个简单的映射概念,而不是变“魔术”(通过推断RelationshipMap),因而在像上面的例子中那样发现不明确的关系时处于异常。
标志 |
基数 |
注释 |
Source |
Req |
源域中关系的标识符。这是空间分离的列表。在RSD说明书中指定转义规则。 |
Target |
Req |
目标域中一个映射结构的标识符,该结构与父映射目标结构有一个关系。 |
UseForConcurrency |
Opt |
默认的是“Always”。 |
Source必须是Source(关系)域中的有效关系。这个确认发生在载入所有源模式的段之后。
Target必须是具有关于被映射的目标的关系的目标域中的有效关系而且必须是目标域中相关被映射结构的名字。为没有被映射到另一个映射或没有关于父映射上的目标的关系的结构(类型、元素)指定名字是错误的。在XML域中,Target必须是父映射上的Target的元素的子段。父映射是指包含RelationshipMap在内的映射。这个确认发生在映射高速缓存器中。
在关系列表中,父映射的源是该列表中第一个Relationship的“From”或“To”。这个规则保证第一关系包括父映射的源。这个确认发生在映射高速缓存器中。
在关系列表中,父映射的源是该列表中末尾的Relationship的“From”或“To”。这个规则保证末尾的关系包括父映射的源。这个确认发生在映射高速缓存器中。
如果源是关系的列表,就必须对列表进行排序。在每一个关系“From”或“To”中,必须匹配下一个关系中的“From”或“To”。这个规则保证根据关系而建造的Join/Where条项一直有效,因为具有不互相联结的的表联结条项是不适当的。这个确认发生在映射高速缓存器中。
必须映射两个被映射的目标结构之间的关系。任何具有目标域中定义的关系的两个被映射的目标结构必须具有一个RelationshipMap,其中通过源的属性将该目标域映射到源结构。通过“Ref”属性映射为源结构的关于目标结构的关系不需要上述关系的映射。使用下面的算法发生这个确认。
为每一个被映射的目标结构获取与其它目标结构的所有联系。
{
对于每一个相关目标结构
{
如果(
映射了相关目标结构
以及(仅应用于XML域,对于Object请忽略)
相关结构是子元素,且不是用“Ref”属性来映射当前目标结构映射。
确认存在基于上述确认规则的有效RelationshipMap。
}
}
注意,相关目标的定义取决于目标域的语义。这个确定发生在映射高速缓存器中。
该被映射的关系的CascadeDelete的值必须是匹配的(仅仅应用于对象域)。匹配值的可允许矩阵如下:
源 |
目标 |
有效 |
Server |
没有指定真 |
是 |
Explicit |
没有指定真 |
是 |
Never |
没有指定假 |
是 |
任何其它的组合都是错误。这个确认发生在映射高速缓存器中。
关系的基数值必须是匹配的,匹配值如在下面的表指示。
源 |
目标 |
有效 |
OneToOne |
对象域中的OneToOne |
是 |
OneToMany |
一个至一个以上的任何基数 |
是 |
任何其它的组合都是错误。这个确认发生在映射高速缓存器中。例如,参见标准实例。
映射元素
映射元素的语义的一个例子是源域的被映射的结构的的映射元素意味着目标域中必然存在一个被映射的目标结构。在一个读操作中,为存在于源域中的每一个实例创建在目标域中的该结构的实例。在写操作中,将在目标域中的一个实例上的操作转化为等价于源域中的一个已有的实例上的的操作。考虑,例如,一个使用Map元素的从顾客表到顾客对象或元素之间的映射。这样的映射的语义是为顾客表中的每一行创建一个顾客对象。删除这样的顾客对象会导致准确地删除顾客表中的一行,创建新顾客对象会导致在该顾客表中插入一行到,类似的逻辑也适用于更新。通过在RSD中指定的顾客表,提供了用于上面描述的已有的1∶1映射的可扩展性和覆盖机制。它允许边界效应,例如插入另一个记录到被映射的表外之外的其它一些表中。用户可以对具有一个适用于所有类型的操作(Retrieve、Insert、Update以及Delete)的命令的顾客进行映射,像任何其它的表一样。当基于在目标域中执行的操作调用这样一个命令的时候,在每一个命令中,用户可以指定映射引擎将要执行的SQL/SP。目标域中的每一个实例可以准确地调用一次该命令(注意,所有表都是自动命令设为“真”的自定义的表)。
在多个映射中可以使用相同的源结构。例如将一个表映射为多个对象类型(将顾客表映射为顾客对象和顾客资料对象),或将相同的表映射为多个XML元素(将顾客表映射为顾客顶层元素和在公司元素之下的顾客元素)。这样的映射的语义是,在源域中为每一个映射创建一个作为迭代器来引用的新集(使用询问命令)。用户可以通过拥有Ref属性而不是源来使用相同的集。
属性:
标志 |
基数 |
注释 |
Source |
Opt |
源域(Relational)中的一个结构(顾客表)的选择表达式或名字。 |
Target |
Req |
目标域中的一个结构的选择表达式。 |
Name |
Opt |
该映射的唯一名字。当用户需要引用一个映射的时候使用它。 |
Ref |
Opt |
另一个映射的名字。仅能用于XML-Relational映射。 |
BasedOnMap |
Opt |
另一个映射的名字。 |
BasedOnRelationship |
Opt |
关系域中的一个Relationship的名字。 |
UseForConcurrency |
Opt |
这个映射中所有FieldMaps的并行设置值。 |
子元素:
标志 |
基数 |
注释 |
FieldMap |
0+ |
对变量的字段的的映射。 |
OverflowMap |
0-1 |
用这个元素来将在该目标结构上的溢出映射为Source DataSources中的一个字段。只有XML支持这个元素。 |
RelationshipMap |
0+ |
映射的目标结构到另一个结构的关系,和被映射的源结构之间可适用的关系之间的映射。 |
目标是一个DataTarget中的有效结构。一个指向不存在于目标域中的映射是一个错误。这个确认发生在映射高速缓存器中。如果源存在,它必须是数据源中的有效结构。一个指向不存在于源域中的源是一个错误。这个确认发生在映射高速缓存器中。
目标结构仅能映射一次。这个规则使得映射是更新的,由于仅能映射目标结构一次,可以将目标域中的该结构的任何实例明确地写入源(关系)域中。如果用户想在读出或写入的方向映射目标结构一次以上,她可以使用源(关系)域中的顾客表。这个确认发生在映射高速缓存器中。
跨越映射模式,映射的名字是唯一的。为了允许其它的映射明确地引用这个映射,映射的名字需要是唯一地跨越映射文件。一些特定功能性需要引用例如Ref和BasedOnMap等已存在的映射。这个确认发生在映射高速缓存器中。
Ref的属性必须指向一个有效映射。Ref的属性值必须是映射模式中一个已存在有效映射的名字。这个确认发生在映射高速缓存器中。Ref和Source属性是互斥的。在一个映射中不允许有多个源,因而正在使用来自另一个映射的源的映射Ref属性,不能与源存在于同一映射中。
没有BasedOnMap就不能存在BasedOnRelationship属性。Ref和BasedOnRelationship属性是互斥的。Ref属性指向一个范围内已有的源(迭代器),因而不存在指定一个关系的需要。
Ref不能够用于Object-Relational映射。该Ref属性语义不适用于对象到关系的映射。
至于实例,参见在上文中的完整的映射实例。
字段映射子元素
字段映射元素表示从一个域到另一个复制值的操作。在读出时,映射引擎只简单地将源字段的值复制到目标字段中,而在写入时是相反的。在一些情况下,这些值是来自不同源(表)的,因此Source/Ref/SourceRelationship属性提供如何来得到那个值所需要的信息。字段映射允许对定义空值转换和设置用于写操作的并行选项。
字段映射使得在目标一方可以方向规格化数据。目标域(对象-字段,等)仅可以被映射一次。但是,可以映射源域一次以上。允许这样是为了支持用户想反向规格化目标域中的数据的情况。考虑顺序表具有一个CurrencyID,而Order对象具有一个关于每个数量字段的当前值字段的情况,例如FreightAmount和FreightCurrency、TaxAmount和TaxCurrency。在更新映射引擎时,改变处理器(CP)检验被更新并映射为相同源域字段的目标字段具有相同值。
具有相同源的多个字段映射是指用户正引用相同的集合(也被称为变量或迭代器)。这是最简单最直观的行为,不存在任何用户会想使用关于相同关系的不同集合的情况。注意,因为基于不同的关键字而联结一个表到另一个表意味着创建一个新的结果集合,改变SourceRelationship意味着一个新的集合。为使其清楚和明白,这个行为的语义与每一个源表示一个新集合(结果集合上的迭代器)的映射的语义不同。
属性:
标志 |
基数 |
注释 |
SourceField |
Req |
源域中一个字段(数据库的列)的标识符或映射参数。 |
TargetField |
Req |
目标域中的字段(关于XML的属性或简单类型元素、关于对象的字段)的标识符或映射参数。 |
SourceRelationship |
Opt |
映射中的源和字段映射中的源之间的关系的名字。 |
ReadOnly |
Opt |
指定这个字段不能被写入到源字段的布尔逻 |
| |
辑。对于任何更新操作来说,将忽略目标字段。 |
Ref |
Opt |
另一个映射的名字。仅能用于XML-Relational映射。 |
UseForConcurrency |
Opt |
用于这个字段映射的并行设置。 |
NullHandling |
Opt |
可以得到“DomainNull”、“Absence”、“UseNullValue”的值。 |
NullValue |
Opt |
目标域中的Null图像表示。 |
ForceNullOnInset |
Opt |
允许显式地插入Null到源域字段(列)的布尔逻辑。 |
如果源域或目标域的值是以“$”开始的,那么映射其它字段(源域或目标域)为映射参数。如果源域是一个映射参数,这意味着这是一个只读字段映射,不在更新操作中。源域/目标域的确认:这些属性的值必须成功地分别分解为父映射的源/目标结构上的一个有效字段或分解为一个映射参数。如果这些属性中的一个值是以“$”符号开始的,它必须分解为映射参数部分所表示的映射参数。这个确认发生在映射高速缓存器中。
Source/Ref/SourceRelationship必须在源域中有效。Source必须分解为源域中的一个有效结构(顾客表),Ref必须是已有映射的名字,而SourceRelationship必须是源域中一个有效关系的名字。这个确认发生在映射高速缓存器中。
Ref和(Source/SourceRelationship)是互斥的。因为Ref的语义是来自一个不同映射的源。那个源必须在范围内,所以不存在对SourceRelationship的需要。
因为映射需要知道在映射的源和字段映射的源之间的关系是什么,如果源存在于字段映射中,就必须提供SourceRelationship,
如果源不存在于字段关系中,那么就不能提供SourceRelationship。如果源不存在,这意味着该SourceField属于父映射源结构。因此不存在对联系信息的需要。
仅能映射任何特定的目标域一次。两个域中的字段在概念上都是纯量值,因此从源域复制值到目标域必须明确并且不能有任何语义合并。
源域和目标域都不能是一个映射参数。映射一个映射参数为另外一个是没有意义的。
当源域是映射参数的时候,不能指定UseForConcurrency。这在映射参数的前后关系中不适用。
SourceRelationship的基数值必须与目标域类型兼容。如果SourceRelationship的基数是OneToOne,TargetField类型就必须是纯量,否则就会出现错误。(对于对象映射来说,不支持这种情况)。这个确认对于在编译时检测目标字段类型和联系基数之间的不匹配是有用的,例如,如果在Customer分类上的“oid int”类型特性被映射为Orders表的orderID列,其中这个Orders表与Customer分类具有多对一的关系。
Ref不能用在Object-Relational映射。Ref语义不能被用在对象到关系的映射。至于实例,参见完整的映射实例。
溢出映射子元素
这个单元总是包含在“映射”元素中并被用来映射溢出。溢出被定义为包含没有被显式地映射的变量的任何东西。它被用于具有不被映射的属性和开放内容的XML元素。这个元素不适用于Object映射,因此在关系和对象域之间映射的映射模式中具有这个元素是一个错误。
溢出源域必须包括具有作为根元素的映射目标源的有效XML文档(作为字符串存储的)。当在询问中使用映射时,将根节点上的属性添加到目标结构元素并且将下面的元素作为子元素。
当使用映射写入脚本时,创建一个与目标结构元素同名的XML元素,该元素的属性既不在模式中,也没有被映射,将该属性添加到根元素中。将没有被映射也不在模式中的子元素作为那个包括那个元素的文本内容的元素的子元素加入。
用户可以询问和更新溢出数据,这个行为作为融合被引用。错误的情况是:
询问—溢出字段中具有被映射的属性(那样会创建双重的属性情况)。
询问—溢出字段中具有关于被映射的Target Structure元素的文本内容。
属性:
标志 |
基数 |
注释 |
SourceField |
Req |
源域中字段(数据库列)名字。这个名字与包含相关联。字段的语法是数据源相关的。 |
这个元素没有任何子元素。
映射参数元素
映射参数的语义是在运行期映射一个已知值到源或目标字段的能力。映射参数在MappingParameter部分被宣布,可以通过映射API在运行期访问它。字段映射上的NullHandling设置也适用于映射参数。映射参数可以被用作源域或目标域。映射引擎将基于映射参数名字开头的$前缀来在它们之间区分。($对于所有被映射域:对象、XML和Relational(其中,它可以被转义)中的标识符来说都是非法字符)。映射参数是没有归型的,因此它的XSD类型是字符串。在运行期中,引擎将把该值转换为被映射字段的类型(目标字段或源字段)。
这个元素的文本内容是这个参数的默认值。可以在运行期中通过使用像ObjectSpace、XQueryProcessor、Bulkload和XMLAdapter这样的映射的应用程序来改变这个值。
属性:
标志 |
基数 |
注释 |
Name |
Req |
该参数的名字。它在映射文件内必须是唯一的。这是如何从映射中引用该参数。名字必须用“$”开始。 |
如果源域/目标域/零值是用“$$”开始的,意味着这不是映射参数,实际值是用单个“$”开始的。映射参数仅可以用作源域、目标域或NullValue的值。映射引擎不能基于它们的字段映射来对映射参数值进行赋值。它们适用和使用在下面的映射前后关系中:映射参数被映射到源域,它被用于写入操作中,而在读出时被忽略。映射参数被映射到目标域,它被用于读出操作中,而在写入时被忽略。因此,映射参数不能用作输出参数。
在成批装载中,许多时候,用户想向不包含在XSD模式中的数据库中插入数据。这个数据通常仅在运行期也是已知的,并且不被作为XML文档的一部分。例子是用户标识、机器标识等。
用户也许会想统一跨越映射模式使用的零值。这是通过创建一个具有给定默认值的映射参数,以及在许多字段映射中的零值属性值中使用这个映射参数来做到的。
至于确认,映射参数的名字必须用字符“$”开始。任何其它字符都会引起错误。这个名字不能用“$$”开始。这使得如果用户具有一个用“$”开始有效域字段名,或想表示一个空值为“$”时,能够对“$”符号进行转义,。
跨越映射模式,该名字必须是唯一的,以便在运行期中将该参数的值赋给源或目标字段时避免歧义。注意,该名字的唯一性是跨越该映射模式所有载入的段的。
BaseOnMap——BaseOnRelationship属性
一个设计原则是,要从映射文件中的映射部分而不是从域中提供所有必需的映射信息。因此,在继承和递归的情况下,用户需要显式地提供关于映射循环元素和被继承的分类字段的信息。“BaseOnMap”属性向用户提供语法简化操作来从一个映射到另一个复制字段映射和关系映射。这使得通过保持显性的映射语法以及该语法独立于域,映射引擎能够得到必要的信息在对象继承情况中和XML递归情况中复制字段映射和关系映射,,。BaseOnMap选项对来自名字实际上被作为“BaseOnMap”属性值引用的映射的字段映射和关系映射进行复制。被复制的字段映射关系映射将会和包括SourceRelationship属性的基础的那些一致。
用在映射上的源中的SourceRelationship不同于在BaseOnMap被指定了的Map上的Source的情况中。因此它需要创建和更新所有相关源信息和联系(SourceRelationship、RelationshipMap)。指定BaseOnRelationship属性,用该源的值,将源属性加入到被复制的字段映射中,其中,该源值的值与在基础映射和具有BaseOnRelationship属性值的SourceRelationship中被指定的一样。如果被映射的字段映射已经具有源和SourceRelationship属性,那么对于任何复制的SourceRelationship,这些属性将被新映射中的源和在所基于的映射中的源之间的联系更新。
BaseOnMap和BaseOnRelationship属性都可以解释为允许语法简化操作的宏。后面的说明和规则中将使用这两个关键词:BasedOnMap Value-BasedOnMap属性指定的值;BasedRelationship Value-BasedRelationship属性指定的值。
BasedOnMap值是用于复制FieldMap的映射名。它只是从它指向的指定映射到已宣布BasedOnMap的映射来复制字段映射。从名字叫BasedOnMap Value的映射复制所有的子FieldMaps以及RelationshipMap元素,到BasedOnMap属性被指定的Map元素,连同它们所有的属性。
BasedOnRelationship归因于BasedOnMap属性。对每一个字段映射元素,查找并更新相关的字段映射。从名字叫BasedOnMap Value的Map中查找所有的子字段映射元素。如果源属性存在于字段映射中,就不对值做改动,否则就把源属性添加到带有名叫BasedOnMap Value的映射元素的源属性值的字段映射中。
如果SourceRelationship属性存在于字段映射中,在SourceRelationship属性的开头插入一个空格(“”)。在SourceRelationship的开头插入BasedRelationshipValue,否则添加SourceRelationship属性,以伴随BasedRelationship Value的值。
将所有字段映射元素和修改过的源和SourceRelationship属性以及它们其余未改变的属性放置到未指定BasedOnMap和RelationshipMap属性的映射元素中。
通过保持所有它们原有的属性,从名字叫BasedOnMap Value中查找所有的子RelationshipMap元素。对于每一个RelationshipMap元素:在Source属性值的开头插入一个空格(“”)。在Source属性的开头插入BasedRelationship Value。将所有RelationshipMap元素和它们已修改的源属性以及所有其它未改变的属性复制到未指定BasedOnMap和RelationshipMap属性的映射元素中。
以上的语义意味着是下面适用的规则。BasedOnMap应该涉及一个有效的映射名。BasedOnRelationship应该涉及一个在资源域中有效的关系名。如果指定了BasedOnRelationship,那么应该存在一个有效的BasedOnMap。因为显式地的定义了被复制的FieldMaps,所以要服从于其它所有的映射规则。
例子-在XML情况下BasedOnRelationship的使用
表:
Employee(EID,FirstName,LastName,HireDate,Salary,Manager)
FiredEmployee(EID,FirstName,LastName,HireDate,Salary,Manager)
在XML里的结果样本:
<AllEmployees>
<GoodEmployee EID=”1”FirstName=”Good”LastName=”Emp”
HireDate=”1/1/2003”Salary=”1,000,000$”/>
<BadEmployee EID=”2”FirstName=”Bad”LastName=”Emp”
HireDate=”10/10/2000”Salary=”10$”/>
</AllEmployees>
映射:
<m:Map Name=″GoodEmployeeMap″Source=″Employee″Target=″AllEmployees/GoodEmployee″>
<m:FieldMap SourceField=″EID″TargetField=″EID″/>
<m:FieldMap SourceField=″FirstName″TargetField=″FirstName″/>
<m:FieldMap SourceField=″LastName″TargetField=″LastName″/>
<m:FieldMap SourceField=″HireDate″TargetField=″HireDate″/>
<m:FieldMap SourceField=″Salary″TargetField=″Salary″/></m:Map><m:Map Source=″FiredEmployee″Target=″AllEmployees/LazyEmployee″BasedOnMap=″GoodEmployeeMap″></m:Map>
在Mapping引擎里创建的实际的Map:<m:Map Name=″GoodEmployeeMap″Source=″Employee″Target=″AllEmployees/GoodEmployee″>
<m:FieldMap SourceField=″EID″TargetField=″EID″/>
<m:FieldMap SourceField=″FirstName″TargetField=″FirstName″/>
<m:FieldMap SourceField=″LastName″TargetField=″LastName″/>
<m:FieldMap SourceField=″HireDate″TargetField=″HireDate″/>
<m:FieldMap SourceField=″Salary″TargetField=″Salary″/></m:Map><m:Map Source=″FiredEmployee″Target=″AllEmployees/LazyEmployee″>
<m:FieldMap SourceField=″EID″TargetField=″EID″/>
<m:FieldMap SourceField=″FirstName″TargetField=″FirstName″/>
<m:FieldMap SourceField=″LastName″TargetField=″LastName″/>
<m:FieldMap SourceField=″HireDate″TargetField=″HireDate″/>
<m:FieldMap SourceField=″Salary″TargetField=″Salary″/></m:Map>
跨越表格层次的继承(对象)
表:
Persons(SSID,FirstName,LastName)
Employees(EID,EmployeeSSID,HireDate,Salary,Manager)
Managers(EID,Bonus)<Relationship Name=″PE″From=″Persons″To=″Employees″>
<FieldJoin From=″SSID″To=″EmployeeSSID″/></Relationship><Relationship Name=″EM″From=″Employees″To=″Managers″>
<FieldJoin From=″EID″To=″EID″/></Relationship><Relationship Name=″MyManager_R″From=″Employees″To=″Employees″>
<FieldJoin From=″EID″To=″Manager″/></Relationship><Relationship Name=″MyEmployees_R″From=″Managers″To=″Employees″>
<FieldJoin From=″EID″To=″Manager″/></Relationship>
继承层次:Person Employee Manager
映射:<m:Map Name=″PersonMap″Source=″Persons″Target=″Person″>
<m:FieldMap SourceField=″SSID″TargetField=″SSID″/>
<m:FieldMap SourceField=″FirstName″TargetField=″FirstName″/>
<m:FieldMap SourceField=″LastName″TargetField=″LastName″/></m:Map><m:Map Name=″EmployeeMap″Source=″Employees″Target=″Employee″BasedOnMap=″PersonMap″BasedOnRelationship=″PE″>
<m:FieldMap SourceField=″EID″TargetField=″EmployeeID″/>
<m:FieldMap SourceField=″HireDate″TargetField=″HireDate″/>
<m:FieldMap SourceField=″Salary″TargetField=″Salary″/>
<m:RelationshipMap Source=″MyManager_R″Target=″myManager″/></m:Map><m:Map Source=″Managers″Target=″Manager″BasedOnMap=″EmployeeMap″BasedOnRelationship=″EM″>
<m:FieldMap SourceField=″Bonus″TargetField=″Bonus″/>
<m:RelationshipMap Source=″MyEmployees_R″Target=″myEmployees″/></m:Map>
在Mapping引擎里创建的实际的Map:<m:Map Name=″PersonMap″Source=″Persons″Target=″Person″>
<m:FieldMap SourceField=″SSID″TargetField=″SSID″/>
<m:FieldMap SourceField=″FirstName″TargetField=″FirstName″/>
<m:FieldMap SourceField=″LastName″TargetField=″LastName″/></m:Map><m:Map Name=″EmployeeMap″Source=″Employees″Target=″Employee″><m:RelationshipMap Source=″MyManager_R″Target=″myManager″/><m:FieldMap SourceField=″EmployeeID″TargetField=″EmployeeID″/><m:FieldMap SourceField=″HireDate″TargetField=″HireDate″/><m:FieldMap SourceField=″Salary″TargetField=″Salary″/><m:FieldMap Source=″Persons″SourceRelationship=″PE″SourceField=″SSID″TargetField=″SSID″/><m:FieldMap Source=″Persons″SourceRelationship=″PE″SourceField=″FirstName″TargetField=″FirstName″/><m:FieldMap Source=″Persons″SourceRelationship=″PE″SourceField=″LastName″Target Field=″LastName″/></m:Map><m:Map Source=″Managers″Target=″Manager″><m:RelationshipMap Source=″MyEmployees_R″Target=″myEmployees″/><m:RelationshipMap Source=″EM MyManager_R″Target=″myManager″/><m:FieldMap SourceField=″Bonus″TargetField=″Bonus″/><m:FieldMap Source=″Employees″SourceRelationship=″EM″SourceField=″EmployeeID″TargetField=″EmployeeID″/><m:FieldMap=″Employees″SourceRelationship=″EM″SourceField=″HireDate″TargetField=″HireDate″/><m:FieldMap=″Employees″SourceRelationship=″EM″SourceField=″Salary″TargetField=″Salary″/><m:FieldMap Source=″Persons″SourceRelationship=″EM PE″SourceField=″SSID″TargetField=″SSID″/><m:FieldMap Source=″Persons″SourceRelationship=″EM PE″SourceField=″FirstName″TargetField=″FirstName″/><m:FieldMap Source=″Persons″SourceRelationship=″EM PE″SourceField=″LastName″TargetField=″LastName″/></m:Map>
使用相同基数表格(不同的自定义表格)的继承例子(对象)
RSD:
<CustomTable Name=″Employees″>
<BasedOn Name=″People″AutoCommands=″true″/>
<QueryCommand>
<Condition LeftField=″TypeIdentifierColumn″Operator=″EQUAL″
RightConstant=″E″
/>
</QueryCommand>
</CustomTable>
<CustomTable Name=″Managers″>
<BasedOn Name=″People″AutoCommands=″true″/>
<QueryCommand>
<Condition LeftField=″TypeIdentifierColumn″Operator=″EQUAL″
RightConstant=″M″
/>
</QueryCommand>
</CustomTable>
MAP:<m:Map Name=″EmployeeMap″Source=″Employees″Target=″Employee″><m:FieldMap SourceField=″NAME″TargetField=″name″/><m:FieldMap SourceField=″SALARY″TargetField=″salary″/></m:Map><m:Map Source=″Managers″Target=″Manager″BasedOnMap=″EmployeeMap″><FieldMap SourceField=″BONUS″TargetField=″bonus″/></m:Map>
意思是:<m:Map Source=″Managers″Target=″Manager″><m:FieldMap SourceField=″NAME″TargetField=″name″/><m:FieldMap SourceField=″SALARY″TargetField=″salary″/><FieldMap SourceField=″BONUS″TargetField=″bonus″/></m:Map>
NULLHANDLING属性NULL的值意思是关于列的数据值是未知或无效的。NULL并不等同于零(数字的或二进制的值)、一个零长度的字符串,或者空格(字符值)。相反地,空值允许一个零输入(数字列)或是空格(字符列)与非输入(数字和字符列的NULL)之间是有区别的。没有两个空值是相等的。两个空值之间、或者在一个NULL与任何其他值之间的比较,都会返回未知的结果,因为每一个NULL的值都是未知的。空值通常指示未知的、不适用的、或是在稍后的时间新增的数据。例如,一个顾客在下订单的时候,他的中间姓名的起首字母是未知的。映射Null是一项复杂的任务,因为它的值是未知的,并且每个域对这个概念(Null)的表示都不同。有时候,它甚至可以以多种不同的方式来表示,例如,XML可以表示Null为:xsi:nil、缺少的或者空列表,对象域具有可空的类型,以及SQL类型,它是DBNull。另外,用户可能想要在代表Null的Target域里选择一个值,那个值通常被引用作Null映像。
NullHandling属性提供了从源域转换Null到目标域里的一个空值表示,以及从相反的方向转换(从一个目标域里的值到源域的空值)的能力。
属性名 |
类型 |
Card |
值 |
注释 |
NullHandling |
xsd:string |
可选 |
‘DomainNull’‘Absence’‘UseNullValue |
适用于读与写的情况 |
NullValue |
Xsd:string |
当NullHandling值为’UseNullValue’时需要,否则应该为空。 |
由用户提供 |
Null值应该是地区明白的 |
ForceNullOnInsert |
Xsd:Boolean |
可选 |
True/false |
Default=false |
在源(有比例关系的)域里定义S为源域以及在目标(对象,XML)域里定义T为目标域。S(Null)
T(基于NullHandling属性的一个值)。这意味着在询问的时候,Null是数据库(DB)到NullHandling,NullValue属性里的指定值的输出。在升级的时候,如果在目标域里的值就是上述属性所指定的,这个值在目标域里就会被翻译成在源域里的空值。每一个目标域规格说明里会指定在目标域里NullHandling的默认值和特定的行为。
当创建一个新的目标结构(对象或XML元素)以及分配一个字段给Null值、或是省略XML属性,更新引擎的默认行为是去将该值设置成在列里定义的默认值。如果没有默认值,它意味着将应用Null。
ForceNullOnInsert支持用户想要忽略上述默认行为的情况。在这种情况下,用户想要更新引擎以显式地将Null写进列中,以及忽略任何在列中定义的默认值。将ForceNullOnInsert属性设置成TRUE意味着当创建对象/元素的时候,空值会被显式地插入到在目标域里用于任何空值的列中去。这个特性的主要方案是启用传递Null到一个Insert贮藏的过程(作为一个自定义表格的插入命令而呈现)的参数。
如果NullHandling值是“UseNullValue”,可以提交NullValue。
空格字符串作为NullValue-在这个例子里,用户想要为顾客的中间姓名的起首字母属性指定为空值的空字符串。
<FieldMap SourceField=”MiddleInitial”TargetField=”MI”NullHandling=”UseNullValue”NullValue=””/>
为空值处理而使用DomainNull-在这个例子里MI是在XML域里的一个元素名。
<FieldMap SourceField=”MiddleInitial”TargetField=”MI”NullHandling=”DomainNull”/>
XML将会是<MI xsi:nil=”true”/>
USEFORCONCURRENCY属性
在最有利的并行操作文件里指定了在这个属性的需求后面的理论和推理。在映射而不是在RSD指定并行操作,原因是在某些情况下,用户想要不同的并行操作设置。考虑一个非规格化的映射到两个类的表格,这些类将具有用在并行操作控制的不同字段。总的来说,在他们的事务逻辑驱使下,人们愿意和不同的映射共享相同的RSD信息。UseForConcurrency属性是一个枚举,它有着以下值:Always-该字段通常用做并行操作并且是默认值;Never-该字段永远不会用做并行操作;Modified-如果这个字段的值已经改变,只能用做并行操作。
UseForConcurrency属性可以用于字段映射以及映射。默认的机制如下所示。如果没有指定UseForConcurrency,则默认的是“Always”。如果在映射里指定了UseForConcurrency,它将用做包含在映射里的所有字段映射和关系的UseForConcurrency的值,除非字段映射或者关系已经定义了UseForConcurrency。在这种情况下,定义的值将会忽略在Map里的默认指定值。在一个FieldMap里指定的UseForConcurrency将会忽略在Map或是RelationShipMap里定义的UseForConcurrency。
用户可以控制用于关联字段的并行操作的设置,其中的关联字段没有在RelationShipMap元素里通过指定UseForConcurrency属性而被显式地映射。注意这个RelationShipMap的属性的设置适用于所有的关联字段。有效性的工作如下。如果Alternate Key UseForConcurrency=Always,它将被用于并行操作并且如其他任何字段一样,将会基于默认的规则确定Primary Key并行操作。否则,如果Alternate Key不存在或者没有被标记为UseForConcurrency=Always,Primary KeyUseForConcurrency将会被默认为Always(映射引擎将忽略MapUseForConcurrency的值)。如果将在主键值FieldMap里的UseForConcurrency值显式地设置为其它任何值(Never或Modified),映射引擎将通过一个例外。
例子:<Map Source=″Customers″Target=″Cust″UseForConcurrency=″Modified″>
<FieldMap SourceField=″cid″TargetField=″CustomerID″/>
<FieldMap SourceField=″street″TargetField=″st″UseForConcurrency=″Never″/>
<FieldMap SourceField=″zip″TargetField=″zip″UseForConcurrency=″Never″/>
<FieldMap SourceField=″house″TargetField=″number″UseForConcurrency=″Never″/>
<FieldMap SourceField=″firstname″TargetField=″fname″UseForConcurrency=″Always″/>
<FieldMap SourceField=″lastname″TargetField=″lname″UseForConcurrency=″Always″/>
<FieldMap SourceField=″status″TargetField=″status″/></Map>
映射在内部表示如下:<Map Source=″Customers″Target=″Cust″>
<FieldMap SourceField=″cid″TargetField=″CustomerID″UseForConcurrency=″Always″<!-Ignored from Map-->/>
<FieldMap SourceField=″street″TargetField=″st″UseForConcurrency=″Never″/>
<FieldMap SourceField=″zip″TargetField=″zip″UseForConcurrency=″Never″/>
<FieldMap SourceField=″house″TargetField=″number″UseForConcurrency=″Never″/>
<FieldMap SourceField=″firstname″TargetField=″fname″UseForConcurrency=″Always″/>
<FieldMap SourceField=″lastname″TargetField=″lname″UseForConcurrency=″Always″/>
<FieldMap SourceField=″status″TargetField=″status″UseForConcurrency=″Modified″<!--Applied from Map-->/></Map>
Ref属性
Ref属性值是一个映射的名字。这个属性的语义是目标结构或目标字段被映射到指定映射的相同的源。“相同的源”的意思是从关系域里的表格选择出的集合。基于关系域的语义,在每映射一个表格,映射引擎就创建一个纪录(选择语句)的新集合。在有些情况下,例如在XML域中一个独立的情况,,用户可能想要将一个先前创建的集合映射到一个目标结构或是字段。考虑以下的情况(从XML域映射中提出),其中用户拥有一个包含客户订单的客户元素。Order元素包含了客户名。
<Customer CustomerID=”Alfki”>
<Order Orderid=”10001”CustomerName=”AlfkiName”/>
</Customer>
关联结构是随着MyBuyer Relationship的Customers和Orders表格。因此,映射看起来像这样:<Map Name=″MainCustomers″Source=″Customers″Target=″Customer″>
<FieldMap SourceField=″CustomerID″TargetField=″@CustomerID″/>
<RelationshipMap Source=″MyBuyer″Target=″Order″/>
</Map>
<Map Source=″Orders″Target=″Customer/Order″>
<FieldMap SourceField=″orderId″TargetField=″@OID″/>
<FieldMap Ref=″MainCustomers″SourceField=″name″
Target Field=″@CustomerName″
/>
</Map>
通过保存需求以用来创建另外一个集合和联结,是一个得到在订单元素里的客户名的有效的方法。注意,由于映射能从源域里的每个结构(行)创建多重的XML元素,Ref属性只能被用在XML域。另外,这个行里的值能被任何XML层次中从一个祖先传下来的行拾取,如上面的例子所示。
更新语义
映射的一个功能强大的属性是可以被更新的能力。以前需要许多程序员写大量的代码以扩展和同步在对象或XML域到SQL服务域的改变,现在可以依靠映射引擎来做这些工作。用户在对象域里创建、删除、或修改一个结构(对象或XML元素),目标域API以及映射引擎将会奇迹般地把这些改变同步(持续的)到源域,其中映射引擎就是一个在下面部分中称为CP的改变处理器(CP)。这个部分描述了在目标域里的不断的进入到源域(关系数据模型)里的变化语义。
以下的术语被附加到上述的存在、复制,以及Mapping RElationships的概念。
Target Unit-来自目标域的一个结构或一个结构群,使用映射元素把它映射到相同的源结构。一个目标结构群就是关于映射的目标,它使用Ref属性而引用另外一个映射(目标单位包括引用映射)。这是一个强加在Object域和XML域之间的区别,其中,在对象域里这样的结构群是不可能存在的,并且每一个使用映射元素映射的对象都是一个目标单位,而在XML域里可以像上述的那样创建这样的结构群。
Source Unit-在源域里的一个结构。在关系域里,一个源是一个顾客表。
Changed单位-对应于未被改变的目标单位的映射源。
CP正在察看任何改变的联系以决定操作、操作次序、以及实施在源域里有关的单位的确认。将改变应用于目标和源域的相关单位以保持它们的同步是非常复杂的。在RelationshipMap里的确认规则保证了关于目标域的改变将不会与关于CP实施实现源域的改变相冲突。这个部分描述了在源域概要里的联系元素的语义(RSD)。
From和To“From”是联系里的父单位,“To”是联系里的子单位。有必要区分父单位和子单位来决定源域里的操作次序。使用改变的类型(插入,删除以及更新)来决定执行操作的次序,对于插入/更新,父类将会先执行,对于删除,子类将会先执行。
重叠删除/重叠更新
当将改变应用到源域的时候,CP查找改变的单位和该改变单位是春父类的映射源单位之间的所有联系。重叠删除/重叠更新的值决定操作是否影响到子表格。这些属性的值决定CP或SQL服务器是否执行关于子表格的改变。
使用IsForeignKey的计算单位(表)从属性
下文在表格内(也叫做单位从属性)基于联系信息,说明计算表格内的从属性和行从属性,以用来决定用以更新引擎CP的行执行次序的语义。CP使用父(From)和子(To)的信息以及由联系元素的IsForeignKey属性指示的外部关键约束条件的存在,来决定这个从属性以及执行更新声明的次序。
以下是一个简单的层次:Customers->Orders->OrderDetails,其中没有循环引用。
<rsd:Relationship Name=″Northwind.FK_Order_OrderDetails″From=″Northwind.Orders″To=″Northwind.dbo.OrderDetails″Cardinality=″OneToMany″IsForeignKey=″true″>
<ColumnJoin Column=″OrderID″RelatedColumn=″OrderID″/></rsd:Relationship><rsd:Relationship Name=″Northwind.FK_Customer_Order″From=″Northwind.dbo.Customers″To=″Northwind.dbo.Orders″Cardinality=″OneToMany″IsForeignKey=″true″>
<ColumnJoin Column=″CustomerID″RelatedColumn=″CustomerID″/></rsd:Relationship>
以下是一个循环引用,其中,一个联系不是对服务器的一个FK约束条件(IsForeignKey=false)。这是至少在一个联系里,不在服务器里创建外部关键约束条件的情况。映射的次序是:A40→B→C。
<rsd:Relationship Name=″BC″From=″B″To=″C″Cardinality=″OneToMany″
IsForeignKey=″true″>
<ColumnJoin Column=″BID″RelatedColumn=″BID″/>
</rsd:Relationship>
<rsd:Relationship Name=″AB″From=″A″To=″B″Cardinality=″OneToMany″
IsForeignKey=″false″><!这里服务器没有一个FK约束条件->
<ColumnJoin Column=″AID″RelatedColumn=″AID″/>
</rsd:Relationship>
<rsd:Relationship Name=″CA″From=″C″To=″A″Cardinality=″OneToMany″
IsForeignKey=″true″>
<ColumnJoin Column=″CID″RelatedColumn=″CID″/>
</rsd:Relationship>
以下是一个循环引用,其中,所有的联系在服务器里都有FK约束条件。(IsForeignKey=true)。在这个情况下,所有的联系都被强加上在服务器上的外部关键约束条件。映射的次序是C→A→B。<rsd:Relationship Name=″CA″From=″C″To=″A″Cardinality=″OneToMany″IsForeignKey=″true″>
<ColumnJoin Column=″CID″RelatedColumn=″CID″/></rsd:Relationship><rsd:Relationship Name=″AB″From=″A″To=″B″Cardinality=″OneToMany″IsForeignKey=″true″>
<ColumnJoin Column=″AID″RelatedColumn=″AID″/></rsd:Relationship><rsd:Relationship Name=″BC″From=″B″To=″C″Cardinality=″OneToMany″IsForeignKey=″true″>
<ColumnJoin Column=″BID″RelatedColumn=″BID″/></rsd:Relationship>
或者<rsd:Relationship Name=″EmployeeManager″From=″Employee″To=″Employee″Cardinality=″OneToMany″IsForeignKey=″true″><!-这里,联系是在相同的表格之间->
<ColumnJoin Column=″EmployeeID″RelatedColumn=″ManagerID″/></rsd:Relationship>
在映射的编译时间中,”From”和”To”定向的属性主要用来确定表格的从属性。这解决了像第一个情况一样的所有简单的层次情况。另一方面,在上述联系方向引起循环引用的第二和第三个情况里,努力通过忽略不指向一个在服务器上实现的外部关键约束条件的联系而找出从属性(IsForeignKey=″true″)。这会访问第二个情况。如果循环引用仍然存在(例如,没有忽略联系路径,所有都被当作外部关键约束条件而被实现),那么将会以随机的方法将从属性图分解为一个层次树。
在运行期间,如果收到一个ChangeUnits,而在第一个情况里不需要进一步的操作并且按照一个编译的从属性图运行执行次序。然而,对于在第二和第三个情况里的一个循环引用,评估运行期实例,通过使用ChangeUnits.GetParents()而算出正确的执行次序。在多数情况下,运行期实例不应该形成一个图,并且将会以一个层次的方式(HaroonA->DanieID->Foo->Bar->BillG)执行改变元素。可是,即使运行期实例形成一个图,也会按照编译的时间从属性而执行该单位。这对第二个情况起作用,而在第三个情况下,所有的联系都引用到外部关键约束条件,这会引起关于插入和删除操作的服务器端约束条件的异常。
这里运算法则启用用于所有情况的有关映射编译时间的从属性计算,而将会评估运行期实例并且在第二和第三个情况下对循环引用给予优选。注意所有单位的从属性信息,一旦从映射里计算,句法就被存储在在一个经过编译的映射内部的数组里,其中对每一个源单位都分配了一个关系上的相对的顺序。甚至在上述第三个情况的无法分解的循环引用里,按照在映射文件里出现的顺序而随机地将一个图分解成一个树。这保证了一个确定性的执行次序,甚至是在无关的单位之间并且因此避免了某些潜在的死锁情况。
基数可以是一对一以及一对多。多对多与一对多有着类似的语义,因为它涉及更新。在“映射”元素将“源”属性指定的源单位称为一个强元素,而在基础的”字段映射”元素里指定的所有其它源单位都被作为弱元素引用。基数信息与弱和强的单位紧紧的耦合在一起。在一对多中,将弱元素看作是只读的。
这种情况的例子是对象窨的每一个类型继承有一个表,以及被映射到多重表格(Customer,CustomerInfo)的Customer XML元素(或类)。在这个情况下,不论对强单位还是弱单位,这个行为都是读-写,并且弱单位行的存在与强单位的存在是紧密相联的。这个意思是如果插入了一个目标单位,那么向强单位里插入了一个行,同时所有的弱单位里也插入了相应的行。同样的,如果删除了一个目标单位,那么会删除所有在强单位和弱单位里相应的行。涉及弱单位的删除属性解释为使在相应列里的值无效,不管这个列是属于强单位或弱单位。必须说明的是,即使删除映射到一个特定弱-单位的所有的目标字段,在弱单位里的行都不会被删除。一个弱单位的行只能在删除目标单位时随着强单位离开。注意这个目标字段删除的情况只存在于XLM,并不存在于对象空间,因为不能移除一个类的属性,但是可以将其无效化。
关于字段映射的Ref属性,在这个情况下,通过在字段映射里使用”Ref”属性而映射多重源单位,对所有基数的弱单位,更新语义是只读的。这服从于”Ref”属性语义,其中”Ref”属性语义意味着存在另一个映射,以控制更新语义。只读语义意思是如果插入了一个目标,那么更新操作将只会在强单位里插入一个行,而弱单位将保持不变。同样的,如果删除了一个目标,那么只会删除强单位里的行。类似地,如果改变了涉及弱单位的属性(更新/删除),那么更新引擎(CP)将会抛出异常。一个客户(ObjectSpaces,XmlCache,等)只有通过不提供关于弱单位修改的变化给CP来忽略行为。这种方法下会忽略变化,而不是引起异常。将有Ref属性而不是源的映射都集合到一个单位里,并且在没有主映射里的目标结构的情况下不能被插入或者删除。它们在概念上是主映射的一部分。这个行为的原因是主映射总能保证包含个人关键信息,并且被映射的结构必须是被映射结构的祖先,这样它才能是那个映射的拥有者结构。
在只读的字段映射中,CP将确认在一个映射在只读的字段映射里的源字段没有被改动,并且在这个情况下抛出一个错误。注意将当前任何在CustomTable的更新命令的参数绑定到只读目标字段,都是错误的。
现在参考图6A,这里图解说明了一个源数据源602和目标数据源604的一个网络图表600,其中在网络中单独处理一个映射组件606。源数据源602和目标数据源604都是只读的,并且也需要映射。根据本发明,映射组件606是用来执行从源602到目标604的映射,其中,在映射组件606的网络位置,一个用户配置映射组件606执行映射。这可以在一个全球通信网络(GCN)608来产生,例如Internet。另外,可以通过网络608来产生映射,例如LAN,WAN,WLAN,WWAN等。这个情况使顾客同意将映射操作交与一个卖主来完成的实现变的容易。卖主只要通过网络608来访问源和目标数据模型,也许,虽然不是需要的,在得到登陆信息之后,配置映射组件606来完成映射操作。这个情况也支持顾客通过LAN,WAN等来完成他或她自己的映射操作。现在参考图6B,这里示出了一个网络图表610,其中映射组件606可以被定位在源位置或是在目标的位置,或者是在这两个位置。现在参考图7,这里图解说明了用来执行公开的体系结构的一个计算机的一个块图。为了提供用于本发明的多种方面额外的前后关系关系,图7以及以下的讨论都意在提供一个合适的简洁的计算环境,总体的论述,在这个环境中,能实现本发明的多种方面。本发明已经在前面用概括的计算机能执行的指令语言说明了,本发明中的指令能在一个或多个计算机上运行,本领域的技术人员会知道本发明也可以通过结合其它程序模块和/或作为硬件和软件的结合来实现。总的来说,程序模块包括例行程序,程序,组件,数据结构等,它们完成特定的任务或是实现特定的抽象的数据类型。而且,本领域的技术人员会理解发明的方法可以用其它的计算机系统配置实践,包括单处理器或者多处理器计算机系统、微型计算机、大型计算机,也可以是个人计算机、手持计算设备、基于微处理器或者可编程的消费电子产品,以及像类似的东西,它们中的每一种都能被可操作的耦合到一个或多个相关的设备。已说明的本发明的方面也可以在分布式的计算环境中实践,其中可以通过使用一种通信网络连接的远程处理设备来完成特定任务。在一个分布式的计算环境中,可以将程序模块定位在本地或是定位在远程内存存储设备。
再一次参考图7,这里图解说明了用于实现本发明的多种方面的一个示范环境700,包括一个计算机702,计算机702包括一个处理器元素704,一个系统内存706以及一个系统总线708。系统总线708耦合了系统组件,系统组件包括,但不局限于系统内存706到处理元素704。处理元素704可以是多种商业上可用的处理器。也能采用双微处理器以及其它多处理器体系结构作为处理元素704。
系统总线708可以是许多总线结构的任意一种,包括一个内存总线或者内存控制器,一个外围总线以及一个局部总线,其中都是使用多种商业上可用的总线体系结构。系统内存706包括只读内存(ROM)710和随机访问内存(RAM)712。以存储在ROM710的一个基本的输入/输出系统(BIOS),包含基本的例行程序用来帮助在计算机702内部的元素间传递信息,例如在启动期间。
计算机702进一步包括了一个硬盘驱动器714、一个磁盘驱动器716、(例如,读写一个可移动的磁盘718)以及一个光盘驱动器720、(例如,读取一个CD-ROM盘或读写其他的光储媒介)。硬盘驱动器714、磁盘驱动器716、以及光盘驱动器720能分别通过一个硬盘驱动器接口724、一个磁盘驱动器接口726、和一个光盘驱动器接口728连接到系统总线708。驱动器和它们相关的计算机可读取的媒介提供非易失性的数据,数据结构,计算机执行的指令的存储,等等。对于计算机702,驱动器和媒介以一种合适的数字方式调整广播编程的存储。虽然上述的计算机可读取的媒介涉及硬盘、可移动的磁盘以及CD,本领域的技术人员会理解其他计算机可读取的媒介类型,例如压缩驱动器、磁带、闪存卡、数字影像盘、盒式磁盘等、,也都能用在这个示范操作环境中,更进一步包括任何包含用于执行本发明方法的计算机可执行指令的媒介。
许多程序模块都能被存储在驱动器以及RAM712,包括一个操作系统730,一个或多个应用程序732,其他程序模块734以及程序数据736。可以理解本发明能够通过商业上可用的操作系统或操作系统的结合来实现。
用户可以通过一个键盘738和一个指针设备,例如鼠标740来向计算机702输入命令和信息到计算机702中。其它的输入设备(未示出)可以包括一个麦克风、一个IR远程控制、一个摇杆、一个游戏手柄、一个圆盘式卫星电视天线、一个扫描仪等。这些及其它输入设备通常通过耦合到系统总线708的一个串行端口接口742来连接到处理元素704,但也可以通过其它的接口来连接,例如一个并行端口、一个游戏端口、一个通用串行总线(USB)、IR接口等。一个监视器744或其它类型的显示设备也通过一个接口连接到系统总线708,如一个视频适配器746。除了监视器744之外,一个典型的计算机包括其它外围输出设备(未示出),如扬声器,打印机等。
计算机702可以在一个网络的环境里操作,使用到一个或多个远程计算机的逻辑连接,例如远程计算机748。远程计算机748可以是一个工作站,一台服务器计算机,一个路由器,一个个人计算机,便携式计算机,基于微处理器的娱乐设备,一个对等设备或者其它通用网络节点,并且通常包括许多或所有所描述的与计算机702相关的元素,虽然为了简洁的目的,只示出了一个内存存储设备。所述的逻辑连接包括一个局域网(LAN)752和一个广域网(WAN)754。这样的网络环境在办公室、企业范围的计算机网络、内联网和Internet,是很平常的。
当在一个LAN网络环境中使用的时候,计算机702通过一个网络接口或适配器756连接到局域网络752。适配器756能有助于到LAN752的有线或无线的通信,其中,LAN752也可以包含一个之后用来与无线适配器756通信的无线访问点。当在一个WAN网络环境中使用的时候,计算机702通常包括一个调制解调器758,或被连接到在LAN上的一个通信服务器,或有着其它通过WAN754建立通信的方式,例如Internet。调制解调器758,可以是内部或外部的,通过串行端口接口742连接到系统总线708。在一个网络的环境下,涉及计算机702的所述的程序模块,或其中的部分,可以存储在远程内存存储设备750。应理解所示的网络连接是示范性的,也可以使用其它建立计算机之间通信连接的方式。
现在参考图8,这里说明了根据本发明的一个示范性计算环境800的原理块图。系统800包括一个或多个客户端802。客户端802可以是硬件和/或软件(例如:线程,进程,计算设备)。例如,通过采用本发明,客户端802可以收藏Cookies和/或相关的原文信息。系统800也包括一个或多个服务器804。服务器804也可以是硬件和/或软件(例如:线程,进程,计算设备)。例如,采用本发明,服务器804可以收藏用来执行转换的线程。一个在客户端802和服务器804之间的可能的通信可以是用来在两个或多个计算机进程之间传输的数据包的形式。例如,数据包可以包括一个Cookie和/或相关的原文信息。系统800包括一个通信主机806(例如,一个全球通信网络,像Internet),可以用它来方便客户端802与服务器804之间的通信。通过有线(包括光纤)和/或无线的技术,能使通信变得便利。操作将客户端802连接到一个或多个客户端数据存储器808,它可以用来存储本地到客户端802的信息(例如,收藏夹和/或相关的原文信息)。类似的,操作将服务器804连接到一个或多个服务器数据存储器810,它可以被用来存储本地到服务器804的信息。
现在参考图9,这里说明了一个根据本发明的串级链映射实现的块图。可以理解所公开的新颖的映射体系结构使一个串级链映射情况的实现变的便利,其中可以以一种从源数据模型S1(任意结构的)到目标数据模型TN(任意结构的)的串行的方法来配置类似于图1的系统100的多重阶段900,这种配置是随着任何数目的中间级以制造所需要的中间数据的转换,到最终在目标数据模型TN(目的地)提供所要求的数据格式。在原文中示出的一个阶段900包括一个源模型S、一个映射组件M、以及一个目标数据模型T。当串级链随着多重阶段900的时候,一个中间目标数据模型T1同样也是一个其次阶段902的数据源S2。因此,将一个中间数据模型(例如,T1/T2)标记为用于先前阶段900的映射组件M1的目标的T1,以及用于之后阶段902的之后映射组件M2的目标的T2。
数据模型可以包括,但不局限于查询语言,数据存取语言,数据操纵语言,数据定义语言,对象模型,关系模型,以及XML模型。
在一个例子中,目的是从一个源数据模型S1映射数据到一个模表数据模型T2。考虑源S1是一个关系数据结构,目标T2是一个XML数据结构。进一步考虑从源S1到目标T2的路径只提供一个基于对象的路径。第一阶段映射M1使用适当的源S1的关系描述组件和目标T1的对象描述组件以进行从源S1到中间目标T1的映射。下一步,中间目标T1不是映射组件M2的源S2。映射组件M2接着用适当的对象描述组件和XML描述组件来完成从源S2到目标T2的映射。
由于这样的能力,可以理解,根据特定的应用程序,可以采用任何数目的阶段(900和902)。
现在参考图10,这里说明了本发明的映射结构体系的一个hub-and-spoke的实现。这个实现在一个大型的网络环境里是非常有用的,例如,Internet或大型的公司网络,其中,由于网络中断,在任何时间点上的数据通路的有效性、有效带宽等会受到影响。这里提供了一个中央控制实体1000,用于与任意数目的数据源(S1,S2,和S3)通信,其中数据来自和/或通过数据源传送或查询,也与任意数目的中间数据目标1008(也被指示为T/S)通信。最终,可以要求映射是从源(S1,S2和S3)中的一个到一个目标T2。
中央控制实体1000包括一个控制组件1002控制实体1000的所有方面;一个描述组件源1004,它存储着许多可访问的、用于从一个数据模型类型到另一个的转换的描述运算规则(例如,一个关系,Object,XML,...);以及一个交换机制1006,用做在源(S1,S2和S3)和中间目标1008之间选定路线或交换数据。
操作中,例如,从一个第一个中间数据源目标1010发起到源S1的数据查询。源S1的数据结构是关系而目标1010是XML。从目标1010到源S1的查询提供了到控制组件1002的转换信息,这样,可以检索以及/或从用于完成映射的源1004生成适当的relation-to-XML映射运算规则。因此映射功能是实体1000的一部分。
在一个更广泛的例子里,其中可以将与一个数据模型相反的映射请求(查询或更新)转化为到一个或多个不同数据模型的请求,如果查询是通过任一中间目标/源1008而从目标T2发起到源S1,实体1000能通过中间数据源1008选择最佳的路径。例如,如果源S1是关系,目标T2是XML,第一个中间数据源1010是基于对象的,第二个中间数据源1012是基于关系的,第三个中间数据源1014是基于XML的,实体1000可以通过第二个中间数据源1012,确定从源S1到目标T2的最佳路径。一旦做出这个决定,控制组件1002采用一个关系到关系的从源S1到中间数据源1012的映射(来自源1004),由此在第二个控制实体1016(类似于控制实体1000)里的一个映射组件采用一个的从第二个中间数据源1012到目标T2的映射relation-to-XML。控制实体(1000和1016)可以通过连接1018来通讯,通过任一经由数据源到目标T2的通讯路径,来协调路径的选择。
正如上面指出的,数据源间的映射可以是相似的数据结构,例如,关系到关系,XML到XML,等。这就是说这样的情况可以存在,其中源关系数据库可以被映射到一个有着不同关系结构的目标关系数据库。类似的,可以存在一个情况,其中将源对象数据映射到一个有着不同对象结构的目标对象数据模型。仍然可以进一步,可以存在一个情况,其中将源XML数据映射到一个有着不同XML结构的目标XML数据模型。
现在参考图10,这里说明了根据本发明的一个方面的一个可堆栈的结构1100。在图10的网络的实现中被采用这个能力。映射框架提供了一套方便的格式,APIs(Application Programmable Interfaces),优化程序,实用程序,以及用于允许用户实现在任意两个任意数据模型之间的数据处理的工具。任何人都可以实现他自己的到QIL编译器(查询独立语言)的查询以用于与任何其它数据源相对的自动执行。QIL是一个到一个数据源的查询(或更新)的通用数据源独立表示。映射允许映射请求(查询或更新)用以反对一个数据模型被转换到对一个不同数据模型的请求的能力。
所述的APIs包括关系1102,XML1104,Object1106,以及其它1108。因此,为了能得到执行,一个查询能在映射的多个层(1110,1112和1114)之间移动,并且能在返回前映射多次结果。映射和QIL是组成的。映射是双向的,也就是可逆的,并且允许自然的更新性能。
上述包括本发明的例子。当然,不可能说明每一种可以想像到的组件的组合或是描述本发明的方法论,但是一个本领域的普通技术人员可以知道很多进一步的本发明的进一步组合和排列都是可行的。因此,本发明意在包含所有这样的属于所附权利要求的精神和范围内的变更、修改和变化。此外,就用于详细的说明以及权利要求里的术语“包括”来说,这个术语意在与术语“包含”相容,例如采用“包含”,权利要求中作为一个过渡的词使用时的含意。