围绕EMF探索(1)之存储和查询
围绕EMF探索(1)之存储
EMF(Eclipse Modeling Framework)的应用会越来越多,而围绕EMF的query, validate, transaction, persistency等等讲逐渐被大家使用,以及EMF eCore也有非常大的参考价值。今天先讲讲EMF的存储与查询方面的内容。
首先讲讲EMF对象的存储
这两天抽空玩了玩EMF的对象存储,采用了Eclipse Teneo这个组件。这是一种桥梁式的组件,为EMF对象提供了一个持久化的解决方案。目前支持Hibernate和JDO的实现方式。Eclipse Teneo的前身是elver persistency组件,后并入Eclipse EMF Tools项目工程下。
Teneo让EMF对象的存储变得非常简单。这样我们只需要关注EMF对象的关系,而不用过多的考虑每一个eObject该如何与数据库表对应。
在使用Hibernate的情况下,Teneo会根据ePackage所描述的Model中的eObject对象之间的关系,自动的产生hiernate.hbm.xml映射文件。当然我们可以手工指定mapping文件来强制描述eObject与数据库表结构的关系。详细可以参看:
http://www.elver.org/hibernate/hibernate_details.html#orgeneration
简单的采用Teneo操作eObjects是非常容易的事情,在elver上也提供了那个经典的“Library Model”实例的实现例子,可参考:
http://www.elver.org/hibernate/tutorialone/tutorial1_intro.html
final
HbDataStoredataStore
=
HbHelper.INSTANCE.createRegisterDataStore(dataStoreName);
dataStore.setEPackages( new EPackage[]{LibraryPackage.eINSTANCE});
final SessionFactorysessionFactory = dataStore.getSessionFactory();
Sessionsession = sessionFactory.openSession();
session.beginTransaction();
LibraryAdapterFactoryadapterFactory = new LibraryAdapterFactory();
Librarylibrary = LibraryFactory.eINSTANCE.createLibrary();
library.eAdapters().add(adapterFactory.createAdapter(library));
library.setName( " MyLibrary " );
session.save(library);
Writerwriter = LibraryFactory.eINSTANCE.createWriter();
writer.setName( " WriterOne " );
Bookbook = LibraryFactory.eINSTANCE.createBook();
book.setPages( 305 );
book.setTitle( " TheHobbit " );
book.setCategory(BookCategory.SCIENCE_FICTION_LITERAL);
book.getWriter().add(writer);
library.getWriters().add(writer);
library.getBooks().add(book);
session.getTransaction().commit();
session.close();
dataStore.setEPackages( new EPackage[]{LibraryPackage.eINSTANCE});
final SessionFactorysessionFactory = dataStore.getSessionFactory();
Sessionsession = sessionFactory.openSession();
session.beginTransaction();
LibraryAdapterFactoryadapterFactory = new LibraryAdapterFactory();
Librarylibrary = LibraryFactory.eINSTANCE.createLibrary();
library.eAdapters().add(adapterFactory.createAdapter(library));
library.setName( " MyLibrary " );
session.save(library);
Writerwriter = LibraryFactory.eINSTANCE.createWriter();
writer.setName( " WriterOne " );
Bookbook = LibraryFactory.eINSTANCE.createBook();
book.setPages( 305 );
book.setTitle( " TheHobbit " );
book.setCategory(BookCategory.SCIENCE_FICTION_LITERAL);
book.getWriter().add(writer);
library.getWriters().add(writer);
library.getBooks().add(book);
session.getTransaction().commit();
session.close();
再说说EMF的查询吧。
Teneo本身提供了一对查询的支持,比如针对Hibernate的实现,支持对HQL的检索。
Queryquery
=
session.createQuery(
"
SELECTbookFROMBookbook,WriterwritWHERE
"
+ " book.title='1984'ANDbook.author=writANDwrit.name='G.Orwell' " );
books = query.list();
+ " book.title='1984'ANDbook.author=writANDwrit.name='G.Orwell' " );
books = query.list();
但是,Teneo仅仅支持Hibernate的HQL,或JDO的JDOQL,略显得不够完善,或者说,让对象检索变得有些“污染”。
我比较喜Eclipse EMF项目工程下有EMF Query组件,这个组件为“内存中的eObjects”的检索提供一套“查询条件”,但目前EMF Query仅支持内存中的对象关系,这就局限来其现实中的应用价值。
当然,EMF Query和Teneo还是在某些不要求效率的情况下能够配合起来的。
public
CollectionqueryLargeBook(EObjectroot)
...
{
SELECTselect=newSELECT(newFROM(root),newWHERE(
newEObjectAttributeValueCondition(LibraryPackage.eINSTANCE
.getBook_Pages(),newNumberCondition.IntegerValue(
newInteger(10),newInteger(Integer.MAX_VALUE)))));
returnselect.execute();
}
SELECTselect=newSELECT(newFROM(root),newWHERE(
newEObjectAttributeValueCondition(LibraryPackage.eINSTANCE
.getBook_Pages(),newNumberCondition.IntegerValue(
newInteger(10),newInteger(Integer.MAX_VALUE)))));
returnselect.execute();
}
Queryquery
=
session.createQuery(
"
FROMLibrary
"
);
Listlibraries = query.list();
Librarylibrary = (Library)libraries.get( 0 );
Collectionbooks = queryLargeBook(library);
Listlibraries = query.list();
Librarylibrary = (Library)libraries.get( 0 );
Collectionbooks = queryLargeBook(library);
在内部实现上,EMF Query会把所有的源对象都装载进内存中,在内存中遍历,并依次判断是否符合所设定的查询条件。下表中代码截取自emf query的Select对象,演示了遍历寻找符合条件的对象的算法。
protected
void
doResume()
...
{
EObjecteObject=null;
setResultSet(newQueryResultSet());
booleancanPrune=getFromClause().canBePruned();
WHEREwhereClause=getWhereClause();
while(it.hasNext()&&(isCancelled()==false))...{
eObject=(EObject)it.next();
if(whereClause.matches(eObject))...{
addEObject(eObject);
if(getResultSet().size()==maximumResultSize)...{
break;
}
}
}
}
EObjecteObject=null;
setResultSet(newQueryResultSet());
booleancanPrune=getFromClause().canBePruned();
WHEREwhereClause=getWhereClause();
while(it.hasNext()&&(isCancelled()==false))...{
eObject=(EObject)it.next();
if(whereClause.matches(eObject))...{
addEObject(eObject);
if(getResultSet().size()==maximumResultSize)...{
break;
}
}
}
}
EMF Query构造了条件(Condition)对象,这个Condition有点“(函数式编程)Function Programming”的影子了,确切的说,应该是“一元谓词(
UnaryPredicate)”。有关java的FP,可参考我的另一篇blog:
http://blog.csdn.net/james999/archive/2005/01/09/246404.aspx
不过,EMF Query的Condition并没有基于任何开源FP的基础,既没有基于apache的Common Functor,也没有基于JGA(http://jga.sourceforge.net/)。
EMF Query内部结构和实现,我目前还没有看完,姑且先不细说,留待后面补充。