Compare commits
6 Commits
8d3783cfec
...
7a78a48d03
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7a78a48d03 | ||
|
|
0b3249cb46 | ||
|
|
17fdb6ed51 | ||
|
|
166acea8b1 | ||
|
|
6c2b1884d2 | ||
|
|
3653def773 |
@@ -1,10 +1,8 @@
|
|||||||
|
using DbFirst.API.Middleware;
|
||||||
using DbFirst.Application;
|
using DbFirst.Application;
|
||||||
using DbFirst.Application.Catalogs;
|
using DbFirst.Application.Repositories;
|
||||||
using DbFirst.Domain.Repositories;
|
|
||||||
using DbFirst.Infrastructure;
|
using DbFirst.Infrastructure;
|
||||||
using DbFirst.Infrastructure.Repositories;
|
using DbFirst.Infrastructure.Repositories;
|
||||||
using MediatR;
|
|
||||||
using DbFirst.API.Middleware;
|
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,18 @@
|
|||||||
"http://localhost:5101"
|
"http://localhost:5101"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"TableConfigurations": {
|
||||||
|
"VwmyCatalog": {
|
||||||
|
"ViewName": "VWMY_CATALOG",
|
||||||
|
"GuidColumnName": "GUID",
|
||||||
|
"CatTitleColumnName": "CAT_TITLE",
|
||||||
|
"CatStringColumnName": "CAT_STRING",
|
||||||
|
"AddedWhoColumnName": "ADDED_WHO",
|
||||||
|
"AddedWhenColumnName": "ADDED_WHEN",
|
||||||
|
"ChangedWhoColumnName": "CHANGED_WHO",
|
||||||
|
"ChangedWhenColumnName": "CHANGED_WHEN"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Logging": {
|
"Logging": {
|
||||||
"LogLevel": {
|
"LogLevel": {
|
||||||
"Default": "Information",
|
"Default": "Information",
|
||||||
|
|||||||
@@ -1,102 +0,0 @@
|
|||||||
using AutoMapper;
|
|
||||||
using DbFirst.Domain.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: 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
public class CatalogService : ICatalogService
|
|
||||||
{
|
|
||||||
private readonly ICatalogRepository _repository;
|
|
||||||
private readonly IMapper _mapper;
|
|
||||||
|
|
||||||
public CatalogService(ICatalogRepository repository, IMapper mapper)
|
|
||||||
{
|
|
||||||
_repository = repository;
|
|
||||||
_mapper = mapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<List<CatalogReadDto>> GetAllAsync(CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var items = await _repository.GetAllAsync(cancellationToken);
|
|
||||||
return _mapper.Map<List<CatalogReadDto>>(items);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<CatalogReadDto?> GetByIdAsync(int id, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var item = await _repository.GetByIdAsync(id, cancellationToken);
|
|
||||||
return item == null ? null : _mapper.Map<CatalogReadDto>(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<CatalogReadDto?> CreateAsync(CatalogWriteDto dto, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var existing = await _repository.GetByTitleAsync(dto.CatTitle, cancellationToken);
|
|
||||||
if (existing != null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entity = _mapper.Map<VwmyCatalog>(dto);
|
|
||||||
entity.AddedWho = "system";
|
|
||||||
entity.AddedWhen = DateTime.UtcNow;
|
|
||||||
entity.ChangedWho = "system";
|
|
||||||
entity.ChangedWhen = DateTime.UtcNow;
|
|
||||||
|
|
||||||
var created = await _repository.InsertAsync(entity, cancellationToken);
|
|
||||||
return _mapper.Map<CatalogReadDto>(created);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<CatalogReadDto?> UpdateAsync(int id, CatalogWriteDto dto, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
var existing = await _repository.GetByIdAsync(id, cancellationToken);
|
|
||||||
if (existing == null)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var entity = _mapper.Map<VwmyCatalog>(dto);
|
|
||||||
entity.Guid = id;
|
|
||||||
entity.CatTitle = dto.UpdateProcedure == CatalogUpdateProcedure.Update ? existing.CatTitle : dto.CatTitle;
|
|
||||||
entity.AddedWho = existing.AddedWho;
|
|
||||||
entity.AddedWhen = existing.AddedWhen;
|
|
||||||
entity.ChangedWho = "system";
|
|
||||||
entity.ChangedWhen = DateTime.UtcNow;
|
|
||||||
|
|
||||||
var procedure = dto.UpdateProcedure;
|
|
||||||
var updated = await _repository.UpdateAsync(id, entity, procedure, cancellationToken);
|
|
||||||
return updated == null ? null : _mapper.Map<CatalogReadDto>(updated);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default)
|
|
||||||
{
|
|
||||||
return await _repository.DeleteAsync(id, cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
using DbFirst.Application.Catalogs;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DbFirst.Application.Catalogs.Commands;
|
namespace DbFirst.Application.Catalogs.Commands;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using DbFirst.Application.Repositories;
|
||||||
using DbFirst.Domain.Entities;
|
using DbFirst.Domain.Entities;
|
||||||
using DbFirst.Domain.Repositories;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DbFirst.Application.Catalogs.Commands;
|
namespace DbFirst.Application.Catalogs.Commands;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using DbFirst.Domain.Repositories;
|
using DbFirst.Application.Repositories;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DbFirst.Application.Catalogs.Commands;
|
namespace DbFirst.Application.Catalogs.Commands;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using DbFirst.Application.Catalogs;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DbFirst.Application.Catalogs.Commands;
|
namespace DbFirst.Application.Catalogs.Commands;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using DbFirst.Application.Repositories;
|
||||||
using DbFirst.Domain.Entities;
|
using DbFirst.Domain.Entities;
|
||||||
using DbFirst.Domain.Repositories;
|
|
||||||
using DbFirst.Domain;
|
using DbFirst.Domain;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
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. */
|
|
||||||
|
|
||||||
public interface ICatalogService
|
|
||||||
{
|
|
||||||
Task<List<CatalogReadDto>> GetAllAsync(CancellationToken cancellationToken = default);
|
|
||||||
Task<CatalogReadDto?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
|
|
||||||
Task<CatalogReadDto?> CreateAsync(CatalogWriteDto dto, CancellationToken cancellationToken = default);
|
|
||||||
Task<CatalogReadDto?> UpdateAsync(int id, CatalogWriteDto dto, CancellationToken cancellationToken = default);
|
|
||||||
Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using DbFirst.Domain.Repositories;
|
using DbFirst.Application.Repositories;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DbFirst.Application.Catalogs.Queries;
|
namespace DbFirst.Application.Catalogs.Queries;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using DbFirst.Application.Catalogs;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DbFirst.Application.Catalogs.Queries;
|
namespace DbFirst.Application.Catalogs.Queries;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using DbFirst.Domain.Repositories;
|
using DbFirst.Application.Repositories;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DbFirst.Application.Catalogs.Queries;
|
namespace DbFirst.Application.Catalogs.Queries;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
using DbFirst.Application.Catalogs;
|
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace DbFirst.Application.Catalogs.Queries;
|
namespace DbFirst.Application.Catalogs.Queries;
|
||||||
|
|||||||
10
DbFirst.Application/Repositories/ICatalogRepository.cs
Normal file
10
DbFirst.Application/Repositories/ICatalogRepository.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
using DbFirst.Domain;
|
||||||
|
using DbFirst.Domain.Entities;
|
||||||
|
|
||||||
|
namespace DbFirst.Application.Repositories;
|
||||||
|
|
||||||
|
public interface ICatalogRepository : IRepository<VwmyCatalog>
|
||||||
|
{
|
||||||
|
Task<VwmyCatalog?> GetByTitleAsync(string title, CancellationToken cancellationToken = default);
|
||||||
|
Task<VwmyCatalog?> UpdateAsync(int id, VwmyCatalog catalog, CatalogUpdateProcedure procedure, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
10
DbFirst.Application/Repositories/IRepository.cs
Normal file
10
DbFirst.Application/Repositories/IRepository.cs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
namespace DbFirst.Application.Repositories;
|
||||||
|
|
||||||
|
public interface IRepository<T>
|
||||||
|
{
|
||||||
|
Task<List<T>> GetAllAsync(CancellationToken cancellationToken = default);
|
||||||
|
Task<T?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
|
||||||
|
Task<T> InsertAsync(T entity, CancellationToken cancellationToken = default);
|
||||||
|
Task<T?> UpdateAsync(int id, T entity, CancellationToken cancellationToken = default);
|
||||||
|
Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default);
|
||||||
|
}
|
||||||
@@ -6,8 +6,4 @@
|
|||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Folder Include="Repositories\" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -1,46 +0,0 @@
|
|||||||
using DbFirst.Domain.Entities;
|
|
||||||
using DbFirst.Domain;
|
|
||||||
|
|
||||||
namespace DbFirst.Domain.Repositories;
|
|
||||||
|
|
||||||
// TODO: instead of creating interface per entity, consider using generic repository pattern (eg. IRepository<T>) to reduce code duplication.
|
|
||||||
|
|
||||||
/* Copilot's Response:
|
|
||||||
|
|
||||||
A generic Repository<T> 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
|
|
||||||
{
|
|
||||||
Task<List<VwmyCatalog>> GetAllAsync(CancellationToken cancellationToken = default);
|
|
||||||
Task<VwmyCatalog?> GetByIdAsync(int id, CancellationToken cancellationToken = default);
|
|
||||||
Task<VwmyCatalog?> GetByTitleAsync(string title, CancellationToken cancellationToken = default);
|
|
||||||
Task<VwmyCatalog> InsertAsync(VwmyCatalog catalog, CancellationToken cancellationToken = default);
|
|
||||||
Task<VwmyCatalog?> UpdateAsync(int id, VwmyCatalog catalog, CatalogUpdateProcedure procedure, CancellationToken cancellationToken = default);
|
|
||||||
Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default);
|
|
||||||
}
|
|
||||||
@@ -1,49 +1,54 @@
|
|||||||
using DbFirst.Domain.Entities;
|
using DbFirst.Domain.Entities;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
|
||||||
namespace DbFirst.Infrastructure;
|
namespace DbFirst.Infrastructure;
|
||||||
|
|
||||||
public partial class ApplicationDbContext : DbContext
|
public partial class ApplicationDbContext : DbContext
|
||||||
{
|
{
|
||||||
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
|
private readonly TableConfigurations _config;
|
||||||
|
|
||||||
|
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options, IOptionsMonitor<TableConfigurations> configOptions)
|
||||||
: base(options)
|
: base(options)
|
||||||
{
|
{
|
||||||
|
_config = configOptions.CurrentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual DbSet<VwmyCatalog> VwmyCatalogs { get; set; }
|
public virtual DbSet<VwmyCatalog> VwmyCatalogs { get; set; }
|
||||||
|
|
||||||
// TODO: Configure column names on appsettings via IConfiguration
|
|
||||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||||
{
|
{
|
||||||
|
var catCfg = _config.VwmyCatalog;
|
||||||
|
|
||||||
modelBuilder.Entity<VwmyCatalog>(entity =>
|
modelBuilder.Entity<VwmyCatalog>(entity =>
|
||||||
{
|
{
|
||||||
entity.HasKey(e => e.Guid);
|
entity.HasKey(e => e.Guid);
|
||||||
|
|
||||||
entity.ToView("VWMY_CATALOG");
|
entity.ToView(catCfg.ViewName);
|
||||||
|
|
||||||
entity.Property(e => e.Guid).HasColumnName("GUID");
|
entity.Property(e => e.Guid).HasColumnName(catCfg.GuidColumnName);
|
||||||
entity.Property(e => e.AddedWho)
|
entity.Property(e => e.AddedWho)
|
||||||
.HasMaxLength(30)
|
.HasMaxLength(30)
|
||||||
.IsUnicode(false)
|
.IsUnicode(false)
|
||||||
.HasColumnName("ADDED_WHO");
|
.HasColumnName(catCfg.AddedWhoColumnName);
|
||||||
entity.Property(e => e.AddedWhen)
|
entity.Property(e => e.AddedWhen)
|
||||||
.HasColumnType("datetime")
|
.HasColumnType("datetime")
|
||||||
.HasColumnName("ADDED_WHEN");
|
.HasColumnName(catCfg.AddedWhenColumnName);
|
||||||
entity.Property(e => e.CatString)
|
entity.Property(e => e.CatString)
|
||||||
.HasMaxLength(900)
|
.HasMaxLength(900)
|
||||||
.IsUnicode(false)
|
.IsUnicode(false)
|
||||||
.HasColumnName("CAT_STRING");
|
.HasColumnName(catCfg.CatStringColumnName);
|
||||||
entity.Property(e => e.CatTitle)
|
entity.Property(e => e.CatTitle)
|
||||||
.HasMaxLength(100)
|
.HasMaxLength(100)
|
||||||
.IsUnicode(false)
|
.IsUnicode(false)
|
||||||
.HasColumnName("CAT_TITLE");
|
.HasColumnName(catCfg.CatTitleColumnName);
|
||||||
entity.Property(e => e.ChangedWhen)
|
entity.Property(e => e.ChangedWhen)
|
||||||
.HasColumnType("datetime")
|
.HasColumnType("datetime")
|
||||||
.HasColumnName("CHANGED_WHEN");
|
.HasColumnName(catCfg.ChangedWhenColumnName);
|
||||||
entity.Property(e => e.ChangedWho)
|
entity.Property(e => e.ChangedWho)
|
||||||
.HasMaxLength(30)
|
.HasMaxLength(30)
|
||||||
.IsUnicode(false)
|
.IsUnicode(false)
|
||||||
.HasColumnName("CHANGED_WHO");
|
.HasColumnName(catCfg.ChangedWhoColumnName);
|
||||||
});
|
});
|
||||||
|
|
||||||
OnModelCreatingPartial(modelBuilder);
|
OnModelCreatingPartial(modelBuilder);
|
||||||
|
|||||||
@@ -16,10 +16,12 @@
|
|||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.1" />
|
<PackageReference Include="Microsoft.Data.SqlClient" Version="5.2.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\DbFirst.Domain\DbFirst.Domain.csproj" />
|
<ProjectReference Include="..\DbFirst.Domain\DbFirst.Domain.csproj" />
|
||||||
|
<ProjectReference Include="..\DbFirst.Application\DbFirst.Application.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ public static class DependencyInjection
|
|||||||
{
|
{
|
||||||
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
public static IServiceCollection AddInfrastructure(this IServiceCollection services, IConfiguration configuration)
|
||||||
{
|
{
|
||||||
|
services.Configure<TableConfigurations>(configuration.GetSection("TableConfigurations"));
|
||||||
services.AddDbContext<ApplicationDbContext>(options =>
|
services.AddDbContext<ApplicationDbContext>(options =>
|
||||||
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
|
options.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
|
||||||
return services;
|
return services;
|
||||||
|
|||||||
@@ -1,17 +1,9 @@
|
|||||||
using Azure;
|
using DbFirst.Domain;
|
||||||
using DbFirst.Domain.Entities;
|
using DbFirst.Domain.Entities;
|
||||||
using DbFirst.Domain.Repositories;
|
using DbFirst.Application.Repositories;
|
||||||
using Microsoft.Data.SqlClient;
|
using Microsoft.Data.SqlClient;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Data;
|
using System.Data;
|
||||||
using System.Diagnostics.Metrics;
|
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Channels;
|
|
||||||
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
|
|
||||||
using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
||||||
using DbFirst.Domain;
|
|
||||||
|
|
||||||
namespace DbFirst.Infrastructure.Repositories;
|
namespace DbFirst.Infrastructure.Repositories;
|
||||||
|
|
||||||
@@ -115,6 +107,11 @@ public class CatalogRepository : ICatalogRepository
|
|||||||
return await _db.VwmyCatalogs.AsNoTracking().FirstOrDefaultAsync(x => x.Guid == guid, cancellationToken);
|
return await _db.VwmyCatalogs.AsNoTracking().FirstOrDefaultAsync(x => x.Guid == guid, cancellationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task<VwmyCatalog?> UpdateAsync(int id, VwmyCatalog catalog, CancellationToken cancellationToken = default)
|
||||||
|
{
|
||||||
|
return await UpdateAsync(id, catalog, CatalogUpdateProcedure.Update, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default)
|
public async Task<bool> DeleteAsync(int id, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var exists = await _db.VwmyCatalogs.AsNoTracking().AnyAsync(x => x.Guid == id, cancellationToken);
|
var exists = await _db.VwmyCatalogs.AsNoTracking().AnyAsync(x => x.Guid == id, cancellationToken);
|
||||||
|
|||||||
19
DbFirst.Infrastructure/TableConfigurations.cs
Normal file
19
DbFirst.Infrastructure/TableConfigurations.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
namespace DbFirst.Infrastructure
|
||||||
|
{
|
||||||
|
public class TableConfigurations
|
||||||
|
{
|
||||||
|
public VwmyCatalogConfiguration VwmyCatalog { get; set; } = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
public class VwmyCatalogConfiguration
|
||||||
|
{
|
||||||
|
public string ViewName { get; set; } = "VWMY_CATALOG";
|
||||||
|
public string GuidColumnName { get; set; } = "GUID";
|
||||||
|
public string CatTitleColumnName { get; set; } = "CAT_TITLE";
|
||||||
|
public string CatStringColumnName { get; set; } = "CAT_STRING";
|
||||||
|
public string AddedWhoColumnName { get; set; } = "ADDED_WHO";
|
||||||
|
public string AddedWhenColumnName { get; set; } = "ADDED_WHEN";
|
||||||
|
public string ChangedWhoColumnName { get; set; } = "CHANGED_WHO";
|
||||||
|
public string ChangedWhenColumnName { get; set; } = "CHANGED_WHEN";
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user