对象化查询之OCL vs. OPath

令人心动的对象化查询

对象化查询是O/R Mapping中非常让人心动的一个特性,当所有的表对我们来说不复存在后,我们可以对实体进行CRUD,可是当我们需要返回多个实体的结果集时,我们怎么办呢?Dataset做为载体是必然的,可是我们查询过滤数据的方式是怎样的?sqlNo!我们就是在尽量避免直接使用sql,因为sql不便于重构,可移植性太差,拼凑出来的sql语句对测试覆盖率也有影响。所以大家都期待着可以用对象化查询来根除将Entity再当做Table来处理的尴尬。

 

.Net下的O/R Mapper对对象化查询的支持

目前为止,.Net下的O/R Mapper对对象化查询的支持绝大部分都是非常有限的:NHibernate用的是HQL语句,其本质可以说是一种把Entity看做Table的改装后的sql语句,DataObjects.NetNHibernate差不多,也有一套自己的类sql对象化查询语法,其它很多O/R Mapper使用的是简单的属性过滤查询,而说到对对象化查询支持得最强大的,要算ECOⅡ和ObjectSpaces,前者使用的是OCL语法,后者是OPath

 

OCL起源

OCLOMG组织制订的UML语言规范的一部分,它的初衷是用来对UML模型视图中的Object添加约束描述的,并不是一种编程语言,而OCL应用到O/R Mapping中就俨然成了一种对对象进行查询的语言(OQL)。

 

OPath起源

OPathMS提出的在WinFS中准备大量使用的一种对象查询语言,从它的命名上可以看出和XPath的相似之处,MS的口号一直是把复杂的东西变简单,把简单的东西变成自动化。所以这个OPath确实不可小觑。

 

简单的例子

先我们从一个简单的例子入手,假设有如下的实体关系(画图太麻烦,还浪费空间):

Department (code name employees)

Employee(code name department salary)

查询

OCL

OPath

包含薪水大于3000的员工所有部门

Department.allInstances->select(self.employees.includes(salary > 3000))

Exists(employees[saleary > 3000])

得到部门001的所有员工

Employee.allInstances->select(self.department.code = ‘001’)

Department.code = ‘001’

所有员工薪水都大于3000的部门

Department.allInstances->select(self.employees.forAll(salary > 3000))

不支持

员工最高薪水大于3000的部门

Department.allInstances->select(self.employees.includes(salary > 3000))

不支持

 

功能比较

从这个列表中可以看到OPath的语法要简洁得多,但OCL的集合操纵能力却是OPath无法比拟的,下面是OCL的一些集合函数:

名称

功能

Collect

得到一个属性的集合

Exists

如果存在符合条件的元素为真

forAll

只有所有集合元素符合条件时才为真

Includes

是否包含某个对象

Select

获取符合条件的一个子集

Reject

减去符合条件的一个子集

IsEmpty

集合为空

NotEmpty

集合不为空 

此外,ECOⅡ对集合操作还有增强,如提供了sumavgmaxmin的聚集操作函数,同时它还支持多种非聚集函数,如concatlengthtouppertolower等。

 

其它的一些特性:

特性

OCL

OPath

NULL判断

支持

支持

Implies(表示如果左边为真,那么右边也要为真)

支持

A implies B可以转化为(A and B) or (Not A)

类型判断和转换

支持

Distinct

支持(通过Set集合返回)

不支持(因为只是对象获取和属性过滤,没有集合操作,所以不涉及到子集合,而外部对象集合一般有主键约束)

集合内元素获取

支持

不支持

Order By

支持

不支持,但可以通过调用查询对象的方法达到目的

 

假如增强OPath的话,大概会是什么样子?

如果要支持集合操作的话,那么现有的OPath语法的简单性肯定要大打折扣,比如说类似于OCL中的forAllOPath如果要实现的话,可能的方法就是:

(Employees[salary > 3000].Count = Employees.Count)

 

性能比较

因为现在ObjectSpaces中的OPath语句最后都将转为SQL执行,所以它的性能是非常好的(时这也正是它功能无法强大的弱点),而OCL的语法只有部分才能转化为SQL,因此在ECOⅡ中,还有部门的OCL操作必须针对内存对象来进行,这样也就使得必须装载大量的实体对象到内存中。

 

你将选择哪种查询?

就我个人而言,我倾向于增强型的OPath。毕竟更加复杂的查询我们可以通过viewstore procedure来完成,就算OCL再强大,也无法涵盖我们需要的查询功能,其内存对象操纵的性能问题不能不让我们谨慎使用,而ECOⅡ可以算是一个MDA的框架,这也让我对MDA的将来感到一些担忧,除非ANSI SQL进化到了可以更加强大的地步,各数据库本身就可以完成OCL所需要的查询功能,但这个时候,也许SQL的表达更加直观,那么,我们又为什么需要OCL来查询呢。当然,OCLUML中的作用我们并不否定,只是直接从模型生成代码的应用似乎只能在不太复杂的场合才生效。

 

(注:因为ECOⅡ的资料很少,很多是参考它的前身bold for delphi的语法,而OPath的资料也少,很多都是无关痛痒的简单操作,这让人弄不明白到底是它的语法就这么简单还是另有其它的增强。)

posted @ 2005-01-26 10:50  progame  阅读(2897)  评论(4编辑  收藏  举报