Centeva.DomainModeling.EFCore 8.0.0

Prefix Reserved
There is a newer version of this package available.
See the version list below for details.
dotnet add package Centeva.DomainModeling.EFCore --version 8.0.0                
NuGet\Install-Package Centeva.DomainModeling.EFCore -Version 8.0.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Centeva.DomainModeling.EFCore" Version="8.0.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add Centeva.DomainModeling.EFCore --version 8.0.0                
#r "nuget: Centeva.DomainModeling.EFCore, 8.0.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install Centeva.DomainModeling.EFCore as a Cake Addin
#addin nuget:?package=Centeva.DomainModeling.EFCore&version=8.0.0

// Install Centeva.DomainModeling.EFCore as a Cake Tool
#tool nuget:?package=Centeva.DomainModeling.EFCore&version=8.0.0                

Centeva.DomainModeling

This package contains types (classes and interfaces) for building a rich domain layer for your application.

Built With

Getting Started

Add a reference to Centeva.DomainModeling in your project.

You should only need to reference this package from the lowest layer of your solution. If you are using multiple projects to separate Core/Domain, Application, and Web API layers (i.e., "Clean" or "Ports and Adapters" architecture) then reference from the Core project.

Using Entity Framework Core

Reference the Centeva.DomainModeling.EFCore package to get an implementation of the Repository pattern for this ORM. Reference this package from your Infrastructure project if your solution separates concerns by project.

This requires EF Core and MediatR to be added to your application's services configuration for dependency injection. See the documentation for these tools individually for instructions.

Using AutoMapper for Projection Support

You can use AutoMapper to provide projection support for your Repositories, which will allow you to map your entities to another type and only request the data you need from the database.

Import the Centeva.DomainModeling.EFCore.AutoMapper package, add AutoMapper to your application's services configuration for dependency injection, and derive your Repository classes from BaseProjectedRepository. See the AutoMapper documentaion for information on dependency injection setup.

Technical Patterns

Entities

An entity is a plain object that has a unique identifier and contains properties that are likely independently mutable. Two instances of an entity type that have the same identifier should be considered to be equivalent.

In most cases your project will involve persisting entities to some kind of data storage, such as an SQL database. However, the details of such persistence should not be contained within the definitions of those entities. (Avoid things like Entity Framework annotation attributes like [Table].)

The BaseEntity class can be inherited for your project's entities.

  • The Id property (your entity's unique identifier) has a public setter but try to avoid using it in application code, especially if your database is auto-generating values. However, it can be helpful when seeding data both in tests and in your application.

You should strive to protect an entity's invariants using appropriate measures such as private setters, read-only collections, constructors, and public methods for updating the entity's properties.

In addition, register Domain Events within your entity's methods if you expect to have side effects as a result of calling those methods (such as changes to other unconnected entities.)

Value Objects

A value object represents something in your domain that has no unique identity. A value object is ideally immutable and equality is determined by comparing its properties.

Entities can (and should) contain value objects, but value objects should never contain entities.

Your value object classes should inherit from the ValueObject class to gain equality functionality.

See https://enterprisecraftsmanship.com/posts/value-objects-explained/ for more information about this concept.

Aggregates

An Aggregate is a collection of domain objects (Entities and Value Objects) that is treated as a single unit for manipulation and enforcement of invariants (validation rules). A good example is an Order with its collection of OrderItems.

One of the entities in an aggregate is the main entity or "root" and holds references to the other ones. An aggregate is retrieved via its root and outside entities should strive to reference other aggregates only via the root.

You can use the IAggregateRoot interface to mark the roots of your aggregates. This is just a marker interface (no properties or methods) and it's up to you to enforce the Aggregate pattern. (See below for information about enforicing in your repositories.)

Domain Events

Each entity inheriting from BaseEntity contains a DomainEvents list which you can use for storing and later publishing Domain Events. These are used to implement "side effects" based on work done to your entities. These events can be handled elsewhere in your code to better decouple them from other parts of the system. You will need to use the DomainEventDispatcher in your application to publish and handle these, likely inside of your Entity Framework DbContext.

Repositories

Repository is a pattern used to control and constrain access to data. It defines standard CRUD operations on a set of entities of the same type. Read-only operations are defined in IReadRepository while IRepository adds update operations to those. This not only better adheres to the Interface Segregation Principle, but allows implementers to add features such as caching that would only apply to read operations.

If you are implementing Aggregates, your repositories should only operate on the root of each Aggregate, as child entities should never be directly accessed.

The package Centeva.DomainModeling.EFCore provides an abstract implementation of IRepository named BaseRepository. You can use it by creating a derived class in your project. Additionally, if you want to enforce that repositories can only access aggregate roots, then your derived class should look like this:

public class EfRepository<T> : BaseRepository<T>, IRepository<T> where T : class, IAggregateRoot
{
    public EfRepository(ApplicationDbContext dbContext) 
      : base(dbContext) { }
}

If you are using the AutoMapper project feature, then derive your repository from the BaseProjectedRepository class like this:

public class EfRepository<T> : BaseProjectedRepository<T>, IRepository<T>, IProjectedReadRepository<T> where T : class, IAggregateRoot
{
    public EfRepository(ApplicationDbContext dbContext, IConfigurationProvider mappingConfigurationProvider) 
      : base(dbContext, mappingConfigurationProvider) { }
}

Specifications

Specification is a pattern used to pull query logic out of other places in an application and into self-contained, shareable, testable classes. This eliminates the need to add custom query methods to your Repository, and avoids other anti-patterns such as leaked IQueryable objects.

See the documentation for the Ardalis.Specification library for more information and examples.

Running Tests

From Windows, use the dotnet test command, or your Visual Studio Test Explorer. Integration tests will use SQL Server LocalDB.

To run tests in a set of containers with Docker Compose, which is useful for build pipelines and non-Windows development environments, use the ci/run-tests.sh or ci/run-tests.bat scripts.

Deployment

Use dotnet pack to generate a NuGet package. This library is versioned by GitVersion. Create a Git tag for an official release (e.g., "v1.0.0").

Contributing

Please use a Pull Request to suggest changes to this library. You should not add any functionality or dependency that is not appropriate for use at the lowest level (the "domain" level) of an application.

Resources

Take a look at https://bitbucket.org/centeva/centeva.templates for more implementation details.

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Centeva.DomainModeling.EFCore:

Package Downloads
Centeva.DomainModeling.EFCore.AutoMapper

AutoMapper projection implementation for EF Core-based repository in Centeva.DomainModeling

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
10.1.0 215 9/5/2024
10.1.0-tags-v10-1-0-pre-1.1 56 9/5/2024
10.0.0 121 9/5/2024
9.0.0-pre.1 128 12/29/2023
8.1.0 369 12/18/2023
8.0.0 210 10/30/2023
7.0.0 181 10/30/2023