Below you’ll find a full (albeit simple) CRUD client for two tables, chinook.artist and chinook.album, with a master detail relationship.
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
package is.codion.demos.chinook.tutorial;
import is.codion.common.db.database.Database;
import is.codion.framework.db.EntityConnectionProvider;
import is.codion.framework.db.local.LocalEntityConnectionProvider;
import is.codion.framework.domain.DomainModel;
import is.codion.framework.domain.DomainType;
import is.codion.framework.domain.entity.EntityFormatter;
import is.codion.framework.domain.entity.EntityType;
import is.codion.framework.domain.entity.attribute.Column;
import is.codion.framework.domain.entity.attribute.ForeignKey;
import is.codion.plugin.flatlaf.intellij.themes.materialtheme.MaterialTheme;
import is.codion.swing.common.ui.component.table.FilterTable;
import is.codion.swing.framework.model.SwingEntityApplicationModel;
import is.codion.swing.framework.model.SwingEntityEditModel;
import is.codion.swing.framework.model.SwingEntityModel;
import is.codion.swing.framework.ui.EntityApplication;
import is.codion.swing.framework.ui.EntityApplicationPanel;
import is.codion.swing.framework.ui.EntityEditPanel;
import is.codion.swing.framework.ui.EntityPanel;
import javax.swing.JTable;
import java.util.List;
import static is.codion.demos.chinook.tutorial.ClientTutorial.Chinook.Album;
import static is.codion.demos.chinook.tutorial.ClientTutorial.Chinook.Artist;
import static is.codion.framework.domain.DomainType.domainType;
import static is.codion.framework.domain.entity.attribute.Column.Generator.automatic;
import static is.codion.swing.common.ui.layout.Layouts.gridLayout;
import static is.codion.swing.framework.ui.EntityEditPanel.ControlKeys.INSERT;
import static java.util.Collections.emptyList;
/**
* When running this make sure the chinook demo module directory is the
* working directory, due to a relative path to a db init script
*/
public final class ClientTutorial {
public static final class Chinook extends DomainModel {
static final DomainType DOMAIN = domainType(Chinook.class);
public interface Artist {
EntityType TYPE = DOMAIN.entityType("chinook.artist");
Column<Integer> ID = TYPE.integerColumn("artistid");
Column<String> NAME = TYPE.stringColumn("name");
Column<Integer> NUMBER_OF_ALBUMS = TYPE.integerColumn("number_of_albums");
}
public interface Album {
EntityType TYPE = DOMAIN.entityType("chinook.album");
Column<Integer> ID = TYPE.integerColumn("albumid");
Column<String> TITLE = TYPE.stringColumn("title");
Column<Integer> ARTIST_ID = TYPE.integerColumn("artistid");
ForeignKey ARTIST_FK = TYPE.foreignKey("artist_fk", ARTIST_ID, Artist.ID);
}
public Chinook() {
super(DOMAIN);
add(Artist.TYPE.as(
Artist.ID.as()
.primaryKey()
.generator(automatic("chinook.artist")),
Artist.NAME.as()
.column()
.caption("Name")
.searchable(true)
.nullable(false)
.maximumLength(120),
Artist.NUMBER_OF_ALBUMS.as()
.subquery("""
SELECT COUNT(*)
FROM chinook.album
WHERE album.artistid = artist.artistid""")
.caption("Albums"))
.formatter(Artist.NAME)
.caption("Artists")
.build());
add(Album.TYPE.as(
Album.ID.as()
.primaryKey()
.generator(automatic("chinook.artist")),
Album.ARTIST_ID.as()
.column()
.nullable(false),
Album.ARTIST_FK.as()
.foreignKey()
.caption("Artist"),
Album.TITLE.as()
.column()
.caption("Title")
.nullable(false)
.maximumLength(160))
.formatter(EntityFormatter.builder()
.value(Album.ARTIST_FK)
.text(" - ")
.value(Album.TITLE)
.build())
.caption("Albums")
.build());
}
}
private static final class ArtistEditPanel extends EntityEditPanel {
private ArtistEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
createTextField(Artist.NAME)
.columns(15);
addInputPanel(Artist.NAME);
}
}
private static final class AlbumEditPanel extends EntityEditPanel {
private AlbumEditPanel(SwingEntityEditModel editModel) {
super(editModel);
}
@Override
protected void initializeUI() {
createSearchField(Album.ARTIST_FK)
.columns(15);
createTextField(Album.TITLE)
.action(control(INSERT).get())
.columns(15);
setLayout(gridLayout(2, 1));
addInputPanel(Album.ARTIST_FK);
addInputPanel(Album.TITLE);
}
}
private static final class ApplicationModel extends SwingEntityApplicationModel {
private ApplicationModel(EntityConnectionProvider connectionProvider) {
super(connectionProvider, List.of(createArtistModel(connectionProvider)));
}
private static SwingEntityModel createArtistModel(EntityConnectionProvider connectionProvider) {
SwingEntityModel artistModel = new SwingEntityModel(Artist.TYPE, connectionProvider);
SwingEntityModel albumModel = new SwingEntityModel(Album.TYPE, connectionProvider);
artistModel.detailModels().add(albumModel);
artistModel.tableModel().items().refresh();
return artistModel;
}
}
private static final class ApplicationPanel extends EntityApplicationPanel<ApplicationModel> {
private ApplicationPanel(ApplicationModel applicationModel) {
super(applicationModel, createPanels(applicationModel), emptyList());
}
private static List<EntityPanel> createPanels(ApplicationModel applicationModel) {
SwingEntityModel artistModel = applicationModel.entityModels().get(Artist.TYPE);
SwingEntityModel albumModel = artistModel.detailModels().get(Album.TYPE);
EntityPanel artistPanel = new EntityPanel(artistModel, new ArtistEditPanel(artistModel.editModel()));
EntityPanel albumPanel = new EntityPanel(albumModel, new AlbumEditPanel(albumModel.editModel()));
artistPanel.detailPanels().add(albumPanel);
return List.of(artistPanel);
}
}
public static void main(String[] args) {
Database.URL.set("jdbc:h2:mem:h2db");
Database.INIT_SCRIPTS.set("src/main/sql/create_schema.sql");
EntityPanel.Config.TOOLBAR_CONTROLS.set(true);
FilterTable.AUTO_RESIZE_MODE.set(JTable.AUTO_RESIZE_ALL_COLUMNS);
EntityApplication.builder(ApplicationModel.class, ApplicationPanel.class)
.domain(Chinook.DOMAIN)
.model(ApplicationModel::new)
.panel(ApplicationPanel::new)
.connectionProvider(LocalEntityConnectionProvider.builder()
.domain(new Chinook())
.build())
.defaultLookAndFeel(MaterialTheme.class)
.name("Artists and Albums")
.start();
}
}