diff --git a/DbFirst.API/Program.cs b/DbFirst.API/Program.cs index d1e3c7e..3cc1af7 100644 --- a/DbFirst.API/Program.cs +++ b/DbFirst.API/Program.cs @@ -1,6 +1,6 @@ using DbFirst.API.Middleware; using DbFirst.Application; -using DbFirst.Domain.Repositories; +using DbFirst.Application.Repositories; using DbFirst.Infrastructure; using DbFirst.Infrastructure.Repositories; diff --git a/DbFirst.Application/Catalogs/CatalogService.cs b/DbFirst.Application/Catalogs/CatalogService.cs index 74bd421..74e0a06 100644 --- a/DbFirst.Application/Catalogs/CatalogService.cs +++ b/DbFirst.Application/Catalogs/CatalogService.cs @@ -1,38 +1,14 @@ using AutoMapper; -using DbFirst.Domain.Repositories; +using DbFirst.Application.Repositories; using DbFirst.Domain.Entities; using DbFirst.Domain; namespace DbFirst.Application.Catalogs; //TODO: create generic service to reduce code duplication - -/* Copilot's Response: -A generic CRUD base service adds little value in your case: - -Pros: -• Less boilerplate for simple entities without special logic. -• Uniform CRUD signatures. - -Cons/Practical here: -• Domain logic differs per entity(unique title check, setting audit fields, forbidding title changes, stored procs with output GUID). -• Generic services tend to be diluted by virtual methods/hooks for special cases—ending up with per-entity overrides and little real gain. -• With stored procedures and output parameters, the pattern doesn’t fit cleanly because operations aren’t symmetric (separate procs for insert/update/delete). - -Conclusion: For this solution a generic service would be more overhead than benefit. If you later have multiple very similar entities without special logic, -you could consider a lightweight generic interface/base; for now, the specialized service implementation is cleaner. */ - -/* Hakan's Response: - * No, it absolutely makes sense to create a generic service using Options pattern. So, you can easily inject your SQL queries or stored procedure names via configuration. - * see: https://docs.microsoft.com/en-us/dotnet/core/extensions/options - */ - +//TODO (TR): kod tekrar?n? azaltmak için generic bir servis/basit CRUD altyap?s? ekleyin //TODO: implement CQRS pattern with MediatR - -/* Hakan's response - * Here is the main part. We dont even need a service layer if we implement CQRS with MediatR at least for CRUD operations. - */ - +//TODO (TR): CQRS desenini MediatR ile uygulay?n public class CatalogService : ICatalogService { private readonly ICatalogRepository _repository; diff --git a/DbFirst.Application/Catalogs/Commands/CreateCatalogHandler.cs b/DbFirst.Application/Catalogs/Commands/CreateCatalogHandler.cs index 3be85da..ccef126 100644 --- a/DbFirst.Application/Catalogs/Commands/CreateCatalogHandler.cs +++ b/DbFirst.Application/Catalogs/Commands/CreateCatalogHandler.cs @@ -1,6 +1,6 @@ using AutoMapper; +using DbFirst.Application.Repositories; using DbFirst.Domain.Entities; -using DbFirst.Domain.Repositories; using MediatR; namespace DbFirst.Application.Catalogs.Commands; diff --git a/DbFirst.Application/Catalogs/Commands/DeleteCatalogHandler.cs b/DbFirst.Application/Catalogs/Commands/DeleteCatalogHandler.cs index 8c5e033..8356117 100644 --- a/DbFirst.Application/Catalogs/Commands/DeleteCatalogHandler.cs +++ b/DbFirst.Application/Catalogs/Commands/DeleteCatalogHandler.cs @@ -1,4 +1,4 @@ -using DbFirst.Domain.Repositories; +using DbFirst.Application.Repositories; using MediatR; namespace DbFirst.Application.Catalogs.Commands; diff --git a/DbFirst.Application/Catalogs/Commands/UpdateCatalogHandler.cs b/DbFirst.Application/Catalogs/Commands/UpdateCatalogHandler.cs index e236981..9e25ef5 100644 --- a/DbFirst.Application/Catalogs/Commands/UpdateCatalogHandler.cs +++ b/DbFirst.Application/Catalogs/Commands/UpdateCatalogHandler.cs @@ -1,6 +1,6 @@ using AutoMapper; +using DbFirst.Application.Repositories; using DbFirst.Domain.Entities; -using DbFirst.Domain.Repositories; using DbFirst.Domain; using MediatR; diff --git a/DbFirst.Application/Catalogs/Queries/GetAllCatalogsHandler.cs b/DbFirst.Application/Catalogs/Queries/GetAllCatalogsHandler.cs index b824f66..e1d952b 100644 --- a/DbFirst.Application/Catalogs/Queries/GetAllCatalogsHandler.cs +++ b/DbFirst.Application/Catalogs/Queries/GetAllCatalogsHandler.cs @@ -1,5 +1,5 @@ using AutoMapper; -using DbFirst.Domain.Repositories; +using DbFirst.Application.Repositories; using MediatR; namespace DbFirst.Application.Catalogs.Queries; diff --git a/DbFirst.Application/Catalogs/Queries/GetCatalogByIdHandler.cs b/DbFirst.Application/Catalogs/Queries/GetCatalogByIdHandler.cs index f61aed3..b463cf2 100644 --- a/DbFirst.Application/Catalogs/Queries/GetCatalogByIdHandler.cs +++ b/DbFirst.Application/Catalogs/Queries/GetCatalogByIdHandler.cs @@ -1,5 +1,5 @@ using AutoMapper; -using DbFirst.Domain.Repositories; +using DbFirst.Application.Repositories; using MediatR; namespace DbFirst.Application.Catalogs.Queries; diff --git a/DbFirst.Application/Repositories/ICatalogRepository.cs b/DbFirst.Application/Repositories/ICatalogRepository.cs new file mode 100644 index 0000000..69dd856 --- /dev/null +++ b/DbFirst.Application/Repositories/ICatalogRepository.cs @@ -0,0 +1,10 @@ +using DbFirst.Domain; +using DbFirst.Domain.Entities; + +namespace DbFirst.Application.Repositories; + +public interface ICatalogRepository : IRepository +{ + Task GetByTitleAsync(string title, CancellationToken cancellationToken = default); + Task UpdateAsync(int id, VwmyCatalog catalog, CatalogUpdateProcedure procedure, CancellationToken cancellationToken = default); +} diff --git a/DbFirst.Domain/Repositories/IRepository.cs b/DbFirst.Application/Repositories/IRepository.cs similarity index 91% rename from DbFirst.Domain/Repositories/IRepository.cs rename to DbFirst.Application/Repositories/IRepository.cs index 0064910..a44f313 100644 --- a/DbFirst.Domain/Repositories/IRepository.cs +++ b/DbFirst.Application/Repositories/IRepository.cs @@ -1,4 +1,4 @@ -namespace DbFirst.Domain.Repositories; +namespace DbFirst.Application.Repositories; public interface IRepository { diff --git a/DbFirst.Domain/DbFirst.Domain.csproj b/DbFirst.Domain/DbFirst.Domain.csproj index fa71b7a..bbf0ab3 100644 --- a/DbFirst.Domain/DbFirst.Domain.csproj +++ b/DbFirst.Domain/DbFirst.Domain.csproj @@ -6,4 +6,8 @@ enable + + + + diff --git a/DbFirst.Domain/Repositories/ICatalogRepository.cs b/DbFirst.Domain/Repositories/ICatalogRepository.cs deleted file mode 100644 index 2534739..0000000 --- a/DbFirst.Domain/Repositories/ICatalogRepository.cs +++ /dev/null @@ -1,41 +0,0 @@ -using DbFirst.Domain.Entities; - -namespace DbFirst.Domain.Repositories; - -// TODO: instead of creating interface per entity, consider using generic repository pattern (eg. IRepository) to reduce code duplication. - -/* Copilot's Response: - -A generic Repository isn’t really worthwhile here: - • Reads from the view are generic, but inserts/updates/deletes go through stored procedures with special parameters/output GUIDs.You’d need lots of exceptions/overrides—little gain. - • Operations aren’t symmetric (separate procs for insert/update/delete with output handling and reload), so a one-size-fits-all CRUD pattern doesn’t fit well. - • Better to keep the specialized repo.If you want reuse, extract small helpers (e.g., for proc calls/output parameters/reload) instead of forcing a generic repository. */ - - -/* Hakan's Response: - * I think it still makes sense. An execute SQL method can be added to repository. The relevant SQL can be executed in the application layer. - * Because the application layer is no longer dependent on a method like CreateAsync. It is now directly dependent on that procedure. - */ - -// TODO: move to application layer as a part of clean architecture - -/* Copilot's Response: - - • Common: Keep the interface in the Domain layer, implementation in Infrastructure. Domain defines the data access contract, Infrastructure provides the implementation. - That matches typical DDD/Clean Architecture. - • Alternative: Move the interface to the Application layer. Then only Application depends on Infrastructure, Domain stays isolated from infra contracts. - Pro: Domain contains only models/rules. - Con: If Domain logic needs repos, it would depend on Application, weakening the layer separation. - Recommendation: Keep the interface in Domain. It’s conventional, clean, and avoids a Domain -> Application dependency. Implementation stays in Infrastructure. */ - -/* Hakan's Response: - * I don't think there's any point in keeping repository interfaces in the domain layer. These interfaces will be used in the application layer, not the domain layer. - * Furthermore, this is how they are used in the most popular clean architecture pattern. - * See: https://github.com/jasontaylordev/CleanArchitecture/blob/main/src/Infrastructure/Identity/IdentityService.cs - */ - -public interface ICatalogRepository : IRepository -{ - Task GetByTitleAsync(string title, CancellationToken cancellationToken = default); - Task UpdateAsync(int id, VwmyCatalog catalog, CatalogUpdateProcedure procedure, CancellationToken cancellationToken = default); -} diff --git a/DbFirst.Infrastructure/DbFirst.Infrastructure.csproj b/DbFirst.Infrastructure/DbFirst.Infrastructure.csproj index 5a8052a..83b7a53 100644 --- a/DbFirst.Infrastructure/DbFirst.Infrastructure.csproj +++ b/DbFirst.Infrastructure/DbFirst.Infrastructure.csproj @@ -21,6 +21,7 @@ + diff --git a/DbFirst.Infrastructure/Repositories/CatalogRepository.cs b/DbFirst.Infrastructure/Repositories/CatalogRepository.cs index d15e5ff..7ee6102 100644 --- a/DbFirst.Infrastructure/Repositories/CatalogRepository.cs +++ b/DbFirst.Infrastructure/Repositories/CatalogRepository.cs @@ -1,6 +1,6 @@ using DbFirst.Domain; using DbFirst.Domain.Entities; -using DbFirst.Domain.Repositories; +using DbFirst.Application.Repositories; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore; using System.Data;