Revision and grammar fix

pull/14878/head
Galip Tolga Erdem 3 years ago
parent 9bfea9c0e8
commit 39839ad5df

@ -1,6 +1,6 @@
# Value generation for DDD guarded types with Entity Framework Core 7.0
In domain-driven design (DDD), *guarded keys* can improve the type safety of key properties. This is achieved by wrapping the key type in another type which is specific to the use of the key. In this article, I will explain the cases why you may need to use use guarded types and discuss the advantages and limitations when implementing to an ABP application.
In domain-driven design (DDD), *guarded keys* can improve the type safety of key properties. This is achieved by wrapping the key type in another type which is specific to the use of the key. In this article, I will explain the cases why you may need to use guarded types and discuss the advantages and limitations when implementing to an ABP application.
> You can find the source code of the example application [here](https://github.com/abpframework/abp-samples/tree/master/EfCoreGuardedTypeDemo).
@ -30,14 +30,16 @@ public class ProductAppService : MyProductStoreAppService, IProductAppService
}
````
While the sample demonstrates a very simple mistake, whilst the business logic get more complex, it is easier to come across mistakes similar to this one. The next section offers using guarded types to prevent these kind of problems as a solution to the problem.
While the sample demonstrates a very simple mistake, it is easier to come across similar mistakes when the business logic gets more complex especially when you are using methods with **multiple foreign key arguments**. The next section offers using guarded types to prevent these kind of problems as a solution to the problem.
## The Solution
With EFCore7, key properties can be guarded with type safety. To use that, update your aggreagate root or entity unique identifier with a complex object.
Strongly-typed IDs (*guarded keys*) is a DDD approach to address this problem. One of the main problems with .NET users was handling the persisting these objects. With EFCore7, key properties can be guarded with type safety seamlessly.
To use guarded keys, update your aggregate root or entity unique identifier with a complex type to overcome *primitive obsession*:
````csharp
public struct CategoryId
public readonly struct CategoryId
{
public CategoryId(Guid value) => Value = value;
public Guid Value { get; }
@ -50,8 +52,6 @@ public readonly struct ProductId
}
````
> It is worth considering as with many [Domain-Driven Design](https://docs.abp.io/en/abp/latest/Domain-Driven-Design) (DDD) concepts, this improved type safety comes with additional code complexity.
You can now use these keys for your aggregate roots or entities:
```csharp
@ -84,7 +84,9 @@ public class Category : AggregateRoot<CategoryId>
}
```
`ProductId` and `CategoryId` guarded key types shown in the sample use `Guid` key values, which means Guid values will be used in the mapped database tables. This is achieved by defining [value converters](https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions) for the types. Override the `ConfigureConventions` method of your DbContext to use the value converters:
`ProductId` and `CategoryId` guarded key types shown in the sample use `Guid` key values, which means Guid values will be used in the mapped database tables. This is achieved by defining [value converters](https://learn.microsoft.com/en-us/ef/core/modeling/value-conversions) for the types.
Override the `ConfigureConventions` method of your DbContext to use the value converters:
````csharp
protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
@ -133,15 +135,15 @@ public class ProductStoreDataSeedContributor : IDataSeedContributor, ITransientD
}
```
You can also use `integer` as guarded type for your key properties and use [Sequence-based key generation for SQL Server](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/whatsnew#sequence-based-key-generation-for-sql-server).
You can also use `integer` as guarded type for your key properties and use [Sequence-based key generation for SQL Server](https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-7.0/whatsnew#sequence-based-key-generation-for-sql-server) for value generation.
## Discussions
In this section, I will discuss the use cases of guarded types and limitations when implementing to an ABP application.
### Do I need guarded type key properties even if I follow DDD principles?
### Do I need to use guarded types?
While using strongly-typed key properties reduce the chance of unnoticed errors, admittedly it increases the code complexity by adding new types to your solution. If you are already following the best practices of [Domain-Driven Design](https://docs.abp.io/en/abp/latest/Domain-Driven-Design), you are aware that **updates** and **creations** of an aggregate are done **over** the aggregate root itself as a whole unit. And entity state changes of an aggregate root can be done using the [domain services](https://docs.abp.io/en/abp/latest/Domain-Services). Domain services should already validate the entity.
If you are already following the best practices of [Domain-Driven Design](https://docs.abp.io/en/abp/latest/Domain-Driven-Design), you are aware that **updates** and **creations** of an aggregate are done **over** the aggregate root itself as a whole unit. And entity state changes of an aggregate root should be done using the [domain services](https://docs.abp.io/en/abp/latest/Domain-Services). Domain services should already validate the entity.
**Example: Using domain service to update product:**
@ -166,7 +168,7 @@ public class ProductManager : DomainService
}
````
In this sample, domain service validates that both **product** and the **category** entities, passed by the application layer, are valid objects since they are not key properties. However, manual assignment is already in place and more complex the domain logic, higher to miss out mistakes.
In this sample, domain service validates that both **product** and the **category** entities, passed by the application layer, are valid objects since they are not key properties. However, manual assignment is already in place and more complex the domain logic, higher to miss out mistakes. At the end, it will depend on your tolerance level for developer errors comparing to the time you want to spend time on additional code base for guarded types.
### Limitations
@ -192,7 +194,9 @@ var newProduct = await _productRepository.InsertAsync(
In this article, I tried to explain DDD guarded types for key properties and value generation for these properties using Entity Framework 7.0 and ABP.
As in many DDD concepts and patterns, guarded types provides improved safety for your code base at the expense of additional code complexity. If you have a large team working on a large scale solution containing complex business logics where key assignments are abundant, I personally suggest using guarded types.
Using strongly-typed key properties reduce the chance of unnoticed errors. Admittedly it increases the code complexity by adding new types to your solution with extra coding, especially if you are using classes as keys. Guarded types provide improved safety for your code base at the expense of additional code complexity as in many DDD concepts and patterns.
If you have a large team working on a large scale solution containing complex business logics where key assignments are abundant or if you are using methods with multiple foreign key arguments, I personally suggest using guarded types.
## The Source Code

Loading…
Cancel
Save