关联关系在应用系统设计开发中,无论在对象关系上还是在表间关系上都是常见问题。对于ECM产品,企业操作最多的就是文档,从业务上讲,仅文档关联而言就是一块大内容,不同企业不同部门其关联规则也是大不相同。FileNet产品为文件关联提供了Link类。比较自己维护两个文档关联的好处是,首先企业文档极有可能是存在版本的,Link的关联是可以针对版本的;再有Link作为对象是可以继承的同时利用它获取关联的文档会很方便。下面的代码对创建连个文档的关联及相应的查询操作进行一点点展示。
public void LinkExample(){
String ceUrl = "http://19.19.19.19:9080/wsi/FNCEWS40MTOM/";
String domainName = " domainName ";
String objectStoreName = " objectStoreName ";
//get objectStore
Connection conn = Factory.Connection.getConnection(ceUrl);
Subject subject = UserContext.createSubject(conn, "Administrator", "passw0rd", null);
UserContext userContext = UserContext.get();
userContext.pushSubject(subject);
Domain domain = Factory.Domain.getInstance(conn, domainName);
ObjectStore os = Factory.ObjectStore.fetchInstance(domain, objectStoreName, null);
//create link
Link link = Factory.Link.createInstance(os, "PathwalkLink");
Document docSrc = Factory.Document.fetchInstance(os, new Id("{03804DAC-1A21-485B-A9E3-F392D0C8468E}"),null);
Document docDes = Factory.Document.fetchInstance(os, new Id("{D6B1F1AC-2C4F-45A3-95A2-087B0D4328CC}"), null);
link.set_Head(docSrc);
link.set_Tail(docDes);
link.save(RefreshMode.REFRESH);
Document docHead = (Document)link.get_Head();
//search link
SearchSQL searchSql = new SearchSQL();
searchSql.setFromClauseInitialValue("Link", "d", true);
//searchSql.setWhereClause("Head=" + )
SearchScope searchScope = new SearchScope(os);
IndependentObjectSet indeObjSet = searchScope.fetchObjects(searchSql, 100, null, true);
System.out.println(indeObjSet.isEmpty());
for(Iterator iter = indeObjSet.iterator();iter.hasNext(); ){
if(docHead.equals((Document)((Link)iter.next()).get_Head())){
System.out.println("the doc has link? yes");
System.out.println("the tail doc is: " + ((Document)(((Link)iter.next()).get_Tail())).toString());
break;
}
}
//Search A to B
SearchSQL searchSql2 = new SearchSQL();
searchSql2.setFromClauseInitialValue("Link ", "d", true);
searchSql2.setWhereClause("Head = OBJECT('" + docHead.get_Id().toString() + "')");
SearchScope searchScope2 = new SearchScope(os);
IndependentObjectSet indeObjSet2 = searchScope2.fetchObjects(searchSql2, 100, null, true);
for(Iterator iter = indeObjSet2.iterator(); iter.hasNext();){
System.out.println("the tail doc id that come from 'search A to B ' is:" + ((Document)((Link)iter.next()).get_Tail()).get_Id().toString());
break;
}
}
代码大致分为三块内容,首先是获取访问CE的必备条件ObjectStore,而后是对对两个document创建link,使用到了Link最为重要的两个方法set_Head和set_Tail,最后进行了关联查询。
在业务上通常我们是通过一个已知的document来查询与之关联的document,代码中展示的也是这个过程。但代码写出出了两种类似的实现方式。对比下//search link和//Search A to B不难看出它们的区别有两个。一个是查询Link的过程,另一个是获取关联document的过程。前者是将所有的Link都查询出来进行遍历,而后者则是直接从SearchScope和searchSQL查询的结果中取出。当然后者是我们提倡的方法,它是高效的。
它们的本质区别在于查询过程,对比//search link中的//searchSql.setWhereClause("Head=" + )以及//Search A to B中的searchSql2.setWhereClause("Head = OBJECT('" + docHead.get_Id().toString() + "')");会发现,后者使用了关键字Object,其作用是在查询的时候将给定的document id转化成相应的document object。因为Link的Head和Tail中所存储的是Object而非简单的标识,所以查询时需要在where子句中指定object才可以。懂得了使用关键字OBJECT自然就会很容易的使用第二中方法了。
本文通过一个简单例子讲解了ECM文档关联在FileNet中的实现及相应的查询过程。其中包含有很多CE的核心知识点,例如获取Domain、objectStore、document object以及使用SearchScope和SearchSQL查询等内容。对Link类存在的好处仅做了简单概述,要在实践中深刻思考其存在的深远意义才好。