/
howto-create-entity.html
237 lines (193 loc) · 17.9 KB
/
howto-create-entity.html
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
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Create an Entity</title><link rel="stylesheet" href="css/style.css" type="text/css" /><meta name="generator" content="DocBook XSL Stylesheets V1.75.2" /><link rel="home" href="index.html" title="" /><link rel="up" href="tutorials.html" title="Tutorials" /><link rel="prev" href="howto-create-sideeffect.html" title="Create a SideEffect" /><link rel="next" href="howto-configure-service.html" title="Configure a Service" />
<!-- favicon -->
<link rel="shortcut icon" href="http://qi4j.org/favicon.ico" type="image/vnd.microsoft.icon" />
<link rel="icon" href="http://qi4j.org/favicon.ico" type="image/x-icon" />
<!-- style -->
<link href="css/shCore.css" rel="stylesheet" type="text/css" />
<link href="css/shCoreEclipse.css" rel="stylesheet" type="text/css" />
<link href="css/shThemeEclipse.css" rel="stylesheet" type="text/css" />
<link href="css/qi4j.css" rel="stylesheet" type="text/css" />
<!-- Syntax Highlighter -->
<script type="text/javascript" src="js/shCore.js"></script>
<script type="text/javascript" src="js/shBrushJava.js"></script>
<script type="text/javascript" src="js/shBrushScala.js"></script>
<script type="text/javascript" src="js/shBrushJScript.js"></script>
<script type="text/javascript" src="js/shBrushBash.js"></script>
<script type="text/javascript" src="js/shBrushPlain.js"></script>
<script type="text/javascript" src="js/shBrushXml.js"></script>
<script type="text/javascript" src="js/shBrushGroovy.js"></script>
<script type="text/javascript" src="js/shBrushPython.js"></script>
<script type="text/javascript" src="js/shBrushRuby.js"></script>
<script type="text/javascript" src="js/shBrushCSharp.js"></script>
<script type="text/javascript">
SyntaxHighlighter.defaults['tab-size'] = 4;
SyntaxHighlighter.defaults['gutter'] = false;
SyntaxHighlighter.defaults['toolbar'] = false;
SyntaxHighlighter.all()
</script>
<!-- JQuery -->
<script type="text/javascript" src="js/jquery-1.6.4.min.js"></script>
<!-- Image Scaler -->
<script type="text/javascript" src="js/imagescaler.js"></script>
<!-- Table Styler -->
<script type="text/javascript" src="js/tablestyler.js"></script>
<!-- Qi4j WebSite Progressive Enhancement -->
<link href="css/progressive-enhancement.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="js/jquery.scrollTo-1.4.2.js"></script>
<script type="text/javascript" src="js/progressive-enhancement.js"></script>
<!-- Analytics -->
<script type="text/javascript">
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-3118496-1']);
_gaq.push(['_trackPageview']);
(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head><body><div xmlns="" xmlns:exsl="http://exslt.org/common" class="logo"><a href="index.html"><img src="images/logo-standard.png" /></a></div><div xmlns="" xmlns:exsl="http://exslt.org/common" class="top-nav"><div xmlns="http://www.w3.org/1999/xhtml" class="toc"><dl><dt><span class="section"><a href="index.html#home">Qi4j</a></span></dt><dt><span class="section"><a href="intro.html">Introduction</a></span></dt><dt><span class="section"><span xmlns="" href="tutorials.html">Tutorials</span></span></dt><dt><span class="section"><a href="javadocs.html">Javadoc</a></span></dt><dt><span class="section"><a href="samples.html">Samples</a></span></dt><dt><span class="section"><a href="core.html">Core</a></span></dt><dt><span class="section"><a href="libraries.html">Libraries</a></span></dt><dt><span class="section"><a href="extensions.html">Extensions</a></span></dt><dt><span class="section"><a href="tools.html">Tools</a></span></dt><dt><span class="section"><a href="glossary.html">Glossary </a></span></dt></dl></div></div><div xmlns="" xmlns:exsl="http://exslt.org/common" class="sub-nav"><div xmlns="http://www.w3.org/1999/xhtml" class="toc"><dl><dt><span class="section"><a href="tutorials.html#_overview">Overview</a></span></dt><dt><span class="section"><a href="two-minutes-intro.html">Qi4j in 2 minutes</a></span></dt><dt><span class="section"><a href="ten-minutes-intro.html">Qi4j in 10 minutes</a></span></dt><dt><span class="section"><a href="thirty-minutes-intro.html">Qi4j in 30 minutes</a></span></dt><dt><span class="section"><a href="two-hours-intro.html">Qi4j in 2 hours</a></span></dt><dt><span class="section"><a href="howto-depend-on-qi4j.html">Depend on Qi4j in your build</a></span></dt><dt><span class="section"><a href="howto-assemble-application.html">Assemble an Application</a></span></dt><dt><span class="section"><a href="tut-composites.html">Transient Composites Tutorial</a></span></dt><dt><span class="section"><a href="tut-services.html">Services Composites Tutorial</a></span></dt><dt><span class="section"><a href="howto-contextual-fragments.html">Use contextual fragments</a></span></dt><dt><span class="section"><a href="howto-leverage-properties.html">Leverage Properties</a></span></dt><dt><span class="section"><a href="howto-create-constraint.html">Create a Constraint</a></span></dt><dt><span class="section"><a href="howto-create-concern.html">Create a Concern</a></span></dt><dt><span class="section"><a href="howto-create-sideeffect.html">Create a SideEffect</a></span></dt><dt><span class="section"><span xmlns="" href="howto-create-entity.html">Create an Entity</span></span></dt><dt><span class="section"><a href="howto-configure-service.html">Configure a Service</a></span></dt><dt><span class="section"><a href="howto-use-io.html">Use I/O API</a></span></dt><dt><span class="section"><a href="build-system.html">Build System</a></span></dt><dt><span class="section"><a href="community-docs.html">Writing Qi4j Documentation</a></span></dt></dl></div></div><div class="section" title="Create an Entity"><div class="titlepage"><div><div><h3 class="title"><a id="howto-create-entity"></a>Create an Entity</h3></div></div></div><p>One of the most common tasks in Qi4j is the management of the life cycle of Entities. Since Qi4j is capable of
delivering much higher performance than traditional Object-Relational Mapping technologies, we also expect that people
use Entities more frequently in Qi4j applications, so it is a very important topic to cover.</p><p>If you want to reproduce what’s explained in this tutorial, remember to depend on the Core Bootstrap artifact:</p><div class="table"><a id="idp19320712"></a><p class="title"><b>Table 12. Artifact</b></p><div class="table-contents"><table summary="Artifact" border="1"><colgroup><col /><col /><col /></colgroup><thead><tr><th align="left" valign="top">Group ID</th><th align="left" valign="top">Artifact ID</th><th align="left" valign="top">Version</th></tr></thead><tbody><tr><td align="left" valign="top"><p>org.qi4j.core</p></td><td align="left" valign="top"><p>org.qi4j.core.bootstrap</p></td><td align="left" valign="top"><p>2.0</p></td></tr></tbody></table></div></div><br class="table-break" /><p>Moreover, you’ll need an EntityStore for persistence and an Indexing engine for querying. Choose among the available
implementations listed in the <a class="xref" href="extensions.html" title="Extensions">Extensions</a> section.</p><p>At runtime you will need the Core Runtime artifact too. See the <a class="xref" href="howto-depend-on-qi4j.html" title="Depend on Qi4j in your build">Depend on Qi4j in your build</a> tutorial for details.</p><div class="section" title="Basics First"><div class="titlepage"><div><div><h4 class="title"><a id="_basics_first"></a>Basics First</h4></div></div></div><p>All Entity operations MUST be done within a UnitOfWork. UnitOfWorks can be nested and if underlying UnitOfWorks are not
completed (method complete()), then none of the operations will be persisted permanently.</p><p>Entity composites are subtypes of the EntityComposite interface.</p><p>Domain code typically don’t need to know of the EntityComposite types directly, and is instead using the domain specific
interface. The Visibility rules will be applied to associate the right EntityComposite when a domain type is requested.
Ambiguities are not accepted and will result in runtime exceptions.</p><p>Qi4j supports that each entity instance can have more than one entity type, and it is managed per instance. This feature
is beyond the scope of this HowTO and will be covered subsequently.</p></div><div class="section" title="Good Practice"><div class="titlepage"><div><div><h4 class="title"><a id="_good_practice"></a>Good Practice</h4></div></div></div><p>We have made the observation that it is good practice to separate the internal state from the observable behavior. By
this we mean that it is not a good practice to allow client code to manipulate or even view the internal states of
objects, which is such a common (bad) practice in the so called POJO world.</p><p>Instead, we recommend that the programmer defines the client requirement of what each participant within the client
context needs to conform to, and then create composites accordingly and hide all the state internal to the composite in
private mixins. By doing so, the same entity can participate in multiple contexts with different behavioral requirements
but using the same internal state.</p><p>We recommend limited use of primitive types for Properties and instead subtype the Property.</p><p>And try to use ValueComposites instead of Entities.</p></div><div class="section" title="The Entity"><div class="titlepage"><div><div><h4 class="title"><a id="_the_entity"></a>The Entity</h4></div></div></div><p>We need an entity to illustrate how we recommend to separate internal state from public behavior and observable state.
We will for the sake of simplicity use a trivial example. Please refer to other (possibly future) HowTos on patterns on
Entity management.</p><pre class="programlisting brush: java">public interface Car
{
@Immutable
Association<Manufacturer> manufacturer();
@Immutable
Property<String> model();
ManyAssociation<Accident> accidents();
}
</pre><pre class="programlisting brush: java">public interface Manufacturer
{
Property<String> name();
Property<String> country();
@UseDefaults
Property<Long> carsProduced();
}
</pre><pre class="programlisting brush: java">public interface Accident
{
Property<String> description();
Property<Date> occured();
Property<Date> repaired();
}
</pre><p>Above we define a Car domain object, which is of a particular Manufacturer (also an Entity), a model and a record of
Accidents.</p><p>We will also need to define the composites for the above domain structure;</p><pre class="programlisting brush: java">public interface CarEntity extends Car, EntityComposite
{}
</pre><pre class="programlisting brush: java">public interface ManufacturerEntity extends Manufacturer, EntityComposite
{}
</pre><pre class="programlisting brush: java">public interface AccidentValue extends Accident, ValueComposite
{}
</pre><p>For this case, we define both the Car and the Manufacturer as Entities, whereas the Accident is a Value, since it is an
immutable event that can not be modified.</p></div><div class="section" title="Assembly"><div class="titlepage"><div><div><h4 class="title"><a id="_assembly"></a>Assembly</h4></div></div></div><p>All of the above must also be declared in the assembly. We MUST associate the EntityComposites with a relevant Module.
We must also assemble an EntityStore for the entire application, but that is outside the scope of this HowTo.</p><pre class="programlisting brush: java">public class MyAssembler
implements Assembler
{
public void assemble( ModuleAssembly module )
{
module.entities( CarEntity.class,
ManufacturerEntity.class );
module.values( AccidentValue.class );
[...snip...]
}
}
</pre><p>We have no other Composites involved yet, so we can proceed to look at the usage code.</p><p>We recommend that the life cycle management of entities is placed inside domain factories, one for each type and made
available as services.</p></div><div class="section" title="The Entity Factory"><div class="titlepage"><div><div><h4 class="title"><a id="_the_entity_factory"></a>The Entity Factory</h4></div></div></div><p>The entity factory is something you need to write yourself, but as with most things in Qi4j it will end up being a
fairly small implementation. So how is that done?</p><pre class="programlisting brush: java">public interface CarEntityFactory
{
Car create(Manufacturer manufacturer, String model);
}
</pre><p>That is just the domain interface. We now need to make the service interface, which Qi4j needs to identify services and
make it possible for the service injection later.</p><pre class="programlisting brush: java">@Mixins( { CarEntityFactoryMixin.class } )
public interface CarEntityFactoryService
extends CarEntityFactory, ServiceComposite
{}
</pre><p>Then we need an implementation of the mixin.</p><pre class="programlisting brush: java">public class CarEntityFactoryMixin
implements CarEntityFactory
{
</pre><p>And doing that, first of all we need to request Qi4j runtime to give us the UnitOfWorkFactory associated with the Module
that our code belongs to, and the UnitOfWork current context the execution is happening in.</p><p>Injections that are related to the Visibility rules are handled by the @Structure annotation. And the easiest way for us
to obtain a UnitOfWorkFactory is simply to;</p><pre class="programlisting brush: java">public class CarEntityFactoryMixin
implements CarEntityFactory
{
@Structure
UnitOfWorkFactory uowf;
</pre><p>Here Qi4j will inject the member uowf with the correct UnitOfWorkFactory. In case we only need the UnitOfWorkFactory
during the construction, we can also request it in the same manner as constructor argument.</p><pre class="programlisting brush: java">public CarEntityFactoryMixin( @Structure UnitOfWorkFactory uowf )
{
}
</pre><p>This is important to know, since the injected member will not be available until AFTER the constructor has been
completed.</p><p>We then need to provide the implementation for the create() method.</p><pre class="programlisting brush: java">public Car create(Manufacturer manufacturer, String model)
{
UnitOfWork uow = uowf.currentUnitOfWork();
EntityBuilder<Car> builder = uow.newEntityBuilder( Car.class );
Car prototype = builder.instance();
prototype.manufacturer().set( manufacturer );
prototype.model().set( model );
return builder.newInstance();
}
</pre><p>So far so good. But how about the Manufacturer input into the create() method?</p><p>DDD promotes the use of Repositories. They are the type-safe domain interfaces into locating entities without getting
bogged down with querying infrastructure details. And one Repository per Entity type, so we keep it nice, tidy and
re-usable. So let’s create one for the Manufacturer type.</p><pre class="programlisting brush: java">public interface ManufacturerRepository
{
Manufacturer findByIdentity(String identity);
Manufacturer findByName(String name);
}
</pre><p>And then we repeat the process for creating a Service…</p><pre class="programlisting brush: java">@Mixins( ManufacturerRepositoryMixin.class )
public interface ManufacturerRepositoryService
extends ManufacturerRepository, ServiceComposite
{}
</pre><p>and a Mixin that implements it…</p><pre class="programlisting brush: java">public class ManufacturerRepositoryMixin
implements ManufacturerRepository
{
@Structure
private UnitOfWorkFactory uowf;
@Structure
private Module module;
public Manufacturer findByIdentity( String identity )
{
UnitOfWork uow = uowf.currentUnitOfWork();
return uow.get(Manufacturer.class, identity);
}
public Manufacturer findByName( String name )
{
UnitOfWork uow = uowf.currentUnitOfWork();
QueryBuilder<Manufacturer> builder =
module.newQueryBuilder( Manufacturer.class );
Manufacturer template = templateFor( Manufacturer.class );
builder.where( eq( template.name(), name ) );
Query<Manufacturer> query = uow.newQuery( builder);
return query.find();
}
}
</pre><p>But now we have introduced 2 services that also are required to be declared in the assembly. In this case, we want the
Services to be available to the application layer above, and not restricted to within this domain model.</p><pre class="programlisting brush: java">public class MyAssembler
implements Assembler
{
public void assemble( ModuleAssembly module )
{
module.entities( CarEntity.class,
ManufacturerEntity.class );
module.values( AccidentValue.class );
module.addServices(
ManufacturerRepositoryService.class,
CarEntityFactoryService.class
).visibleIn( Visibility.application );
}
}
</pre></div><div class="section" title="The UnitOfWork"><div class="titlepage"><div><div><h4 class="title"><a id="_the_unitofwork"></a>The UnitOfWork</h4></div></div></div><p>If you notice, there is a couple of calls to UnitOfWorkFactory.currentUnitOfWork(), but what is current UnitOfWork, and
who is setting that up?</p><p>Well, the domain layer should not worry about UoW, it is probably the responsibility of the application/service layer
sitting on top. That could be a web application creating and completing a UoW per request, or some other co-ordinator
doing long-running UnitOfWorks.</p><p>There are of course a lot more details to get all this completed, but that is beyond the scope of this HowTo.</p></div></div><div xmlns="" xmlns:exsl="http://exslt.org/common" class="footer">(c) 2012 The Qi4j Community</div></body></html>