You can follow these rules and apply in your solution while implementing the Domain Driven Design.

This class guarantees to create a valid entity by its constructor. An entity (that's not the aggregate root) in an aggregate can use a composite primary key. A sub-collection should not have more than.

It requires explicit database transaction that covers both operations. The following rules ensures implementing the principles introduced above. Each module has its own independent DbContext and your application has also one DbContext. A Repository is a collection-like interface that is used by the Domain and Application Layers to access to the data persistence system (the database) to read and write the Business Objects, generally the Aggregates. However, EF Core & relational database developers may find this restrictive rule unnecessary since EF Core can handle it on database read and write. Where to implement this rule? So, we need to force the Application Layer always to use the IssueManager to create a new Issue. Before going into details, let's see some overall DDD principles; The domain and the application layers should be ORM / Database Provider agnostic. An aggregate (with the root entity and sub-collections) should be serializable and transferrable on the wire as a single unit. Sometimes you find breaking rules will save you time in a short term. Your application reacts to changes faster. However, being important is not sufficient to consider a code as a Core Business Logic. If we declare all the properties with public setters (like the example Issue class above), we can't force validity and integrity of the entity in its lifecycle. It is a useful utility application that you can use it in development as well as in production environment. Domain Services implement domain logic which; Domain Services work with Domain Objects. So, they will be treated differently. Issue.AddComment gets a userId and comment text, implements the necessary business rules and adds the comment to the Comments collection of the Issue. DDD helps to deal with complexity when your system is large. Because, in this example, whenever you change a filter, you have to make the necessary changes in all the methods to have a consistent reporting system. _issueRepository.GetAsync method gets an optional parameter, includeDetails, that you can pass false to disable this behavior when you need it. The Domain Layer is splitted into two projects; The Application Layer is also splitted into two projects; ABP Framework also supports different kind of UI frameworks including Angular and Blazor. Automatic object to object mapping is a useful approach to copy values from one object to another when two objects have same or similar properties. So, you actually don't need to call _issueRepository.UpdateAsync. An aggregate should maintain its self integrity and validity by implementing domain rules and constraints. If we have a business rule like "Users can not comment on the locked issues", how can we check the Issue's lock state without retrieving it from the database? There are a some responsibilities of a well designed constructor: Example: Issue (Aggregate Root) constructor. You are free to do all these things as long as you don't infect them into your business logic. In a DDD implementation, you may have a single Infrastructure project to implement all the abstractions and integrations, or you may have different projects for each dependency. Web project depends on the Application and EntityFrameworkCore projects which theoretically should not be like that but actually it is. Johan Cruyff. However, it is an important practice of Domain Driven Design. UserDto is defined below: This is more maintainable approach although more code is written. Now, we can explain the reasons of the dependencies; When you investigate the solution, you will see two more dependencies shown with the dashed lines in the figure above. Example: Creating a new Organization in a Domain Service. However, they don't get/return DTOs. An aggregate is retrieved and saved as a single unit, with all the sub-collections and properties. This time, beginning from the Update DTO: By comparing to IssueCreationDto, you see no RepositoryId. If you've multiple applications with a single domain; Such a design makes it even more important to distinguish between Domain logic and Application Logic. It is internal and changing it is possible only inside the same Assembly, the IssueTracking.Domain project for this example solution. Instead, an IssueTracking.HttpApi.Host application will be in the solution to serve the HTTP APIs as a standalone endpoint to be consumed by the UI applications via HTTP API calls. An admin user can use a Back Office Application to create a new organization without any payment. As you can guess, there will be a lot of code duplications for querying data, mapping entities to DTOs. It is used by the Presentation Layer. Even if they are same now, they will probably become different by the time and you will come to the same problem. Example: Throwing a business exception with code. In this way, we can check activeness when we have an issue entity. But it happens, especially when you try to reuse input DTOs. A specification is a named, reusable, combinable and testable class to filter the Domain Objects based on the business rules. Since the specification (the filter) has been moved out of the repository, we no longer need to create different methods to get issues with different conditions (like GetAssignedIssues(), GetLockedIssues(), etc.). Exceptional Case: There can be some exceptions for this rule: If you always want to develop two methods in parallel, they may share the same input DTO (by inheritance or direct reuse). There are four fundamental layers of a Domain Driven Based Solution; Business Logic places into two layers, the Domain layer and the Application Layer, while they contain different kinds of business logic; The same layering can be shown as the diagram below and known as the Clean Architecture, or sometimes the Onion Architecture: In the Clean Architecture, each layer only depends on the layer directly inside it. You can even delete the IssueTracking.HttpApi.Client project if you think that you don't need to them. Examples; As you see, payment is not a necessary operation to create a valid organization. What if the business logic requires to query database or use any external services that should be resolved from the dependency injection system. This section will demonstrate some example use cases and discuss alternative scenarios. Once an entity is created, it is updated/manipulated by the use cases until it is deleted from the system. In this case, the same information is duplicated in different collections and it will be hard to maintain data consistency (whenever you add an item to User.Roles, you need to add it to Role.Users too). The figure below shows some of the aggregates, aggregate roots, entities, value object and the relations between them: Issue Aggregate consists of an Issue Aggregate Root that contains Comment and IssueLabel collections. This method perfectly guarantees to apply the business logic when you want to assign an issue to a user. On the other hand, User may have such a Roles collection since a user doesn't have much roles in practical and it can be useful to have a list of roles while you are working with a User Aggregate. You may be undecided which code should stand in the Application Layer, which code should be in the Domain Layer. The following rules will already bring the serializability. Some developers think it is better to separate the validation rules and DTO classes. That's why this logic is a core domain logic, should be located in the Domain Layer and should not be duplicated in all these application service methods. It is mostly related to modularity. The checks in the UI layer is mostly for user experience while checks in the application and domain layers are for security and data integrity. You see two aggregate roots, GitRepository and Issue in the example below; So, when you have an Issue and need to have GitRepository related to this issue, you need to explicitly query it from database by the RepositoryId. Input DTOs (those are passed to the Application Service methods) have different natures than Output DTOs (those are returned from the Application Service methods). Most of the business applications are re-written just because you can't maintain it anymore. This Application Service does nothing itself and delegates all the work to the Domain Service. ABP Framework helps to implement this principle in your applications. So, whenever we need to create an instance of that entity, we should always use that constructor. Implementing DDD highly relies on the Object Oriented Programming (OOP) and SOLID principles. Example: Using Data Annotation Attributes. Creating an object from an Entity / Aggregate Root class is the first step of the lifecycle of that entity. See the Loading Related Entities section of the EF Core document for the configuration and alternative scenarios. We will introduce and explain some explicit rules with examples. This is a practical guide for implementing the Domain Driven Design (DDD). If you follow the rules and best practices, your code base will be simpler and easier to maintain.

However, for MongoDB, you need to explicitly update the changed entity. Define public methods to manipulate such properties. Most of the time, API Controllers are just wrappers around the Application Services to expose them to the remote clients. Mixing all these logics into a single application layer makes your services contain too many if conditions with complicated business logic makes your code harder to develop, maintain and test and leads to potential bugs. See the example below: Role aggregate has a collection of UserRole value objects to track the users assigned for this role. This is because the example code above just focuses on the constructor. It uses and coordinates the domain objects (entities, repositories, etc.) See the Application Startup Template document if you want to know more about the solution structure. It is simple to implement a business rule in an entity method when the business logic only uses the properties of that entity. Here, two of the alternatives if you want to remove this dependency; The figure below shows a typical request flow for a web application that has been developed based on DDD patterns. See the Validation document for all validation options. However, it is a problem in practical. Getting the Issue with all details seems unnecessary and inefficient. Remember; Entities can not inject services! This rule makes it possible to implement the serializability principle. When you throw the exception, ABP automatically uses this localized message (based on the current language) to show to the end user. part is not shown to be simple).

Finally, we use _issueRepository.UpdateAsync to save changes to the database. The only problem of this design is that Issue.AssignedUserId is now open to set out of the class. Just moved the expression here, from the repository. That means, unlike the DTOs, Entities have methods to implement some business logic. However, in real life, you have; We can give more examples. Actually, we should try to implement business rules in the entities wherever possible. If a use case works with a single aggregate, reads and saves it as a single unit, all the changes made to the aggregate objects are saved together as an atomic operation and you don't need to an explicit database transaction. Then we can add a CreateAsync method to the IssueManager: The IssueAppService is changed as shown below in order to use the IssueManager's CreateAsync method: You may ask "Why didn't IssueManager save the Issue to the database?". Playing football is very simple, but playing simple football is the hardest thing there is. It causes performance lost because of double database round trip. If you do that, you find a copy of the destination aggregate object in the database collection of the source aggregate since it is being serialized to JSON on save. There are some reasons why you should not use input DTO to Entity auto mapping; While some of these problems can be solved through mapping configurations (For example, AutoMapper allows to define custom mapping rules), it makes your business code implicit/hidden and tightly coupled to the infrastructure. Otherwise, we would need to perform one Insert (in the IssueManager) and one Update (after the Assignment). Finally, we can pass any Specification instance to the GetIssuesAsync method: Actually, you don't have to create custom repositories to be able to use specifications. That means you can not add navigation properties to other aggregates. You can surely define optional properties, but they should effect how the use case is working, when the client provides them. There can be different types of the use cases directly or indirectly changes an entity. DTO and Entity classes generally have same/similar properties and you typically need to create DTO objects from Entities. Let's see the CreateAsync method step by step to discuss if the code part should be in the Domain Service, or not; Example: Creating a new Organization in an Application Service. There is one more project, IssueTracking.DbMigrator, that is a simple Console Application that migrates the database schema and seeds the initial data when you execute it. If you think carefully, there is one more problem when Role and User both have the list of relation when use a non-relational database, like MongoDB. See the Unit Of Work documentation for more info. The Aggregate Root Entities are also responsible for their sub-collection entities. There are more combining methods are available, like Or() and AndNot(). That doesn't mean they are not important. The result will be same. Here, the main reasons of this principle; As a respect to this principle, none of the projects in the solution has reference to the EntityFrameworkCore project, except the startup application. Since the Application Layer gracefully abstracts the Domain Layer, the refactoring process doesn't effect the UI Layer and other clients. If you want to take advantage of this EF Core feature, please see the Discussion About the Database Independence Principle section above. ABP's startup solution has two projects for the Entity Framework Core integration; You may wonder why there are two projects for the EF Core. Define a specialized input DTO for each use case (Application Service method). Example: Returning Different DTO types from different methods, (We didn't use async methods to make the example cleaner, but use async in your real world application!). This is a duplication of a business logic, which is pretty dangerous. Example: Get inactive issues from a repository. IssueAssignDto in this example is a simple DTO class: A DTO is a simple object that is used to transfer state (data) between the Application and Presentation Layers. UI frameworks and database providers have their own rules and best practices that you need to know and apply. The solution is layered by considering DDD principles as well as development and deployment practicals. It is a use-case specific application logic. So; Example: Methods to change the properties in a controlled way. In such cases, create Domain Service methods, but only for those really necessary. The request typically begins with a user interaction on the UI (a, An MVC Controller or a Razor Page Handler in the Presentation Layer (or in the Distributed Services Layer) handles the request and can perform some cross cutting concerns in this stage (, The Application Service uses the Domain Objects (Entities, Repository interfaces, Domain Services, etc.) While the definition is clear, the implementation may not be easy. However, it has some problems; An alternative way of implementing this business logic is to introduce a Domain Service, which will be explained later. The sub sections below explains the projects in the solution; Your solution structure may be slightly different if you choose a different UI or Database provider. We think the business code should be explicit, clear and easy to understand. If additional actions cancel the entity creation because of a business rule, the transaction should be rolled back in the database. An application service typically gets and returns DTOs.

ABP's object to object mapping system with AutoMapper integration makes these operations much easier comparing to manual mapping. For example, we force to pass a non-null Title in the constructor. However, reporting is another topic. We think this is reasonable; While there is a tradeoff between two approaches, we prefer to create Domain Services when the business logic requires to work with external services. Query (load/save) performance and memory consumption. For example, think a scenario where you show a data grid of Users on the UI. See the Entity Creation section below for an example implementation of the suggestions made in this section. This section tries to explain the differences. First, made SetTitle internal in the Issue class: Then added a new method to the IssueManager to change the Title: As mentioned before, Business Logic in the Domain Driven Design is spitted into two parts (layers): Domain Logic and Application Logic: Domain Logic consists of the Core Domain Rules of the system while Application Logic implements application specific Use Cases. You can even reference to the EF Core NuGet Package from your application layer to be able to directly use the asynchronous LINQ extension methods, like ToListAsync() (see the IQueryable & Async Operations section in the Repositories document for more info). You may wonder why the payment code is not inside the OrganizationManager. We suggest a balanced approach; Create separate projects for main infrastructure dependencies (like Entity Framework Core) and a common infrastructure project for other infrastructure. While most of the time you don't need to know it, you can see the EF Core migrations document for more information. IIssueRepository extends the standard IRepository<> interface by adding a GetInActiveIssuesAsync method. After updating a user, you can get the return value and update it on the UI. That doesn't mean the Presentation and Infrastructure layers are not important. We may have other use cases where we don't charge money to create a new Organization.