iayti / CleanArchitecture

ASP.NET Core 6 Web API Clean Architecture Solution Template
MIT License
682 stars 124 forks source link

Clean architecture with EF Core DB First approach #44

Open milyas-salik opened 2 years ago

milyas-salik commented 2 years ago

Hi,

I am implementing clean architecture using the existing database, with scaffolding command I have generated the POCO entities in the Infrastructure layer and as well as manually created the entities in the domain layer to map them later.

in the Application layer, I have the generic interface repository with a few standard operations.

 public interface IRepository<T> where T : class
    {
        Task<IReadOnlyList<T>> GetAllAsync();
        Task<T> GetByIdAsync(int id);
        Task<T> AddAsync(T entity);
        Task UpdateAsync(T entity);
        Task DeleteAsync(T entity);
    }

As per the principles of Clean-Architecture, I am implementing it in the Infrastructure layer.

public class Repository<T> : IRepository<T> where T : class
    {

        protected readonly MyDBContext _MyDBContext;
        public Repository( MyDBContext mydbContext)
        {
            _MyDBContext= mydbContext;
        }
        public async Task<T> AddAsync(T entity)
        {
            await _MyDBContext.Set<T>().AddAsync(entity);
            await _MyDBContext.SaveChangesAsync();
            return entity;
        }

-----
----

As per the template, I am using a Mediator pattern with CQRS, when I try to save the user from the API layer I will end up with the below exception.

System.InvalidOperationException: Cannot create a DbSet for 'ABC.Domain.Entities.User' because this type is not included in the model for the context. However, the model contains an entity type with the same name in a different namespace: 'ABC.Infrastructure.Models.User'.

It will be resolved if I can able to map the domain entity to the infrastructure entity in the above Repository implementation. In the above implementation, the T is the ABC.Domain.Entities.User, not the ABC.Infrastructure.Models.User. I can't pass the ABC.Infrastructure.Models.User from the Application layer ( because I can't add a reference to the Infrastructure layer in Application layer) due to the rule Clean Architecture all dependencies flow inwards and Core has no dependency on any other layer.

Please help me to map the incoming domain entity with the infrastructure entity in the above repository implementation so that I can use these general methods for other entity operations as well.

@iayti .. Please do the needful.

iayti commented 2 years ago

Hi @milyas-salik ,

I didn't have enough time to test what you wrote. Can you try updating the Models folder to look at the Entities folder in the Domain project while doing Database Scaffolding? Db first runs as database-dependent at startup. In this example, we are trying to make it database-independent.

If you have time, could you create an example project with the steps you followed and share it with me? Let's try to solve the error together.

milyas-salik commented 2 years ago

@iayti : here is my source code. https://gitlab.com/mail2mdilyas/workcontinent/-/tree/master

The one way, I am thinking is to get rid of the dependency with infrastructure entities (generated from the database using scaffolding) and use the domain entities with the model builder ==> modelBuilder.Entity - Professional class should be the one coming from your domain instead of infrastructure

As per me, this is the easier solution for DB's first approaches using clean architecture. I need your advice on it, is it a valid adjustment or do you advise using any other alternative solution? At the same time, I don't want to break the clean architecture rules as I want scalable and maintainable applications in the future.

wahabalemi commented 1 year ago

hi when use " dotnet ef migrations add "CreateDb" --project src\Common\CleanArchitecture.Infrastructure.SqlServe --startup-project src\Apps\CleanArchitecture.Api " command cli returns "The entity type 'DomainEvent' requires a primary key to be defined."