记得刚开始使用EMF时,我就觉得它跨文件保存对象的功能非常强大方便。
而使用WTP持久化EMF对象就没有这么方便了。毕竟WTP对保存的格式做了
严格的限制。
为了实验,我随便建立了一个模型,如下所示:
Shiep代表学校,包含若干系,每个系有若干老师。
Document是每个老师的档案,Documents是包含Document的容器。
建立这样一个模型的原因:学校要求把学校资料和老师档案分开保存。
这样Document就不能象平时一样把Document和Teacher设为包含(containment)关系。
一,EMF持久化
如果使用EMF自带的保存方法,建立完模型也就结束了:)
1.保存对象的代码片断:
Shiep shiep
=
ModelFactory.eINSTANCE.createShiep();
Depart electric
=
ModelFactory.eINSTANCE.createDepart();
electric.setName(
"
electric
"
);
shiep.getDeparts().add(electric);
Teacher andy
=
ModelFactory.eINSTANCE.createTeacher();
andy.setName(
"
andy
"
);
electric.getTeachers().add(andy);
Resource shiepRes
=
resourceSet.createResource(URI
.createURI(
"
file:///home/winters/emftest/shiep.xml
"
));
shiepRes.getContents().add(shiep);
Documents root
=
ModelFactory.eINSTANCE.createDocuments();
Document d1
=
ModelFactory.eINSTANCE.createDocument();
d1.setOwner(andy);
//
这个andy对象就是跨文件保存的对象
d1.setContent(
"
He is a very good teacher.
"
);
root.getChildren().add(d1);
Resource documentsRes
=
resourceSet.createResource(URI
.createURI(
"
file:///home/winters/emftest/documents.xml
"
));
documentsRes.getContents().add(root);
shiepRes.save(
null
);
documentsRes.save(
null
);
2.看看EMF的保存结果:
Shiep.xml:
<?
xml version="1.0" encoding="ASCII"
?>
<
org
.shiep.edu.model:Shiep xmlns:org.shiep.edu.model
="http:///org/shiep/edu/model.ecore"
>
<
departs
name
="electric"
>
<
teachers
name
="andy"
/>
</
departs
>
</
org.shiep.edu.model:Shiep
>
Document.xml:
<?
xml version="1.0" encoding="ASCII"
?>
<
org
.shiep.edu.model:Documents xmlns:org.shiep.edu.model
="http:///org/shiep/edu/model.ecore"
>
<
children
content
="He is a very good teacher."
>
<
owner
href
="shiep.xml#//@departs.0/@teachers.0"
/>
</
children
>
</
org.shiep.edu.model:Documents
>
在Document.xml中EMF使用了<owner href="shiep.xml#//@departs.0/@teachers.0"/>这
一行来表示其它文件中的对象。
3.对象保存好了,从文件中读取对象的过程也非常方便。
读取对象的代码片断:
Resource docRes
=
resourceSet.getResource(URI.createURI(
"
file:///home/winters/emftest/documents.xml
"
),
true
);
Resource shiepRes
=
resourceSet.getResource(URI.createURI(
"
file:///home/winters/emftest/shiep.xml
"
),
true
);
Documents root
=
(Documents) docRes.getContents().get(
0
);
Teacher andyFromDoc
=
((Document)root.getChildren().get(
0
)).getOwner();
Shiep shiep
=
(Shiep) shiepRes.getContents().get(
0
);
Teacher andyFromShiep
=
(Teacher) ((Depart) shiep.getDeparts().get(
0
)).getTeachers().get(
0
);
assertEquals(andyFromDoc, andyFromShiep);
//
true
就这么简单。
二,WTP持久化
不幸的是我要使用WTP持久化机制来保存对象,这样EMF这么强大的功能我不得不自己来实现了。
1.要使用WTP持久化EMF对象前期准备必须做一些工作。
因为这些地方没有什么特别的,所以我也就不每个都细细来讲了,有兴趣的可以看代码。
1)Translator
因为两个保存得文件是不同的XML格式(使用不同的DTD文件),所以我必须写两个Translator
DocumentsTranslator
ShiepTranslator
2)EntityResolver
同样是两个
DocumentsEntityResolver
ShiepEntityResolver
3)ResourceImpl和ResourceFactoryImpl
全部是double
DocumentsResourceImpl
DocumentsResourceFactoryImpl
ShiepResourceImpl
ShiepResourceFactoryImpl
4)DTD文件
shiep.dtd:
<!
ELEMENT shiep (department*)
>

<!
ELEMENT department (teacher*)
>
<!
ATTLIST department name CDATA #IMPLIED
>

<!
ELEMENT teacher EMPTY
>
<!
ATTLIST teacher name CDATA #IMPLIED
>
documents.dtd:
<!
ELEMENT documents (document*)
>

<!
ELEMENT document (owner, content)
>
<!
ELEMENT owner (#PCDATA)
>
<!
ELEMENT content (#PCDATA)
>
2.更改模型
在document.xml文件中,我是使用Teacher的name来标识Teacher的。这样我
必须在Document模型中加上一个OwnerName属性:
/**
* @model transient="true" volatile="true"
*/
String getOwnerName();
transient和volatile表示这个属性是可以在运行期间根据其它信息能够计算出来的。
而ownerName可以根据owner得到。
3.看看WTP保存的结果吧:
shiep.xml:
<?
xml version="1.0" encoding="UTF-8"
?>
<!
DOCTYPE shiep PUBLIC "public id" "dtds/shiep.dtd"
>
<
shiep
>
<
department
name
="electric"
>
<
teacher
name
="andy"
/>
<
teacher
name
="Jacky"
/>
<
teacher
name
="richard"
/>
</
department
>
</
shiep
>
document.xml:
<?
xml version="1.0" encoding="UTF-8"
?>
<!
DOCTYPE documents PUBLIC "public id" "dtds/documents.dtd"
>
<
documents
>
<
document
>
<
owner
>
andy
</
owner
>
<
content
>
He is a very good teacher.
</
content
>
</
document
>
<
document
>
<
owner
>
Jacky
</
owner
>
<
content
>
He like playing basketball.
</
content
>
</
document
>
<
document
>
<
owner
>
richard
</
owner
>
<
content
>
He like coffee.
</
content
>
</
document
>
</
documents
>
4.从文件中读取对象
这个时候没有了EMF的跨文件保存功能,只能自己来一个个匹配了。代码如下:
Shiep shiep
=
(Shiep) shiepRes.getContents().get(
0
);
Depart depart
=
(Depart) shiep.getDeparts().get(
0
);
EList teachers
=
depart.getTeachers();
Resource docRes
=
docResourceSet.getResource(URI
.createURI(
"
file:///home/winters/emftest2/documents.doc.xml
"
),
true
);
Documents root
=
(Documents) docRes.getContents().get(
0
);
EList documents
=
root.getChildren();
for
(Iterator it
=
teachers.iterator(); it.hasNext();)
{
Teacher teacher = (Teacher) it.next();
for (Iterator docIt = documents.iterator(); docIt.hasNext();) {
Document doc = (Document) docIt.next();
if (doc.getOwnerName().equals(teacher.getName())) {
doc.setOwner(teacher);
break;
}
}
}

for
(Iterator iter
=
documents.iterator(); iter.hasNext();)
{
Document element = (Document) iter.next();
System.out.println(element.getOwner() + " : "
+ element.getContent());
}
代码输出:
andy : He is a very good teacher.
Jacky : He like playing basketball.
richard : He like coffee.
5.小结:
使用这个我觉得很简单也很原始的方法很直观,但是也有不足之处,那就是我首先做出了这样一个假设:
每个老师的名字都不相同。如果实际情况更加复杂,那就要根据ID之类的来判断了。
附件:
这个例子的代码
http://pickup.mofile.com/3343335105319994
本文介绍了如何使用EMF进行跨文件持久化对象,并对比了使用WTP进行持久化的复杂过程,包括创建Translator、EntityResolver、ResourceImpl和ResourceFactoryImpl等,以及手动匹配对象的需求。
5155

被折叠的 条评论
为什么被折叠?



