由于把模型交给最终用户手里动态调整,模型本身就存在这进化的过程。例如当模型元素原先设定为长整型 (xs:long) 类型,后来发现该元素还需要可以容纳负数 xs:negativeInteger 的值,此时,模型结构的定义就需要做出相应的调整,这就是模型进化的一个情形。同样的,为了适应需求,模型结构可能发生别的变化,比如增加一些新元素,增加新的约束条件等。
对于向前兼容的模型进化,可以在原有的模型上进行修改,比如上述的类型变化,可以通过模型定制界面修改模型元素的类型为其共同的父类型 xs:integer,或者新增加模型元素。这样可以不影响既有的模型实例,又能适应进化后的模型。
对于向前不兼容的模型进化,例如删除某模型元素,增加约束条件,修改模型元素名称等,则需要对模型做特殊处理。可以将进化前的模型复制到新模型,赋予新的版本,然后基于新版本的模型进行修改,之后的模型实例都基于该新版本模型生成,从而达到模型进化的目的。
一些担忧和对策
模型定制减轻了开发者的负担,但是模型的不断进化给模型的管理带来了挑战。如果没有一定的约束,那么,日积月累,模型的数量将会越来越多,最后导致无法管理。
解决这类问题的办法有两种:
其一,将模型定制的权限限制在一个较小的范围,例如开放给管理员,由客户指派的管理员专门进行模型定制,对模型的修改需要通过相应的授权。这样就可以在制度上解决这个问题;
其二,对于模型元素,提供元素字典,定制任何模型都必须从该字典中选取元素。,这样,可以给最终用户更加粗粒度的定制方式,减轻了模型混乱的可能性。
另外,提供基本的模型给用户,让客户在这个模型基础上进行扩展,也是比较好的方式之一。
在性能上,由于模型本身的不确定性,系统无法在最初就在 XML 上创建相应的索引来提高查询效率。因此在让用户定义模型的时候,可以给用户选项,是否优化某模型元素的查询性能,从而确定在哪个元素上添加索引。
模型的安全性也是需要考虑的要素之一,在模型定制的过程中,应该尽量采用参数化形式操作,例如之前的模型元素增加,不采用直接 SQL 拼接的方式,而使用参数化的形式进行节点更新。从而避免恶意的语句危及数据库的安全。
清单 7. 采用参数化形式进行节点更新
update template set schema_info = xmlquery( 'declare namespace xsd="http://www.w3.org/2001/XMLSchema"; transform copy $new:=$i modify do insert $newpart as last into $new/xsd:schema/xsd:element/xsd:complexType/xsd:sequence return $new' passing schema_info as "i") where XMLEXISTS('declare namespace xsd="http://www.w3.org/2001/XMLSchema";$doc/xsd:schema/xsd:element[@name=$parentName]' PASSING schema_info AS "doc", “parentName” as $parentName, ? as “newpart”);