You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Jan 27, 2022. It is now read-only.
A facade library useful for [Entity](https://github.com/wintoncode/Winton.DomainModelling.Abstractions#entity) operations in DocumentDb (SQL API).
8
+
A facade library useful for [Entity](https://github.com/wintoncode/Winton.DomainModelling.Abstractions#entity) and Value Object operations in DocumentDb (SQL API).
9
+
10
+
This implementations allow multiple types to be transparently stored in one collection using 'wrapper' documents with type discriminators and namespaced IDs (for entities). It can be tempting for those from a traditional SQL background to provision a separate collection per type. However, this is often unnecessarily expensive, especially if much of the reserved throughput for a given collection is unused. Taking advantage of the "schemaless" nature of a document store, such as DocumentDb, can both reduce cost and simplify infrastructural complexity. This implementation provides an easy way to work with a single collection within a bounded context (within which persisted type names are unique) while outwardly still achieving the desired level of strong typing. There really is a schema, but the database doesn't need to know about it.
9
11
10
12
## Types
11
13
12
14
### IEntityFacade
13
15
14
-
An abstraction layer over [Entity](https://github.com/wintoncode/Winton.DomainModelling.Abstractions#entity) CRUD operations in DocumentDb. Provides strong typed Create, Read (including Query), **Upsert**, and Delete methods.
16
+
An abstraction layer over [Entity](https://github.com/wintoncode/Winton.DomainModelling.Abstractions#entity) CRUD operations in DocumentDb. Provides strong typed Create, Read, **Upsert**, Delete, and Query methods.
15
17
16
18
### EntityFacade
17
19
18
20
The default implementation of `IEntityFacade`. The Create method supports automatic ID generation for string-serializable ID types, otherwise IDs must be set before creating.
19
21
20
-
This implementation allows multiple entity types to be transparently stored in one collection (using a 'wrapper' document with a type discriminator and namespaced ID). It can be tempting for those from a traditional SQL background to provision a separate collection per entity type. However, this is often unnecessarily expensive, especially if much of the reserved throughput for a given collection is unused. Taking advantage of the "schemaless" nature of a document store, such as DocumentDb, can both reduce cost and simplify infrastructural complexity. This implementation provides an easy way to work with a single collection within a bounded context (within which entity type names are unique) while outwardly still achieving the desired level of strong typing. There really is a schema, but the database doesn't need to know about it.
22
+
Note that this implementation is currently **incompatible with partitioned collections**. This restriction could potentially be lifted in a future version, at the expense of implementation complexity (and probably a leakier abstraction). However, for applications requiring large collections, where partitioning is actually needed, the conveniences provided by this facade are unlikely to be suitable anyway.
23
+
24
+
### IValueObjectFacade
25
+
26
+
An abstraction layer over Value Object operations in DocumentDb. Provides strong typed Create, Delete, and Query methods.
27
+
28
+
### ValueObjectFacade
29
+
30
+
The default implementation of `IValueObjectFacade`.
21
31
22
32
Note that this implementation is currently **incompatible with partitioned collections**. This restriction could potentially be lifted in a future version, at the expense of implementation complexity (and probably a leakier abstraction). However, for applications requiring large collections, where partitioning is actually needed, the conveniences provided by this facade are unlikely to be suitable anyway.
23
33
24
34
## Usage
25
35
26
-
The constructor for `EntityFacade`takes a [Database](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.database), a [DocumentCollection](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.documentcollection), and an [IDocumentClient](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.idocumentclient). Of course, resolving all dependencies from a DI container is preferred, but for clarity an `EntityFacade` can be manually constructed as
36
+
The constructors for both `EntityFacade`and `ValueObjectFacade` take a [Database](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.database), a [DocumentCollection](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.documentcollection), and an [IDocumentClient](https://docs.microsoft.com/en-us/dotnet/api/microsoft.azure.documents.idocumentclient). Of course, resolving all dependencies from a DI container is preferred, but for clarity they can be manually constructed as
Consider some application with an "Accounting" domain containing 2 entity types, `Account` and `Transaction`, each with a [strong typed](https://tech.winton.com/2017/06/strong-typing-a-pattern-for-more-robust-code/) ID. Note that both ID types use [SingleValueConverter](https://github.com/wintoncode/Winton.Extensions.Serialization.Json#singlevalueconverter), so they are string-serializable.
47
+
Consider some application with an "Accounting" domain containing 2 entity types, `Account` and `Transaction`, each with a [strong typed](https://tech.winton.com/2017/06/strong-typing-a-pattern-for-more-robust-code/) ID. Note that both ID types use [SingleValueConverter](https://github.com/wintoncode/Winton.Extensions.Serialization.Json#singlevalueconverter), so they are string-serializable. The "Accounting" domain also contains a value object type, `AccountType`, used as reference data.
38
48
39
49
```csharp
40
50
[JsonConverter(typeof(SingleValueConverter))]
@@ -47,15 +57,15 @@ public sealed class Account : Entity<AccountId>
47
57
{
48
58
publicAccount(
49
59
AccountIdid,
50
-
AccountNamename,
60
+
AccountTypetype,
51
61
...)
52
62
: base(id)
53
63
{
54
-
Name=name;
64
+
Type=type;
55
65
...
56
66
}
57
67
58
-
publicAccountNameName { get; }
68
+
publicAccountTypeType { get; }
59
69
60
70
...
61
71
}
@@ -86,6 +96,27 @@ public sealed class Transaction : Entity<TransactionId>
86
96
87
97
...
88
98
}
99
+
100
+
publicstructAccountType : IEquatable<AccountType>
101
+
{
102
+
[JsonConstructor]
103
+
publicAccountType(
104
+
stringname,
105
+
decimalrate,
106
+
...)
107
+
: base(id)
108
+
{
109
+
Name=name;
110
+
Rate=rate;
111
+
...
112
+
}
113
+
114
+
publicstringName { get; }
115
+
116
+
publicdecimalRate { get; }
117
+
118
+
...
119
+
}
89
120
```
90
121
91
122
These types could each have their own repository interfaces, defined within the "Accounting" domain.
@@ -108,9 +139,18 @@ public interface ITransactionRepository
108
139
109
140
...
110
141
}
142
+
143
+
publicinterfaceIAccountTypeRepository
144
+
{
145
+
TaskCreate(AccountTypeaccountType);
146
+
147
+
IEnumerable<AccountType> GetAll();
148
+
149
+
...
150
+
}
111
151
```
112
152
113
-
The respective implementations of these repositories, potentially defined in a separate "Persistence" layer, would simply be thin wrappers around the `IEntityFacade`.
153
+
The respective implementations of these repositories, potentially defined in a separate "Persistence" layer, would simply be thin wrappers around the `IEntityFacade` or `IValueObjectFacade`.
These repositories will store their respective entities in a single shared collection, using the entity type names to namespace the IDs and discriminate between each type. Therefore, these names should be considered part of the document schema, and would therefore require a data migration if they were changed as part of a domain refactoring.
226
+
These repositories will store their respective types in a single shared collection, using the type names to discriminate between each type and namespace the IDs (for entities). Therefore, these names should be considered part of the document schema, and would require a data migration if they were changed as part of a domain refactoring.
0 commit comments