-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcodes.html
818 lines (669 loc) · 41.9 KB
/
codes.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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
<HTML>
<HEAD>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="css/docs.css">
<!-- <link rel="stylesheet" href="css/zenburn.min.css"> -->
<link rel="stylesheet" href="css/default.min.css">
<script src="lib/highlight.min.js"></script>
<script type="text/javascript">hljs.initHighlightingOnLoad();</script>
</HEAD>
<BODY>
<div id="LeftSide">
<a class="menu-main-item" href="#Introduction">Introduction</a>
<a class="menu-child-item" href="#GetStarted">Get started</a>
<a class="menu-child-item" href="#Requirements">Limitations and requirements</a>
<a class="menu-child-item" href="#Terminology">Terminology and naming</a>
<a class="menu-main-item" href="#Ideas">Ideas</a>
<a class="menu-child-item" href="#BoilerPlateFree">Free from boiler plate code</a>
<a class="menu-child-item" href="#DAO">DAO is interface</a>
<a class="menu-child-item" href="#AnnotationsFree">Free from annotations</a>
<a class="menu-child-item" href="#WeakDependence">Weak dependence</a>
<a class="menu-main-item" href="#TargetClasses">Target class and annotations</a>
<a class="menu-child-item" href="#OrmDao">OrmDao</a>
<a class="menu-child-item" href="#TargetQuery">@TargetQuery</a>
<a class="menu-child-item" href="#TargetFilter">@TargetFilter</a>
<a class="menu-child-item" href="#TargetDao">@TargetDao</a>
<a class="menu-child-item" href="#TargetMethod">@TargetMethod</a>
<a class="menu-child-item" href="#TargetField">@TargetField</a>
<a class="menu-child-item" href="#TargetConstructor">@TargetConstructor</a>
<a class="menu-main-item" href="#SqlQueries">Sql Queries</a>
<a class="menu-child-item" href="#SELECT">SELECT</a>
<a class="menu-child-child-item" href="#ColumnsAndFields">Columns and fields</a>
<a class="menu-child-child-item" href="#ColumnFilters">Column filters</a>
</div>
<div id="RightSide"><span></span></div>
<div id="CenteredContent">
<div id="ContentBody">
<h1 id="Introduction">Introduction</h1>
<p>RefOrms is SQL-oriented JDBC framework, similar to Spring Framework JDBC but having several advantages over it.
Your thoughts, approaches and actions will be related to SQL by 99%.
You will be exempted from the routine and boilerplate code such as setting parameters to PreparedStatement
or reading the result from ResultSet or setting result to DTO. Nothing but SQL</p>
<h2 id="GetStarted">Get started</h2>
<p>Using maven release dependency</p>
<pre><code class="html">
<dependency>
<groupId>com.github.reforms</groupId>
<artifactId>reforms</artifactId>
<version>2017.08.07</version>
</dependency></code></pre>
<p>Using maven last dependency. Helpful for developing mode</p>
<pre><code class="html">
<dependency>
<groupId>com.github.reforms</groupId>
<artifactId>reforms</artifactId>
<version>master-SNAPSHOT</version>
</dependency>
<!-- Don't forget to add sonatype-staging repo for access to last dependency -->
<repository>
<id>sonatype-staging</id>
<url>https://oss.sonatype.org/content/groups/staging/</url>
</repository></code></pre>
<details>
<summary>
<span>See full pom examples with last version</span>
</summary>
<pre><code class="html">
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>doc</artifactId>
<groupId>examples</groupId>
<version>1-SNAPSHOT</version>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>com.github.reforms</groupId>
<artifactId>reforms</artifactId>
<version>master-SNAPSHOT</version>
</dependency>
</dependencies>
<repositories>
<repository>
<id>sonatype-staging</id>
<url>https://oss.sonatype.org/content/groups/staging/</url>
</repository>
</repositories>
</project>
</code></pre></details>
<p>Free open source <a href="https://github.com/reforms/reforms">RefOrms</a> code on github</p>
<h2 id="Requirements">Limitations and requirements</h2>
<p>1) Java 8 and upper</p>
<p>2) SQL expression based on ANSI SQL92 standard. But important SQL-specific part like paging,
date api and some other SQL expressions are supported too for most known DBMS (Oracle, MsSQL, PostreSql)</p>
<p>3) RefOrms framework <span class="color-red">doesn't have external dependencies</span> and it's good news</p>
<h2 id="Terminology">Terminology and naming</h2>
<p>We will discuss using 3 layouts: Dao, Orm and App. Dao is layout to accessing some data, Orm is POJO/DTO object wich contains some data
and App is layout to build application using Dao and Orm elements</p>
<p>All examples below will using next naming pattern for layout
<ul>
<li>Entity layout naming pattern like that <span class="color-dark-red text-bold">YourOrm</span>:
<div class="block-item"><span class="color-dark-red text-bold">YourOrm</span> - entity object like Client, Person, Car and so on</div>
</li>
</ul>
<ul>
<li>Dao layout naming pattern like that <span class="text-bold">I</span><span class="color-dark-red text-bold">YourOrm</span><span class="text-bold">Dao</span>:
<div class="block-item"><span class="text-bold">I</span> - interface marker and interface class is expected</div>
<div class="block-item"><span class="color-dark-red text-bold">YourOrm</span> - entity object like Client, Person, Car and so on</div>
<div class="block-item"><span class="text-bold">Dao</span> dao layout marker</div>
<div class="block-item"><span >Summary: for Client entity we will have IClientDao class name</span></div>
</li>
</ul>
<ul>
<li>App layout naming pattern like that <span class="color-dark-red text-bold">YourOrm</span><span class="text-bold">App</span>:
<div class="block-item"><span class="color-dark-red text-bold">YourOrm</span> - entity object like Client, Person, Car and so on</div>
<div class="block-item"><span class="text-bold">App</span> - business layout marker</div>
<div class="block-item"><span >Summary: for Client entity we will have ClientApp class name</span></div>
</li>
</ul>
<p>
<h1 id="Ideas">Ideas</h1>
<h2 id="BoilerPlateFree">Free from boiler plate code</h2>
<p>Generally, does anyone like to write boiler plate code? Free from boiler plate code is root idea and hard task for RefOrms.
Being a developer there is an understanding of that the less code the better. Great efforts are spent to adhere to this rule here.</p>
<h2 id="DAO">DAO is interface</h2>
<p>It is assumed that access to the data will be carried out through the so-called DAO pattern.
It is assumed that DAO will be interface with annotated methods. Interface-way help you keep code clean, readable and aesthetic.
See example below for undestanding base idea
</p>
<pre><code class="java">
public interface IClientDao {
// All records from clients table will automatically converted to List<Client>
@TargetQuery("SELECT id," +
" name," +
" state " +
"FROM clients")
List<Client> loadAllClients();
@TargetQuery("INSERT INTO clients ( id, name, state) " +
"VALUES (:id, :name, :state)")
void saveClient(@TargetFilter Client client);
} </code></pre>
<details>
<summary>
<span>SQL table clients</span>
</summary>
<pre><code class="sql">
--PostreSql. Client Table:
CREATE TABLE clients (
id bigint NOT NULL, -- 1, 2, 3 and so on
name character varying(127) NOT NULL, -- Lovy Babon, Jim Martin and so on
state int NOT NULL -- 1 - ACTIVE, 2 - BLOCKED, 3 - DELETED
);</code></pre>
</details>
<details>
<summary>
<span>Client entity</span>
</summary>
<pre><code class="java">
// You can use lombok to escape boilerplate code like get/set/toString
// @lombok.Data
public class Client {
private long id;
private String name;
// automatically converted from state column
private ClientState state;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ClientState getState() {
return state;
}
public void setState(ClientState state) {
this.state = state;
}
@Override
public String toString() {
return "Client(" + id + ", " + name + ", " + state + ")";
}
}</code></pre></details>
<details>
<summary>
<span>ClientState enum</span>
</summary>
<pre><code class="java">
public enum ClientState {
ACTIVE(1),
BLOCKED(2),
DELETED(3);
private int state;
ClientState(int state) {
this.state = state;
}
public int getState() {
return state;
}
}</code></pre></details>
<details>
<summary>
<span>ClientApp - how to using code</span>
</summary>
<pre><code class="java">
public class ClientApp {
public void doWorkWithClients() throws SQLException {
try (Connection connection = resolveConnection()) {
IClientDao cliensDao = OrmDao.createDao(connection, IClientDao.class);
List<Client> clients = cliensDao.loadAllClients();
clients.forEach(System.out::println);
}
}
public void saveClient(long id, String name, ClientState state) throws SQLException {
Client newClient = new Client();
newClient.setId(id);
newClient.setName(name);
newClient.setState(state);
try (Connection connection = resolveConnection()) {
IClientDao cliensDao = OrmDao.createDao(connection, IClientDao.class);
cliensDao.saveClient(newClient);
}
}
private Connection resolveConnection() {
// code here to resolving your connection or connection holder
}
}</code></pre></details>
<p>In the above example, one method <span class="text-bold color-dark-red">loadAllClients</span> select all records
from clients table and map result to list of Client entities. Second method, <span class="text-bold color-dark-red">saveClient</span>,
store Client entity to clients table. It's as simple as possible is not it?</p>
<h2 id="AnnotationsFree">Free from annotations</h2>
<p>This may seem strange but usaging annotated code as little as possible - central idea of RefOrms framework.
Yes, it is impossible to refuse completely but reduce the number of annotations to a minimum - possible.
In the above example only two annotations are using. In more cases you need 1 annotation <span class="text-bold color-dark-red">@TargetQuery</span> for SQL query
and 1 annotation <span class="text-bold color-dark-red">@TargetFilter</span> for query filtering. Absence of annotations implies the search for alternative solutions.
For example, you can annotate entity class fields to link them with table columns. But why? You can map columns to entity fields in SQL query.
For example, you can annotate constructor(s) in entity class. But why? We can detect a more suitable constructor ourselves</p>
<h2 id="WeakDependence">Weak dependence</h2>
<p>One of the tasks RefOrms framework is make you code clean from RefOrms infrastructure. This is very important for several reasons.
You should be able to change the framework for working with DB if you wish. Your application should have your code and not the code of RefOrms or
any other frameworks. This is the right message. It idea is more like philosophy but it's have practice base. So summary, you will have one
<span class="text-bold color-dark-red">OrmDao</span> class for create Dao in your App layer and 3 annotations for using inside Dao layer.
Yes, we have more classes for achievement advanced features and some settings to your specific needs.
Free from annotations is also part of the weak dependence idea.
</p>
<h1 id="TargetClasses">Target class and annotations</h1>
<h2 id="OrmDao">OrmDao</h2>
<p>Class <span class="color-jclass">com.reforms.orm.OrmDao</span> is central to create YourOrmDao impl inside your App layer. It contains one base method createDao. See example below</p>
<pre><code class="java">
class YourApp {
/**
* @param connectionHodler is java.sql.Connection
* or connection holder object like java.sql.DataSource
* or any object with getConnection() method
*/
public void someMethod(Object connectionHodler) {
IClientDao cliensDao = OrmDao.createDao(connectionHodler, IClientDao.class);
List<Client> clients = cliensDao.loadAllClients();
// do work with clients here
}
}
</code></pre>
<p>Method <span class="color-jclass">OrmDao.createDao</span> require connection <span class="color-strong">holder</span> object at first argument and DAO interface class in the second argument.
It's very important to undestand the idea of connection <span class="color-strong">holder</span> object. The connection holder object is responsible for
getting java.sql.Connection impl. The connection holder object must to returning the <span class="color-strong">same</span> instance of the connection
each times when required inside Dao layer. It's pattern naming as connection per task or if you are developing client-server app - connection per request.
YourOrmDao impl which produces from createDao method is not responsible for closing the connection. Connection holder may be one of th next:</p>
<ul>
<li>Intsance of <span class="color-jclass">java.sql.Connection</span>;</li>
<li>Intsance of <span class="color-jclass">java.sql.DataSource</span>;</li>
<li>Intsance of any class with public Connection getConnection() method inside;</li>
</ul>
<p>Also YourOrmDao impl which produces from <span class="color-jclass">OrmDao.createDao</span> method is not <span class="color-strong">thread safe</span>
</p>
<h2 id="TargetQuery">@TargetQuery</h2>
<p><span class="text-bold color-dark-red">@TargetQuery</span> using for declare the SQL query expresion and any extra information. It contains next properties:</p>
<ul>
<li><span class="text-bold color-dark-red">type</span> - type of SQL query like SELECT, INSERT, UPDATE, DELETE and CALL. In most cases not need to declare because framework can be resolved it automatically</li>
<li><span class="text-bold color-dark-red">query</span> - SQL query expression. If any properties absent is more best using value property for SQL query</li>
<li><span class="text-bold color-dark-red">value</span> - SQL-query expression for short style, if nothing except query</li>
<li><span class="text-bold color-dark-red">batchSize</span> - batch size for UPDATE or INSERT queries</li>
<li><span class="text-bold color-dark-red">returnType</span> - special SQL type for declaring return type in store procedure </li>
<li><span class="text-bold color-dark-red">orm</span> - class of entity like Client.class, Car.class and so on. In most cases not need to declare because framework can be resolved it automatically</li>
</ul>
<p>Two thing are important keep in mind. The first is that short style is good. The second is that not all thing are posible to do automatically.
And second is problem. To undestanding this collision look at example below</p>
<pre><code class="java">
public interface IClientDao {
@TargetQuery("SELECT id, name, state FROM clients")
List<Client> loadAllClients();
} </code></pre>
<p>Yes, it's very compact. But how RefOrms can undestand what is entity type Client corresponds to the type selected? We all know that java don't keep
generic type and Client type will not be available, isn't it? And yes and no. If you recall the idea of
<a href="#BoilerPlateFree">'free from boiler plate code'</a> the next code will redundant but more corrected:</p>
<pre><code class="java">
public interface IClientRedundantDao {
@TargetQuery(query = "SELECT id, name, state FROM clients",
orm = Client.class)
List<Client> loadAllClients();
} </code></pre>
<p>In continue of this think first example and second are differing with 28 symbols ('query = ', ',\n' and 'orm = Client.class').
But the real danger is that you can write next code:</p>
<pre><code class="java">
public interface IClientRedundantDao {
@TargetQuery(query = "SELECT id, name, state FROM clients",
orm = Car.class)
List<Client> loadAllClients();
} </code></pre>
<p><span class="color-jclass">orm = </span><span class="text-bold color-dark-red">Car.class</span> instead of
<span class="color-jclass">orm = </span><span class="text-bold color-dark-red">Client.class</span> and runtime exception will occurring.
So, short style less error-prone than full style. But we did not finish with think about generic type in java and RefOrms framework.
<span id="Magic">So, some magic and sorcery help us to solve this problem. How? It's our beta secret. Don't worry, you have accessing to all code on github.</span>
</p>
<h2 id="TargetFilter">@TargetFilter</h2>
<p><span class="text-bold color-dark-red">@TargetFilter</span> using for associates a parameter with named filter in SQL query expression. It contains next properties:</p>
<ul>
<li><span class="text-bold color-dark-red">value</span> - filter name</li>
<li><span class="text-bold color-dark-red">columnFilter</span> - using for filtering selected columns in SQL query expresion. Advanced mode. More details in text below</li>
</ul>
<p>TargetFilter supports three types of params:</p>
<ul>
<li>Based on simple filter value with type like <span class="color-jclass">int.clas, String.class, Date.class</span> and so on</li>
<li>Based on Bean object</li>
<li>Based on java.util.Map key-value</li>
</ul>
<p>Let's look at an example with simple filter values:</p>
<pre><code class="java">
public interface IClientFilterParamsDao {
// Example: N1
@TargetQuery("SELECT id, name, state " +
"FROM clients " +
"WHERE name = :name AND state = :state")
Client filterClientByIdShort(String name, ClientState state);
// Example: N2
@TargetQuery("SELECT id, name, state " +
"FROM clients " +
"WHERE name = :name AND state = :state")
Client filterClientByIdShort(@TargetFilter("name") String name,
@TargetFilter("state") ClientState state);
}
</code></pre>
<p>Examples with number 1 and 2 are the same and both work. But second has explicit filter names like name and state.
It does not have any rules. It is more dependence on task. If you have 1 or 2 parameter to filtering data you can ignore <span class="color-jclass">TargetFilter</span> annotation.
If you have more than 2 parameters it is better using explicit filter name. But you needed keep in mind that if you don't using <span class="color-jclass">TargetFilter</span> annotation,
parameters ordering are important. In exmaple N1 the first sql filter link with first method parameter, the second sql filter with second and so on.
It is not bad if you choose your own rule to solve be or not to be <span class="color-jclass">TargetFilter</span> annotation in code.</p>
<p>Let's look at an example with Bean object:</p>
<pre><code class="java">
public interface IClientFilterParamsDao {
// Example: N3
@TargetQuery("SELECT id, name, state " +
"FROM clients " +
"WHERE name LIKE :name AND " +
" state = :state AND id <> :id")
List<Client> filterClients(@TargetFilter ClientFilter filter);
static class ClientFilter {
private final String name;
private final ClientState state;
public ClientFilter(String likeName, ClientState state) {
this.name = likeName;
this.state = state;
}
public long getId() {
return 0L;
}
}
}
</code></pre>
<p>Example N3 is easy to undestand by yourself. But some details are important.
At first, annotation <span class="color-jclass">TargetFilter</span> is required (perhaps, that fact will be changed in future
to simplify coding and correspond base idea of <a href="#BoilerPlateFree">'free from boiler plate code'</a>).
At second, bean inside bean is available. For example, <span class="color-jclass">:address.zipCode</span> filter is similar <span class="color-jclass">filter.getAddress().getZipCode()</span>.
At third, access by method has higher priority than access by field. There are some more rules but wich we'll omit for simplicity.
</p>
<p>Filters in RefOrms take central place and it is one of the reasons why RefOrms should be used. We'll discuss in more details in next chapter step by step.</p>
<h2 id="TargetDao">@TargetDao</h2>
<p><span class="text-bold color-dark-red">@TargetDao</span> using for set marker on Dao class. It contains next properties:</p>
<ul>
<li><span class="text-bold color-dark-red">name</span> - description of DAO class like java-doc</li>
<li><span class="text-bold color-dark-red">orm</span> - entity type by default for result of SQL query expression</li>
<li><span class="text-bold color-dark-red">value</span> - entity type for short style, if nothing except entity type</li>
</ul>
<p>Annotation <span class="color-jclass">TargetDao</span> is not necessary at all. It's using as marker for Dao layer. See example below<p>
<pre><code class="java">
@TargetDao(name = "It's dao for client. Table: clients", orm = Client.class)
public interface IClientDao {
// Any methods with client here...
}
</code></pre>
<p>But secrets here exist. At first, you can specify entity type in orm attribute. It help RefOrms with <a href="#Magic">magic</a>.
At second, set marker with text is cool for code reader. At third, it possible to make automate test for all DAO classes</p>
<h2 id="TargetMethod">@TargetMethod</h2>
<p>Annotation <span class="color-jclass">TargetMethod</span> is using in YourEnum class. See example below
<pre><code class="java">
public enum ClientState {
ACTIVE(1),
BLOCKED(2),
DELETED(3);
private int state;
ClientState(int state) {
this.state = state;
}
// convert enum to int value
@TargetMethod
public int getState() {
return state;
}
// convert int value to enum
@TargetMethod
public static ClientState valueFor(int code) {
return code == 1 ? ACTIVE : code == 2 ? BLOCKED : DELETED;
}
}
</code></pre>
<p>Here 2 method are annotated with <span class="color-jclass">TargetMethod</span>.
Both are needed to establish a correspondence between Enum instance and column value. So it's like converter in two way: from and to.
To date, there is no need to use it at all. For more detail see <a href="#TargetField"><span class="color-jclass">TargetField</span></a>.
It's my mistake in code design.
</p>
<h2 id="TargetField">@TargetField</h2>
<p>Annotation <span class="color-jclass">TargetField</span> is using in YourEnum class. See example below
<pre><code class="java">
public enum ClientState {
ACTIVE(1),
BLOCKED(2),
DELETED(3);
@TargetField
private int state;
ClientState(int state) {
this.state = state;
}
public int getState() {
return state;
}
}
</code></pre>
<p>It is needed to establish a correspondence between Enum instance and column value.
<span class="color-jclass">TargetField</span> is necessary to use if you want use enum instance as filter value for SQL query or
get it as result or part of result of SQL select expression.
To date, RefOrms have some logic to automate detection a correspondence between Enum instance and column value.
In example above, if remove annotation <span class="color-jclass">TargetField</span> from state field it will work fine too.
Next rule is important to know if you decide to escape <span class="color-jclass">TargetField</span> annotation:
first param with unique type in constructor will use to establish a correspondence between Enum instance and column value.
Otherwise it's strongly recommended to use <span class="color-jclass">TargetField</span> annotation on main field.
If no annotaion will present in enum class and no field will present in enum class a correspondence between Enum instance and column value will occur by enum instance name.
</p>
<h2 id="TargetConstructor">@TargetConstructor</h2>
<p><span class="text-bold color-dark-red">@TargetConstructor</span> using for selecting constructor to be using for create entity instance.
See example below for undestanding</p>
<pre><code class="java">
public class Car {
private int number;
private String color;
public Car() {
this(0);
}
@TargetConstructor
public Car(int number) {
this(number, "white");
}
public Car(int number, String color) {
this.number = number;
this.color = color;
}
}
</code></pre>
<details>
<summary>
<span>Car DAO example</span>
</summary>
<pre><code class="java">
public interface ICarDao {
@TargetQuery("SELECT number, color " +
"FROM cars " +
"WHERE id = :id")
Car loadCar(int id);
}
</code></pre>
</details>
<p><span class="color-jclass">TargetConstructor</span> is need for your own control for the creation of an object inside RefOrms framework.
In the example above we have 3 constructor and only one will be using for creation Car object.
I believe that you will not need to use this opportunity at all. In the example above if we remove <span class="color-jclass">TargetConstructor</span>
annotation, nothing change. RefOrms automatically detect more suitable constructor. There are some rules for detection of constructor:</p>
<ul>
<li>Default constructor has max priority for using. If your entity class will have such constructor no problems will occur</li>
<li>Constructor with max parameters wich correspondence selected result has hight priority for using</li>
</ul>
<h1 id="SqlQueries">Sql Queries</h1>
<h2 id="SELECT">SELECT</h2>
<p>Запрос типа SELECT в большенстве проектов является центральным, важным и сложным. Запросы такого типа можно встретить на любой вкус и цвет.
Поэтому RefOrms уделяет особое внимание этому типу запроса. Результатом этого запроса могуть быть: список объектов заданного типа, отчет,
одиночная сущность, данные примитивного типа и многое другое.
</p>
<h3 id="ColumnsAndFields">Columns and fields</h3>
<p>Что нужно знать? Первое, это полный формат выбираемой колонки для RefOrms в SQL выражении:</p>
<p>
<span class="color-dark-green text-bold">columnName</span>
<span class="color-dark-red"> AS </span>
<span class="color-dark-blue">columnAlias</span>
<span class="text-bold">:</span>
<span class="color-dark-green text-bold">fieldName</span>
<ul>
<li><span class="color-dark-green text-bold">columnName</span> is column name or SQL selectable expression</li>
<li><span class="color-dark-blue">columnAlias</span> is alias for selectable expression. [optional]</li>
<li><span class="text-bold">:</span> is separator between alias and field name. [optional]</li>
<li><span class="color-dark-green text-bold">fieldName</span> is entity field name. [optional]</li>
</ul>
</p>
<p>Второе, это понять, как осуществляется связывание колонки в SQL выражении и поля в ORM объекте.
Третье, какие у Вас есть возможности для этого. Все. Начнем по порядку и покажем как осуществляется связывание на примере:</p>
<pre><code class="java">
public interface ISimpleClientDao {
/**
* CREATE TABLE clients (
* id bigint NOT NULL,
* name character varying(127) NOT NULL,
* state int NOT NULL);
*/
@TargetQuery("SELECT id, " + // link with field 'id'
" name, " + // link with field 'name'
" state " + // link with field 'state'
"FROM clients")
List<Client> allClients();
}
public class SimpleClient {
private long id;
private String name;
private ClientState state;
// get/set method omit for simplicity
}
</code></pre>
<p> В примере выше, связывание результата выборки осуществляется по названию колонки, т.е. для колонки с именем 'id'
ищется соответствующие поле с именем 'id', для колонки 'name' - поле 'name' в классе SimpleClient и т.д.
Это интуитивно понятно. Но что делать, если имя колонки не совпадает с именем поля класса? Давайте опять посмотрим пример:
</p>
<pre><code class="java">
public interface IClientOrgDao {
/**
* CREATE TABLE clients (
* id bigint NOT NULL,
* name character varying(127) NOT NULL,
* state int NOT NULL);
*/
@TargetQuery("SELECT id AS orgId, " + // link with field 'orgId'
" name AS orgName, " + // link with field 'orgName'
" state AS orgState " + // link with field 'orgState'
"FROM clients")
List<ClientOrg> allClientsOrg();
/** It's important. Output SQL: SELECT id, name, state FROM clients */
}
public class ClientOrg {
private long orgId;
private String orgName;
private ClientState orgState;
// get/set method omit for simplicity
}
</code></pre>
<p> Что изменилось? В SQL запросе добавилось 'AS clause' выражение для каждой колонки, чье наименование не совпадает с именем поля класса ClientOrg.
Здесь важно знать, что 'AS clause' выражение имеет наивысший приоритет при определении соответствия между колонкой и полем класса. Отдельно стоит
отметить, что результирующий SQL запрос будет изменен и из него будут вырезаны 'AS clause'. Эту особенность работы RefOrms нужно держать в голове.
Разумеется, что иногда нужно сохранить информацию о 'AS clause' в результирующем SQL запросе. Посмотрим на следующий пример:
</p>
<pre><code class="java">
public interface IClientOrgDao {
/**
* CREATE TABLE clients (
* id bigint NOT NULL,
* name character varying(127) NOT NULL,
* state int NOT NULL);
*/
@TargetQuery("SELECT id AS aId:orgId, " + // link with field 'orgId'
" name AS aOrgName:orgName, " + // link with field 'orgName'
" state AS aOrgState:orgState " + // link with field 'orgState'
"FROM clients")
List<ClientOrg> clientsOrg();
/** It's important. Output SQL:
* SELECT id AS aId, name AS aOrgName, state AS aOrgState FROM clients */
}
public class ClientOrg {
private long orgId;
private String orgName;
private ClientState orgState;
// get/set method omit for simplicity
}
</code></pre>
<p>Итого, в результирующий запрос поподут алиасы колонок <span class="color-jclass">aOrgId, aOrgName</span> and <span class="color-jclass">aOrgState</span></p>
<h3 id="ColumnFilters">Column filters</h3>
<p>Фильтрация выбираемых колонок задача редкая. С другой стороны может быть жизненно-необходимой для решения конкретной задачи, например,
для уменьшения количества отдаваемых колонок с сервера на клиент в клиент-серверном приложении. Конечная задача - уменьшить количество передаваеммых данных
с одной стороны и увеличить отзывчивотсть приложения - с другой. Но это одна из задач, в Вашем случае могут быть другие причины для фильтрации.
RefOrms предоставляет инструменты для этого. Существует 2 способа отфильтровать колонки: <span class="color-jclass">статический</span> фильтр
- через SQL выражение или <span class="color-jclass">динамический</span> через <span class="color-jclass">TargetFilter</span> в DAO методах и 2 типа фильтрации:
1 - <span class="color-jclass">присутствует</span> в выборке, но не участвует в меппинге объекта и
2 - <span class="color-jclass">отсутствует</span> в выборке и соответственно не участвует в меппинге. Рассмотрим каждую из возможностей более подробно.
</p>
<p><span class="text-bold">Статический фильтр.</span> Фильтрация конкретной колонки осуществляется в SQL выражении. Формат:
<p>
<span class="color-dark-green text-bold">columnName</span>
<span class="color-dark-red"> AS </span>
<span class="color-dark-blue">columnAlias</span>
<span class="text-bold">:</span>
<span class="text-bold">!</span>
<ul>
<li><span class="color-dark-green text-bold">columnName</span> is column name or SQL selectable expression</li>
<li><span class="color-dark-blue">columnAlias</span> is alias for selectable expression. [optional]</li>
<li><span class="text-bold">:</span> is separator between alias and marker. [optional]</li>
<li><span class="text-bold">!</span> is marker for column which does not have corresponding field inside entity object</li>
</ul>
</p>
<p>Простой пример демонстрирует эту возможность:
</p>
<pre><code class="java">
public interface IClientDao {
@TargetQuery("SELECT id," +
" name," +
" state ! " + // add '!' symbol,
"FROM clients")
List<Client> loadClients();
/** Output SQL: SELECT id, name, state FROM clients */
}
// No state field inside Client
public class Client {
private long id;
private String name;
// get/set method omit for simplicity
}
</code></pre>
<p>В примере выше мы добавили символ '!' напротив столбца <span class="color-jclass">state</span>, что означает, что для данного столбца отсутствует поле в классе Client.
Если добавить поле <span class="color-jclass">state</span> в класс Client и выполнить запрос, то это поле не будет участовать в меппинге
и получит значение <span class="color-jclass">null</span>. Может показаться, что это не очень полезная фитча, но это не так. Существуют запросы,
которые используют синтетические поля для упорядочивания результата (ORDER BY clause), но при этом которые не нужны в ORM объекте.
</p>
<p><span class="text-bold">Динамические фильтр.</span> Фильтрация колонок осуществляется в методах DAO класса. Давайте посмотрим полный пример,
чтобы понять с чем и как это едят :)
</p>
<pre><code class="java">
public interface IBigOrmDao {
@TargetQuery("SELECT field_name1, field_name2, field_name3, field_name4, field_name5, " +
"field_name6, field_name7, field_name8, field_name9, field_name10 " +
"FROM big_orms ")
BigOrm load(@TargetFilter(columnFilter = true) int[] keepFields);
}
public class BigOrm {
private String fieldName1;
private String fieldName2;
private String fieldName3;
private String fieldName4;
private String fieldName5;
private String fieldName6;
private String fieldName7;
private String fieldName8;
private String fieldName9;
private String fieldName10;
// get/set method omit for simplicity
}
</code></pre>
<!-- REMOVE after docs finish (footer) -->
<pre>
</pre>
</div>
</div>
</BODY>
</HTML>