1 #Region "Microsoft.VisualBasic::9e7f515b80a02b0b1bc642658705dc0a, Microsoft.VisualBasic.Core\ComponentModel\DataSource\Repository\Repository.vb"
2
3     ' Author:
4     
5     '       asuka (amethyst.asuka@gcmodeller.org)
6     '       xie (genetics@smrucc.org)
7     '       xieguigang (xie.guigang@live.com)
8     
9     ' Copyright (c) 2018 GPL3 Licensed
10     
11     
12     ' GNU GENERAL PUBLIC LICENSE (GPL3)
13     
14     
15     ' This program is free software: you can redistribute it and/or modify
16     ' it under the terms of the GNU General Public License as published by
17     ' the Free Software Foundation, either version 3 of the License, or
18     ' (at your option) any later version.
19     
20     ' This program is distributed in the hope that it will be useful,
21     ' but WITHOUT ANY WARRANTY; without even the implied warranty of
22     ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23     ' GNU General Public License for more details.
24     
25     ' You should have received a copy of the GNU General Public License
26     ' along with this program. If not, see <http://www.gnu.org/licenses/>.
27
28
29
30     ' /********************************************************************************/
31
32     ' Summaries:
33
34     '     Interface IKeyedEntity
35     
36     '         Properties: Key
37     
38     '     Class ClientRecord
39     
40     '         Properties: ClientUniqueKey, Code
41     
42     '     Interface IRepositoryRead
43     
44     '         Function: Exists, GetAll, GetByKey, GetWhere
45     
46     '     Interface IRepositoryWrite
47     
48     '         Function: AddNew
49     
50     '         Sub: AddOrUpdate, Delete
51     
52     '     Interface IRepository
53     
54     
55     
56     '     Interface IClientRepository
57     
58     
59     
60     '     Class RepositoryReadException
61     
62     '         Properties: Fatal
63     
64     '         Constructor: (+2 OverloadsSub New
65     
66     
67     ' /********************************************************************************/
68
69 #End Region
70
71 Namespace ComponentModel.DataSourceModel.Repository
72
73     ' http://www.codeproject.com/Reference/731015/The-repository-pattern-in-VB-Net
74
75     ' The repository pattern (in VB.Net)
76
77     ' Background
78     ' The repository pattern Is a method To introduce a shearing layer between your business objects And
79     ' the data access/persistence technology you are Using And this especially useful In unit testing As
80     ' the alternative(mocking an entire data access library) can be quite heart breaking.
81
82     ' Motivation
83     ' The repository pattern introduces the following advantages over the traditional three-tier architecture over an ORM:
84
85     ' 1. The classes persisted by an ORM (Entity framework Or the Like) need To have a good deal Of information about how they are stored.
86     '    This Is Not ideal because When you make a change To the underlying storage you would need To change the business objects As well.
87     ' 2. Not all persistence Is in the form of a relational database - the repository can be backed by a blended storage made of files,
88     '    database tables And NoSQL records As well.
89     ' 3. Some fields exist only In order To allow navigation To a record Or To identify child records - these fields should Not
90     '    be passed up into the business layer If they have no business meaning.
91
92     ''' <summary>
93     ''' Interface defining any item we can store in a repository and can identify by
94     ''' an unique key
95     ''' </summary>
96     ''' <remarks>
97     ''' This interface is typed so we can make type-safe code for retrieving the entity
98     ''' (don't pass in an integer if the entity is keyed by string etc.)
99     ''' </remarks>
100     Public Interface IKeyedEntity(Of TKeyType)
101
102         ''' <summary>
103         ''' Get the key to find the entity by
104         ''' </summary>
105         Property Key As TKeyType
106
107     End Interface
108
109     ''' <summary>
110     ''' Record for storing a client record in the common database
111     ''' </summary>
112     Public NotInheritable Class ClientRecord
113         Implements IKeyedEntity(Of Integer)
114
115         ''' <summary>
116         ''' The unique number by which we know this client
117         ''' </summary>
118         ''' <remarks>
119         ''' Every client has an unique id but this is not needed publically
120         ''' </remarks>
121         Public Property ClientUniqueKey As Integer Implements IKeyedEntity(Of Integer).Key
122
123         ' Other non-key properties can go here
124         ''' <summary>
125         ''' The short code for the client
126         ''' </summary>
127         ''' <remarks>
128         ''' e.g. MCL for Merrion Computing Ltd etc.
129         ''' </remarks>
130         Public Property Code As String
131     End Class
132
133     ''' <summary>
134     ''' Interface to support reading entities from the backing store
135     ''' </summary>
136     ''' <typeparam name="TEntity">
137     ''' The key-identified type of entity we are reading
138     ''' </typeparam>
139     ''' <typeparam name="TKey">
140     ''' The type of the key
141     ''' </typeparam>
142     ''' <remarks>
143     ''' In this architecture there is a seperate read and write interface but often this
144     ''' pattern has just the one interface for both functions
145     ''' </remarks>
146     Public Interface IRepositoryRead(Of TKey, TEntity As IKeyedEntity(Of TKey))
147
148         ''' <summary>
149         ''' Does a record exist in the repository identified by this key
150         ''' </summary>
151         ''' <param name="key">
152         ''' The unique identifier of the entity we are looking for
153         ''' </param>
154         Function Exists(key As TKey) As Boolean
155
156         ''' <summary>
157         ''' Get the entity uniquely identified by the given key
158         ''' </summary>
159         ''' <param name="key">
160         ''' The unique identifier to use to get the entity
161         ''' </param>
162         Function GetByKey(key As TKey) As TEntity
163
164         ''' <summary>
165         ''' Get a set of entities from the repository that match the where clause
166         ''' </summary>
167         ''' <param name="clause">
168         ''' A function to apply to filter the results from the repository
169         ''' </param>
170         Function GetWhere(clause As Func(Of TEntity, Boolean)) As IReadOnlyDictionary(Of TKey, TEntity)
171
172         ''' <summary>
173         ''' Get all of this type of thing from the repository
174         ''' </summary>
175         ''' <remarks>
176         ''' returns an IQueryable so this request can be filtered further
177         ''' </remarks>
178         Function GetAll() As IReadOnlyDictionary(Of TKey, TEntity)
179
180     End Interface
181
182     ''' <summary>
183     ''' Interface to support writing (and deletes) to a typed repository
184     ''' </summary>
185     ''' <typeparam name="TEntity">
186     ''' The type of entity in the repository
187     ''' </typeparam>
188     ''' <typeparam name="TKey">
189     ''' The type of the key to uniquely identify the entity
190     ''' </typeparam>
191     ''' <remarks>
192     ''' In this architecture there is a seperate read and write interface but often this
193     ''' pattern has just the one interface for both functions
194     ''' </remarks>
195     Public Interface IRepositoryWrite(Of TKey, TEntity As IKeyedEntity(Of TKey))
196
197         ''' <summary>
198         ''' Delete the entity uniquely identified by this key
199         ''' </summary>
200         ''' <param name="key">
201         ''' The unique identifier of the record to delete
202         ''' </param>
203         Sub Delete(key As TKey)
204
205         ''' <summary>
206         ''' Add or update the entity
207         ''' </summary>
208         ''' <param name="entity">
209         ''' The record to add or update on the repository
210         ''' </param>
211         ''' <param name="key" >
212         ''' The key that uniquely identifies the record to add or update
213         ''' </param>
214         Sub AddOrUpdate(entity As TEntity, key As TKey)
215
216         ''' <summary>
217         ''' Adds an entity that we know to be new and returns its assigned key
218         ''' </summary>
219         ''' <param name="entity">
220         ''' The entity we are adding to the repository
221         ''' </param>
222         ''' <returns>
223         ''' The unique identifier for the entity
224         ''' </returns>
225         ''' <remarks>
226         ''' This is useful if the unique identifier is not an intrinsic property of
227         ''' the entity - for example if it is a memory address or a GUID
228         ''' </remarks>
229         Function AddNew(entity As TEntity) As TKey
230
231     End Interface
232
233     ''' <summary>
234     ''' Read/write repository of typed entites
235     ''' </summary>
236     ''' <typeparam name="TKey">
237     ''' The type by which the entity is uniquely identified
238     ''' </typeparam>
239     ''' <typeparam name="TEntity">
240     ''' The type of entity in the repository
241     ''' </typeparam>
242     Public Interface IRepository(Of TKey, TEntity As IKeyedEntity(Of TKey))
243         Inherits IRepositoryRead(Of TKey, TEntity)
244         Inherits IRepositoryWrite(Of TKey, TEntity)
245
246     End Interface
247
248     Public Interface IClientRepository
249         Inherits IRepository(Of Integer, ClientRecord)
250
251     End Interface
252
253     ''' <summary>
254     ''' An exception that occured when reading from the repository backing store
255     ''' </summary>
256     ''' <remarks>
257     ''' The inner exception is from whatever
258     ''' </remarks>
259     Public Class RepositoryReadException
260         Inherits Exception
261
262         Public ReadOnly Property Fatal As Boolean
263
264         Public Sub New(message As String, innerExcption As Exception, fatalInit As Boolean)
265             MyBase.New(message, innerExcption)
266             Fatal = fatalInit
267         End Sub
268
269         Public Sub New(message As String, fatalInit As Boolean)
270             MyBase.New(message)
271             Fatal = fatalInit
272         End Sub
273     End Class
274 End Namespace