Skip to content

Commit

Permalink
GITBOOK-2: Antonello's Oct 21 changes
Browse files Browse the repository at this point in the history
  • Loading branch information
tsutomi authored and gitbook-bot committed Oct 21, 2023
1 parent 67c5a38 commit 5584f79
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 65 deletions.
9 changes: 4 additions & 5 deletions docs/motivation.md → docs/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
# Why Another Repository Pattern Library?


## Drivers and Motivation

The repository pattern is a well-known pattern in the domain-driven design, that allows to abstract the data access layer from the domain model, providing a clean separation of concerns.
The repository pattern is a well-known pattern in the domain-driven design, that allows to abstract of the data access layer from the domain model, providing a clean separation of concerns.

The repository pattern is often used in conjunction with the _unit of work_ pattern, that allows to group a set of operations in a single transaction.
The repository pattern is often used in conjunction with the _unit of work_ pattern, which allows to grouping of a set of operations in a single transaction.

While implementing several projects for my own needs, and while creating some Open-Source projects requiring a certain degree of data persistence, I've found myself implementing the same pattern over and over again, with some minor differences, depending on the data source I was using.

I tried to look for existing solutions that could help me in this task, but I found that most of the existing libraries were either unreliable, either too opinionated, or simply not providing the features I was looking for.
I tried to look for existing solutions that could help me in this task, but I found that most of the existing libraries were either unreliable, either too opinionated or simply not providing the features I was looking for.

Although this pattern is not applicable to all scenarios (for instance in the case of _event-driven_ applications), I found that it is still a good pattern to use in many cases, and I decided to create this library to provide a simple and reliable implementation of the pattern, that can be used in different scenarios.

### Why Not Just Use Entity Framework Core?

A great advantage from the usage _Entity Framework Core_ is that it provides a set of abstractions that allows to access different data sources, and to use the same LINQ syntax to query the data.
A great advantage of the usage of _Entity Framework Core_ is that it provides a set of abstractions that allows one to access different data sources and use the same LINQ syntax to query the data.

Anyway, design-wise the Entity Framework is closer to an ORM than to a repository pattern, and it doesn't provide a way to abstract the data access layer from the domain model.

Expand Down
12 changes: 12 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Table of contents

* [Why Another Repository Pattern Library?](README.md)
* [The Repository Pattern](repository-pattern.md)
* [Getting Started](index.md)
* [Customize the Repository](custom-repository.md)
* [Multi-Tenancy of Data Sources](multi-tenancy.md)
* [In-Memory Repositories](in-memory.md)
* [Entity Framework Core Repositories](ef-core.md)
* [MongoDB Repositories](mongodb.md)
* [The Entity Manager](entity-manager/README.md)
* [Caching Entities](entity-manager/caching-entities.md)
50 changes: 23 additions & 27 deletions docs/entity-manager.md → docs/entity-manager/README.md
Original file line number Diff line number Diff line change
@@ -1,48 +1,44 @@
## Entity Manager
# The Entity Manager

The framework provides an extension that allows to control the operations performed on the repository, ensuring the consistency of the data (through validation).
The framework provides an extension that allows control of the operations performed on the repository, ensuring the consistency of the data (through validation).

The `EntityManager<TEntity>` class wraps around instances of `IRepository<TEntity>`, enriching the basic operations with validation logic, and providing a way to intercept the operations performed on the repository, and preventing exceptions to be thrown without a proper handling.
The `EntityManager<TEntity>` class wraps around instances of `IRepository<TEntity>`, enriching the basic operations with validation logic, providing a way to intercept the operations performed on the repository, and preventing exceptions from being thrown without proper handling.

It is possible to derive from the `EntityManager<TEntity>` class to implement your own business and validation logic, and to intercept the operations performed on the repository.

This class is suited to be used in application contexts, where a higher level of control is required on the operations performed on the repository (such for example in the case of ASP.NET services).

### Instrumentation
#### Instrumentation

To register an instance of `EntityManager<TEntity>` in the dependency injection container, you can use the `AddEntityManager<TManager>` extension method of the `IServiceCollection` interface.

```csharp
public void ConfigureServices(IServiceCollection services) {
services.AddEntityManager<MyEntityManager>();
services.AddEntityManager<MyEntityManager>();
}
```

The method will register an instance of `MyEntityManager` and `EntityManager<TEntity>` in the dependency injection container, ready to be used.

### Entity Validation
#### Entity Validation

It is possible to validate the entities before they are added or updated in the repository, by implementing the `IEntityValidator<TEntity>` interface, and registering an instance of the validator in the dependency injection container.

The `EntityManager<TEntity>` class will check for instances of `IEntityValidator<TEntity>` in the dependency injection container, and will use the first instance found to validate the entities before they are added or updated in the repository.
The `EntityManager<TEntity>` the class will check for instances of `IEntityValidator<TEntity>` in the dependency injection container, and will use the first instance found to validate the entities before they are added or updated in the repository.

### Operation Cancellation
#### Operation Cancellation

The `EntityManager<TEntity>` class provides a way to directly cancel the operations performed on the repository, by passing an argument of type `CancellationToken` to each asynchronous operation, and optionally verifies for instances of `IOperationCancellationSource` that are registered in the dependency injection container.
The `EntityManager<TEntity>` class provides a way to directly cancel the operations performed on the repository, by passing an argument of type `CancellationToken` to each asynchronous operation, and optionally verifies instances of `IOperationCancellationSource` that are registered in the dependency injection container.

When the `CancellationToken` argument of an operation is `null`, the `EntityManager<TEntity>` class will check for instances of `IOperationCancellationSource` in the dependency injection container, and will use the first instance found to cancel the operation.
When the `CancellationToken` the argument of an operation is `null`, the `EntityManager<TEntity>` the class will check for instances of `IOperationCancellationSource` in the dependency injection container, and will use the first instance found to cancel the operation.

The value of this approach is to be able to attach the cancellation of the operation to a specific context (such as `HttpContext`), and to be able to cancel the operation from a different context (for instance when the HTTP request is cancelled).
The value of this approach is to be able to attach the cancellation of the operation to a specific context (such as `HttpContext`), and to be able to cancel the operation from a different context (for instance when the HTTP request is canceled).

## License

The project is licensed under the terms of the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).

### Caching
Caching

The `EntityManager<TEntity>` class provides a way to cache the entities retrieved from the repository, and to use the cached entities instead of querying the repository, through the `IEntityCache<TEntity>` service optionally available in the dependency injection container.

To enable the caching feature in the application, you can register an instance of the entity cache specific provider.
To enable the caching feature in the application, you can register an instance of the entity cache-specific provider.

For example, to use the [EasyCaching](https://easycaching.readthedocs.io/en/latest/) library, you can use the following code:

Expand All @@ -60,19 +56,19 @@ The above code will register an instance of `IEntityCache<MyEntity>` in the depe

The `EntityManager<TEntity>` class will interface the instance of `IEntityCache<TEntity>` with the following methods:

| Method | Cache Operation | Description |
| ------ | --------------- | ----------- |
| `FindByKeyAsync` | `GetOrSetAsync` | Retrieves an entity from the cache, using a key generated from the given primary key, and if not found it will invoke a the Repository method to retrieve the entity, and cache it (if found) |
| `AddAsync` | `SetAsync` | Adds an entity to the cache, using a set of keys generated from the entity added. |
| `AddRangeAsync` | `SetAsync` | Adds a set of entities to the cache, using a set of keys generated from the entities added. |
| `UpdateAsync` | `SetAsync` | Updates an entity in the cache, using a set of keys generated from the entity updated. |
| `RemoveAsync` | `RemoveAsync` | Removes an entity from the cache, using a set of keys generated from the entity removed. |
| `RemoveRangeAsync` | `RemoveAsync` | Removes a set of entities from the cache, using a set of keys generated from the entities removed. |
| Method | Cache Operation | Description |
| ------------------ | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `FindByKeyAsync` | `GetOrSetAsync` | Retrieves an entity from the cache, using a key generated from the given primary key, and if not found it will invoke a the Repository method to retrieve the entity, and cache it (if found) |
| `AddAsync` | `SetAsync` | Adds an entity to the cache, using a set of keys generated from the entity added. |
| `AddRangeAsync` | `SetAsync` | Adds a set of entities to the cache, using a set of keys generated from the entities added. |
| `UpdateAsync` | `SetAsync` | Updates an entity in the cache, using a set of keys generated from the entity updated. |
| `RemoveAsync` | `RemoveAsync` | Removes an entity from the cache, using a set of keys generated from the entity removed. |
| `RemoveRangeAsync` | `RemoveAsync` | Removes a set of entities from the cache, using a set of keys generated from the entities removed. |

By default, the `EntityManager<TEntity>` class will use the primary key of the entity to generate the keys used to store the entity in the cache: this behavior can be overridden by implementing the `IEntityCacheKeyGenerator<TEntity>` interface, and registering an instance of the generator in the dependency injection container.
By default, the `EntityManager<TEntity>` class will use the primary key of the entity to generate the keys used to store the entity in the cache: this behavior can be overridden by implementing the `IEntityCacheKeyGenerator<TEntity>` interface and registering an instance of the generator in the dependency injection container.

Implementations of the `EntityManager<TEntity>` have the option to override the default behavior for generating keys for the entities.

#### Cache Serialization
**Cache Serialization**

In some scenarios, the entities retrieved from the repository need to be converted to another version of the entity, that is capable of being serialized before being stored in the cache, and deserialized when retrieved from the cache.
2 changes: 2 additions & 0 deletions docs/entity-manager/caching-entities.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Caching Entities

Loading

0 comments on commit 5584f79

Please sign in to comment.