diff --git a/docs/Best-Practices/Entities.md b/docs/Best-Practices/Entities.md index e2fd57999e..71f7df01ac 100644 --- a/docs/Best-Practices/Entities.md +++ b/docs/Best-Practices/Entities.md @@ -1,29 +1,52 @@ ## Entity Best Practices & Conventions +### Entities + +Every aggregate root is also an entity. So, these rules are valid for aggregate roots too unless aggregate root rules override them. + +- **Do** define repository interfaces in the **domain layer**. + +#### Primary Constructor + +* **Do** define a **primary constructor** that ensures the validity of the entity on creation. Primary constructors are used to create a new instance of the entity by the application code. + +- **Do** define primary constructor as `public`, `internal` or `protected internal` based on the requirements. If it's not public, the entity is expected to be created by a domain service. +- **Do** always initialize sub collections in the primary constructor. +- **Do not** generate `Guid` keys inside the constructor. Get it as a parameter, so the calling code will use `IGuidGenerator` to generate a new `Guid` value. + +#### Parameterless Constructor + +- **Do** always define a `protected` parameterless constructor to be compatible with ORMs. + +#### References + +- **Do** always **reference** to other aggregate roots **by Id**. Never add navigation properties to other aggregate roots. + +#### Other Class Members + +- **Do** always define properties and methods as `virtual` (except `private` methods, obviously). Because some ORMs and dynamic proxy tools require it. +- **Do** keep the entity as always **valid** and **consistent** within its own boundary. + - **Do** define properties with `private`, `protected`, `internal ` or `protected internal` setter where it is needed to protect the entity consistency and validity. + - **Do** define `public `, `internal` or `protected internal` (virtual) **methods** to change the properties (with non-public setters) if necessary. + ### Aggregate Roots +#### Primary Keys + * **Do** always use a **Id** property for the aggregate root key. * **Do not** use **composite keys** for aggregate roots. * **Do** use **Guid** as the **primary key** of all aggregate roots. + +#### Base Class + * **Do** inherit from the `AggregateRoot` or one of the audited classes (`CreationAuditedAggregateRoot`, `AuditedAggregateRoot` or `FullAuditedAggregateRoot`) based on requirements. + +#### Aggregate Boundary + * **Do** keep aggregates **as small as possible**. Most of the aggregates will only have primitive properties and will not have sub collections. Consider these as design decisions: * **Performance** & **memory** cost of loading & saving aggregates (keep in mind that an aggregate is normally loaded & saved as a single unit). Larger aggregates will consume more CPU & memory. * **Consistency** & **validity** boundary. -### Entities - -Every aggregate root is also an entity. So, these rules are valid for aggregate roots too. - -- **Do** always **reference** to other aggregate roots **by Id**. Never add navigation properties to other aggregate roots. -- **Do** keep the entity as always valid and consistent within its own boundary. -- **Do** define properties with **private/protected/internal setters** where it is needed to protect the entity consistency. -- **Do** always define entity members (public/protected properties and methods) as **virtual**. Because some ORMs require it. -- Do define a **primary public/internal constructor** that ensures the validity of the entity on creation. Primary constructors are used to create a new instance of the entity. - - **Do** always initialize sub collections in the primary constructor. - - **Do** always define a **protected default (parameterless) constructor** to be compatible with ORMs. -- **Do** define (virtual) **methods** to change the properties (with private/protected setters) if necessary. -- **Do not** generate `Guid` keys inside the constructor. Get it as a parameter, so the calling code will use `IGuidGenerator` to generate a new `Guid` value. - ### Example #### Aggregate Root diff --git a/docs/Best-Practices/Repositories.md b/docs/Best-Practices/Repositories.md index 295c832c39..c0058df433 100644 --- a/docs/Best-Practices/Repositories.md +++ b/docs/Best-Practices/Repositories.md @@ -2,6 +2,7 @@ ### Repository Interfaces +* **Do** define repository interfaces in the **domain layer**. * **Do** define a repository interface (like `IIdentityUserRepository`) and create its corresponding implementations for **each aggregate root**. * **Do** always use the created repository interface from the application code. * **Do not** use generic repository interfaces (like `IRepository`) from the application code. @@ -25,7 +26,6 @@ public interface IIdentityUserRepository : IBasicRepository } ```` -* **Do** define repository interfaces in the **domain layer**. * **Do not** inherit the repository interface from the `IRepository` interface. Because it inherits the `IQueryable` and the repository should not expose `IQueryable` to the application. * **Do** inherit the repository interface from `IBasicRepository` (as normally) or a lower-featured interface, like `IReadOnlyRepository` (if it's needed). * **Do not** define repositories for entities those are **not aggregate roots**.