Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: d8a30e483e9766086e1db26961dcd2e3f702c0e0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
<?xml version="1.0" encoding="UTF-8"?>
<!--
	Copyright (c) 2005, 2006 Springsite BV (The Netherlands) and others
	All rights reserved. This program and the accompanying materials
	are made available under the terms of the Eclipse Public License v1.0
	which accompanies this distribution, and is available at
	http://www.eclipse.org/legal/epl-v10.html
-->

<!--
	@author <a href="mtaal@elver.org">Martin Taal</a>
	@version $Revision: 1.3 $ $Date: 2006/09/26 12:45:14 $
-->

<!DOCTYPE document PUBLIC
	"-//APACHE//DTD Documentation V2.0//EN"
	"http://forrest.apache.org/dtd/document-v20.dtd">

<document> 
	<header> 
		<title>EMF - Hibernate Integration Details</title> 
		<abstract>Discusses a number of specific implementation and use details of the EMF - Hibernate integration.</abstract>
	</header> 
	<body>
		<section><title>Classloader</title>
			<p>Teneo performs explicit classloading in specific locations. It is possible to set the classloader which is being
			user by Teneo. This can be done through the org.eclipse.emf.teneo.ClassLoaderResolver class. In this class you can 
			register a org.eclipse.emf.teneo.classloader.ClassLoaderStrategy. The registered ClassLoaderStrategy is used by 
			Teneo to explicitly load classes.</p>
		</section>
		<section><title>Requirements on EObjects: InternalEObject</title>
		<p>The EMF Hibernate persistency layer only requires that the persisted objects implement
			the org.eclipse.emf.ecore.InternalEObject interface.</p>
		</section>
		<section>
			<title>Relational Validation and EObject persistency</title>
			<p>When an object is made persistent by session.save() then at 
				that moment also constraints, such as nullable fields, are checked. So when
				calling the session.save method the passed EObject should be valid.</p>
		</section>
		<section><title>Automatic creation of tables/Database Schema</title>
		<p>The EMF Hibernate persistency layer will automatically update the database schema 
		when a new SessionFactory is registered. The Hibernate class org.hibernate.tool.hbm2ddl.SchemaUpdate class is used for
		this purpose.</p>
		<p>An <a href="hbdatastore.html#options">option</a> can be used to control if the database schema should be updated when a new HbDataStore
		is created.</p>
		</section>
		<section id="orgeneration"><title>Manual Generation of OR Mapping</title>
		<p>Standard Teneo will automatically map the model to Hibernate when a datastore is initialized. However, it can sometimes make sense to manually
		adapt the mapping or use a specific mapping file. For this purpose Teneo also allows you to manually generate the mapping file. To do this right
		click on one or more .ecore files and choose the relevant option in the Teneo submenu.</p>
		<p> </p>
		<figure src="images/elver_menu.gif" alt="Manual generation of hibernate or mapping"/>
		<p>The hibernate.hbm.xml is created in the folder of the selected .ecore file. To direct Teneo to use this mapping file you 
		need to do the following:</p>
		<ol><li>Copy the hibernate.hbm.xml to the generated EPackage source tree and let it be copied to the output directory/destination when building.</li>
		<li>Pass the following option: PersistenceOptions.USE_MAPPING_FILE with the value "true" to the HbDataStore.</li>
		</ol>
		<p><strong>Note:</strong> the generation of the hibernate.hbm.xml will only work if the org.eclipse.emf.teneo.hibernate.runtime plugin has been added to the 
		dependencies of the projects of the selected .ecore files.</p>
		</section>
		<section id="escaping"><title>Escaping of table and column names</title>
		<p>Teneo will escape table and column names of primitive types. Escaping is done by surrounding the name with backtics (`).</p>
		<p>Note that:</p>
		<ul>
			<li>Join table names are not escaped: Hibernate will in some cases automatically create a table to store the contents of a collection,
			for example the contents of a list with primitive types. Hibernate will not automatically escape this name. To escape such a join table you 
			need to add a JoinTable annotation with an escaped name or a non-keyword name.</li>
			<li>Teneo will not escape column names of manually specified Column annotations</li>
		</ul>
		</section>
		<section><title>Lazy loading/fetching, Proxy</title>
			<p>The Hibernate integration does not make use of the Hibernate Proxy.</p>
			<p>Primitive features and single refererences are eagerly loaded. ELists are 
		lazily loaded. In the future probably also single-references will be lazily loaded.</p>
		</section>
		<section><title>Synthetic ID and Version properties</title>
			<p>When Teneo detects that a certain type does not have an id or version annotated property then
			it will add these automatically. The synthetic id and version are hidden for the developer. You can
			retrieve the hidden synthetic id or version through the class org.eclipse.emf.teneo.hibernate.mapping.identifier.IdentifierCacheHandler.
			You can prevent the automatic adding of a synthetic version property by setting the PersistenceOptions.ALWAYS_VERSION 
			to false, see <a href="options.html">here</a>. If this property is false then only efeatures with a version annotation are
			translated into a version mapping.</p>
			<p>Synthetic id and version use object equality (==), this means that synthetic id and version will not
			work if objects are transferred to other systems and back (for example in case of client-server communication).</p>
		</section>
		<section id="cutpaste">
			<title>Move an EObject between EContainers or support cut and paste in the EMF editor</title>
			<p>In the standard approach it is not possible to move an EObject from one containment relation to another containment relation. A move
			between containment relations corresponds to a cut and paste in the EMF editor. The reason is that Teneo will 
			specify an orphan-delete cascade for a containment relation. This has a consequence that Hibernate will throw 
			an exception (deleted object would be re-saved by cascade, remove deleted object from associations) when you move an EObject from its container to another container. 
			See <a href="http://opensource.atlassian.com/projects/hibernate/browse/HHH-785">here</a> for a description.</p>
			<p><em>Solution:</em> as a solution you can prevent the orphan-delete from being set as the cascade style, by specifying 
			an annotation on the relevant EReference features or by setting the global runtime property PersistenceOptions.SET_CASCADE_ALL_ON_CONTAINMENT
			to false (see <a href="options.html">here</a>). As an example of the first approach:</p>
			<source><![CDATA[
<xsd:element maxOccurs="unbounded" minOccurs="0" name="writers" type="lib:Writer">
	<xsd:annotation>
		<xsd:appinfo source="teneo.jpa">@OneToMany(cascade={MERGE,PERSIST,REFRESH,REMOVE})</xsd:appinfo>
	</xsd:annotation>
</xsd:element>
			]]></source>
			<p>This annotation means that cascading deletes are still enforced but a child (the Writer) can exist without its
			parent (the Library).</p>
			<p>When this annotation is used in the context of a Hibernate Resource then when an EObject is removed from 
			its container then it will also be removed from the resource and from the database. However, when you set this 
			annotation and not work with Hibernate Resources then the removed EObject is not removed from the database and will 
			be present without a container!</p>
		</section>
		<section>
			<title>Validation</title>
			<p>When storing and retrieving EMF objects from a Hibernate store it is not required to work with a 
			EMF type Resource. However the standard EMF validator checks if every EObject is
			present in an EMF resource and that all referenced EObjects are in the same resource. So, if 
			this standard validator is used unnecessary errors are thrown.
			</p>
			<p>To prevent this situation you can register your own validator which does not perform this resource check. 
				See the example here below.
			</p>
			<p>
			Validators are registered using a call to put method of the EValidator.Registry.INSTANCE object.
			</p>
			<source>			
public class MyValidator extends EObjectValidator
{
	/** 
	* Overrides the method from the superclass to prevent this check because it
 	* is not required in the context of a hibernate store. Note that this assumes that 
 	* an object and its references are all stored in the same hibernate database. 
 	*/
	public boolean validate_EveryReferenceIsContained(EObject eObject, DiagnosticChain diagnostics, Map context) 
	{
		return true;
	}
}
			</source>
		</section>
		<section><title>Default cacheprovider is org.hibernate.cache.HashtableCacheProvider</title>
			<p>Default cacheprovider has been set to org.hibernate.cache.HashtableCacheProvider because of ehcache issues which occur when using
			ehcache with the default values.</p>
			<p>Encountered error message was: 
			<em>Attempt to restart an already started EhCacheProvider. Use sessionFactory.close()  between repeated calls to buildSessionFactory. Consider using net.sf.ehcache.hibernate.SingletonEhCacheProvider. Error from  ehcache was: Cannot parseConfiguration CacheManager. Attempt to create a new instance of CacheManager using the diskStorePath "/tmp" which is already used by an existing CacheManager. The source of the configuration was classpath.</em>
			</p>
			<p>The HashtableCacheProvider is not for production use. You can override this default setting by setting the hibernate.cache.provider_class property with the cache provider class you want to use.
			</p>
		</section>
		
	</body>
</document>

Back to the top