Ik zou eigenlijk eens wat advies willen hebben ivm het mappen van 'value types' (components) & audit information.
Het is nl. zo dat iedere tabel in mijn database 'audit-columns' bevat. Per tabel heb ik dus zowiezo 4 columns (lastupdated, created, createdby, lastupdatedby).
Om deze columns op het juiste moment van informatie te voorzien, heb ik een AuditInterceptor geschreven. So far so good, dat werkt goed.
Echter, ik zit nu in deze situatie:
- Ik heb een class 'Chapter', en een Chapter kan namen hebben in verschillende talen. Dit resulteert in m'n databank dus in 2 tabellen: Chapter & ChapterName:
In mijn domain-model, heb ik 2 classes gemaakt: nl. Chapter & ChapterName. Een Chapter heeft een collectie van ChapterNames. Volgens mij moet die ChapterName als een 'value type' aanzien worden.
De classes zien er zo uit:
(AuditableEntity is een abstract base class die de audit-velden, een Id veld, & gethashcode / equals overrides voorziet.
De vraag is nu, hoe map ik dit het best voor NHibernate ?
Volgens mij moet ChapterName dus als een component gezien worden. Zoals je kan zien, heeft de ChapterName tabel echter ook een surrogate primary key. Daarom gebruik ik dus een id-bag om de mapping te doen.
Mijn mapping ziet er als volgt uit:
De vraag is nu, wat vind je hiervan ? Is dit OK ?
Een andere vraag is: hoe zorg ik ervoor dat de Auditinformatie mbt de ChapterNames ook 'gezet' wordt in m'n databank ?
Zoals ik al eerder vemeldde, heb ik een speciale interceptor geschreven die dit kan afhandelen, en dat ook goed doet. Echter, het ziet er naar uit dat NHibernate die interceptor enkel gebruikt voor 'entities', en niet voor components. Moet ik in dit geval dan afstappen van het 'point of view' dat chaptername een component is, en deze ook als een entity mappen (Dit wil dan zeggen dat vrijwel al mijn classes in mijn domain model entities moeten zijn)? Of zijn er andere oplossingen ?
Het is nl. zo dat iedere tabel in mijn database 'audit-columns' bevat. Per tabel heb ik dus zowiezo 4 columns (lastupdated, created, createdby, lastupdatedby).
Om deze columns op het juiste moment van informatie te voorzien, heb ik een AuditInterceptor geschreven. So far so good, dat werkt goed.
Echter, ik zit nu in deze situatie:
- Ik heb een class 'Chapter', en een Chapter kan namen hebben in verschillende talen. Dit resulteert in m'n databank dus in 2 tabellen: Chapter & ChapterName:
code:
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
| CREATE TABLE [dbo].[Chapter]( [ChapterId] [uniqueidentifier] NOT NULL, [ChapterCode] [varchar](25) NOT NULL, [CreationDate] [datetime] NOT NULL, [ModificationDate] [datetime] NOT NULL, [Version] [int] NOT NULL, [CreatedBy] [varchar](50) NOT NULL, [LastUpdatedBy] [varchar](50) NOT NULL, CONSTRAINT [PK_Chapter] PRIMARY KEY ( [ChapterId] ASC ) CREATE TABLE [dbo].[ChapterName]( [ChapterNameId] [uniqueidentifier] NOT NULL, [ChapterId] [uniqueidentifier] NOT NULL, [Name] [varchar](255) NOT NULL, [LanguageCode] [int] NOT NULL, [CreationDate] [datetime] NOT NULL, [ModificationDate] [datetime] NOT NULL, [Version] [int] NOT NULL, [CreatedBy] [varchar](50) NOT NULL, [LastUpdatedBy] [varchar](50) NOT NULL, CONSTRAINT [PK_ChapterName] PRIMARY KEY ( [ChapterNameId] ASC ) |
In mijn domain-model, heb ik 2 classes gemaakt: nl. Chapter & ChapterName. Een Chapter heeft een collectie van ChapterNames. Volgens mij moet die ChapterName als een 'value type' aanzien worden.
De classes zien er zo uit:
C#:
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
| public class Chapter : AuditableEntity<Guid> { public string ChapterCode { get; set; } private IList<ChapterName> _names = new List<ChapterName> (); public ReadOnlyCollection<ChapterName> Names { get { return new List<ChapterName> (_names).AsReadOnly (); } } public string GetChapterNameInLanguage( LanguageCode language ) { foreach( ChapterName name in _names ) { if( name.Language == language ) { return name.Name; } } return string.Empty; } } public class ChapterName : IAuditable { public LanguageCode Language { get; set; } public string Name { get; set; } public Chapter Chapter { get; internal set; } #region Equals / GetHashcode() public override bool Equals( object obj ) { ChapterName other = obj as ChapterName; if( other == null ) { return false; } return this.GetHashCode () == other.GetHashCode (); } public override int GetHashCode() { return ( "Language:" + Language + "|Name:" + Name ).GetHashCode (); } #endregion #region Auditable public DateTime Created { get; private set; } public string CreatedBy { get; private set; } public string CreatedByPropertyName { get { return "CreatedBy"; } } public string CreatedPropertyName { get { return "Created"; } } public string LastUpdatedBy { get; private set; } public string LastUpdatedByPropertyName { get { return "LastUpdatedBy"; } } void IAuditable.SetCreatedBy( string createdBy ) { CreatedBy = createdBy; } void IAuditable.SetCreationDate( DateTime created ) { Created = created; } void IAuditable.SetLastUpdatedBy( string lastUpdatedBy ) { LastUpdatedBy = lastUpdatedBy; } void IAuditable.SetUpdateDate( DateTime updated ) { Updated = updated; } public DateTime Updated { get; private set; } public string UpdatedPropertyName { get { return "Updated"; } } public int Version { get; private set; } #endregion } |
(AuditableEntity is een abstract base class die de audit-velden, een Id veld, & gethashcode / equals overrides voorziet.
De vraag is nu, hoe map ik dit het best voor NHibernate ?
Volgens mij moet ChapterName dus als een component gezien worden. Zoals je kan zien, heeft de ChapterName tabel echter ook een surrogate primary key. Daarom gebruik ik dus een id-bag om de mapping te doen.
Mijn mapping ziet er als volgt uit:
code:
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
| <class name="Chapter" table="Chapter" lazy="false"> <id name="Id" column="ChapterId"> <generator class="guid.comb" /> </id> <version name="Version" column="Version" /> <property name="ChapterCode" column="ChapterCode" /> <idbag name="Names" access="field.camelcase-underscore" lazy="false" table="ChapterName"> <collection-id column="ChapterNameId" type="guid"> <generator class="guid.comb" /> </collection-id> <key column="ChapterId" /> <composite-element class="ChapterName"> <parent name="Chapter" /> <property name="Language" column="LanguageCode" /> <property name="Name" column="Name"/> <property name="Created" column="CreationDate" /> <property name="Updated" column="ModificationDate" /> <property name="CreatedBy" column="CreatedBy" /> <property name="LastUpdatedBy" column="LastUpdatedBy" /> </composite-element> </idbag> <property name="Created" column="CreationDate" /> <property name="Updated" column="ModificationDate" /> <property name="CreatedBy" column="CreatedBy" /> <property name="LastUpdatedBy" column="LastUpdatedBy" /> </class> |
De vraag is nu, wat vind je hiervan ? Is dit OK ?
Een andere vraag is: hoe zorg ik ervoor dat de Auditinformatie mbt de ChapterNames ook 'gezet' wordt in m'n databank ?
Zoals ik al eerder vemeldde, heb ik een speciale interceptor geschreven die dit kan afhandelen, en dat ook goed doet. Echter, het ziet er naar uit dat NHibernate die interceptor enkel gebruikt voor 'entities', en niet voor components. Moet ik in dit geval dan afstappen van het 'point of view' dat chaptername een component is, en deze ook als een entity mappen (Dit wil dan zeggen dat vrijwel al mijn classes in mijn domain model entities moeten zijn)? Of zijn er andere oplossingen ?
https://fgheysels.github.io/