DiyanetCleanArchitectureDbContext data katmanının merkezidir. Hem klasik DbContext’tir hem de IUnitOfWork arayüzünü uygular — yani transaction sınırı ve domain event dispatch noktası buradadır.
DbSet’ler
Tüm aggregate root’lar (ve bazı child entity’ler)DbSet olarak tanımlıdır:
Citizen (vatandaş portalı) ile User (personel/admin) ayrı aggregate’lerdir ve ayrı tablolara yazılır. Aynı kişi iki tarafta da bağımsız kayıt tutar.OnModelCreating
Üç iş yapar: configuration’ları toplar, MassTransit messaging tablolarını ekler, global soft-delete filtresini kurar.ISoftDeletable için DeletedAt == null koşulu ekler — detaylar Soft Delete sayfasında.
UnitOfWork: SaveEntitiesAsync
SaveEntitiesAsync business akışının kullandığı kayıt metodudur. SaveChanges çağırır, ardından değişen aggregate’lerin domain event’lerini dispatch eder:
DispatchDomainEventsAsync (SeedWork/MediatorExtension.cs) change tracker’daki her Entity’nin event’lerini toplar, temizler ve tek tek yayar. IntegrationEvent’ler IEventBus (MassTransit Outbox), kalan domain event’ler MediatR ile in-memory işlenir:
DbContext ayrıca manuel transaction desteği sunar: BeginTransactionAsync (ReadCommitted), CommitTransactionAsync, RollbackTransaction. Çoğu komut tek SaveEntitiesAsync ile yetinir; çapraz-aggregate atomikliği gereken yerlerde açık transaction kullanılır.
EntityTypeConfiguration örnekleri
Value object’leri kolona çevirme — HasConversion
User.Email, User.Phone, User.FullName value object’tir; tek kolona serialize edilir:
Owned type — OwnsOne
TOTP konfigürasyonu nested owned type’tır (aynıusers satırına kolon olarak yazılır):
Citizen.ProfileImage ise owned type olmasına rağmen ayrı tabloya (citizen_profile_images) yazılır — bytea payload’ı liste sorgularını şişirmesin diye AsSplitQuery ile lazy yüklenir:
DB-generated referans numarası — IDENTITY kolon
User.ReferenceNumber PostgreSQL IDENTITY kolonudur (insan-okuyabilir, artan numara), 100’den başlar ve insert sonrası salt-okunur:
Optimistic concurrency
users tablosu shadow row_version kolonuyla optimistic concurrency control yapar:
Repository’ler
İki ayrı path var: write (IRepository<T>) ve read (IReadRepository<T>). İkisi de Ardalis.Specification tabanlıdır.
EFRepository — write tarafı
UnitOfWork property’si _context’in ta kendisidir; handler _repository.UnitOfWork.SaveEntitiesAsync(...) ile kaydeder.
CachedRepository — read tarafı (HybridCache decorator)
IReadRepository<T> implementasyonu, gerçek sorguyu EFCacheRepository<T>’ye delege eder ve spec cache-enabled ise HybridCache (L1 memory + L2 Redis) ile sarmalar:
Cache:Enabled açık ve spec’te EnableCache(...) zinciri kurulmuş olmalı:
Cache:L2:Ttl kullanılır. Handler/query cache’ten habersizdir — cache tamamen decorator’ın işidir.
DI kaydı
AddInfrastructureEFCore (DependencyInjection.cs) tüm bağımlılıkları kurar:
Connection string adı sabittir:
DiyanetCleanArchitectureDatabaseConnection. Aynı isim DesignTimeDbContextFactoryBase tarafından da kullanılır (migration araçları için).İlgili
Audit Interceptor
AuditInterceptor’ın SaveChanges anında nasıl çalıştığı.
Soft Delete
Global query filter ve restore senaryoları.
Migrations
Bu DbContext’ten migration üretme ve uygulama.
Data Genel Bakış
Katmanın rolü, şemalar, klasör yapısı.