Transaction sınırı, repository metotlarının kaç satır yazdığıyla değil, iş işleminin hangi değişiklikleri birlikte tamamlaması gerektiğiyle belirlenir. Sipariş kaydı ve ona ait audit kaydı birlikte başarılı olmalıysa bu bir iş birimidir. İki repository’nin bağımsız SaveChanges çağrıları aynı garantiyi kendiliğinden kurmaz.
EF Core’da transaction destekleyen provider üzerinde tek SaveChanges çağrısındaki değişiklikler atomik uygulanır. Bu nedenle her basit kayıt işlemine ayrıca explicit transaction eklemek gerekmez. İki save, aradaki sorgu veya farklı context koordinasyonu varsa kapsam yeniden değerlendirilmelidir.
Transaction sınırı için işin başarı tanımını yazmak
Bir sipariş oluşturma endpoint’i yalnızca sipariş tablosuna kayıt ekliyor gibi görünebilir. Ancak iş beklentisi siparişle birlikte audit, rezervasyon veya başka kayıtların da oluşması olabilir. Önce hangi değişikliklerin birlikte başarılı sayılacağını belirlemek gerekir. Sipariş var ama audit yok durumu kabul ediliyor mu? Audit teknik teşhis için mi, zorunlu denetim kaydı için mi tutuluyor? Bu iki durumda hata davranışı farklı olabilir. Transaction sınırını repository metodunun adına göre çizmek yerine başarı tanımını business anlamıyla yazmak, doğru kapsamı bulmayı kolaylaştırır.
Yerel database üzerinde birlikte korunması gereken iki değişiklik varsa tek iş birimi tasarlanabilir. Ancak farklı kullanım senaryolarında aynı tabloların bulunması onları her zaman ortak transaction’a almak gerektirmez. Siparişin açıklamasını değiştirme işlemiyle dönem sonu raporu üretme işleminin başarı koşulları farklıdır. Transaction bir katman şablonu değil belirli bir iş akışının garantisidir. Bu yüzden application service’in hangi adımları koordine ettiğini incelemek gerekir. Veriyi kaydeden alt metodun içinde commit saklanmışsa caller’ın garanti alanı belirsizleşebilir. Ortak isimler gerçek koordinasyonun yerini tutmaz.
Üç adımlı bir akış düşünelim: Sipariş ekleniyor, audit kaydı oluşturuluyor ve müşteriye bildirim gönderiliyor. İlk iki adım aynı relational database’de olabilir. Bildirim ise harici bir sistemde gerçekleşir. Üçünün birlikte başarılı olması istense bile local transaction üçüncü adımı otomatik geri alamaz. Bu fark tasarımın başında açık yazılmalıdır. Başarı yanıtı “sipariş kaydedildi ve bildirim kuyruğa alındı” anlamına gelebilir. “Müşteri bildirimi kesin aldı” daha farklı bir garanti ister. Yanıtın anlamını abartmak teknik hata kadar ciddi bir davranış sorunudur.
Tercihim: Koordinasyon gerektiren iş biriminin commit kararını application işleminin vermesi. Bu seçim transaction’ın neden açıldığını ve hangi değişiklikleri kapsadığını görünür tutar. Bedeli, persistence sınırının application tarafından uygun bir contract üzerinden yönetilmesi ve lifetime’ın tutarlı olmasıdır. Küçük bir işlem tek SaveChanges ile tamamlanıyorsa explicit transaction eklemem. Birden fazla save, ara query veya birden fazla context varsa tekrar değerlendiririm. Gereken en kısa kapsamı kurmak, her repository metodunda transaction açmaktan daha anlaşılır davranış üretir.
SaveChanges ve explicit transaction farkını okumak
Tek SaveChanges çağrısına kadar biriken değişiklikler, transaction destekleyen provider üzerinde atomik kaydedilebilir. Bu nedenle iki entity eklenmiş olması iki explicit transaction gerektirmez. Önce bu varsayılan davranışın iş için yeterli olup olmadığına bakın. Birinci SaveChanges ile kimlik üretip sonra ikinci adımı tamamlamak gibi ihtiyaçlarda birden fazla save bulunabilir. Bu adımlar birlikte korunacaksa kapsam ayrıca tasarlanır. Otomatik transaction ile explicit transaction farklı koordinasyon alanlarıdır. Kullandığınız provider’ın desteklediği davranışı doğrulamak, genel bir Unit of Work sınıfına güvenmekten daha somut bir kontroldür.
Explicit transaction açıldığında commit’in sahipliği belirgin olmalıdır. İç servisler aynı kapsam içinde çalışıyorsa hangisi transaction oluşturuyor, hangisi yalnızca katılıyor? Bir alt metot kendi başına commit yaparsa caller’ın henüz tamamlanmamış diğer adımları için garanti bozulabilir. Aynı şekilde iç metot transaction’ı dispose ederse dış kapsam kullanılamaz hale gelebilir. Bu nedenle ownership, yalnızca dependency injection lifetime’ıyla açıklanamaz. Metotların davranış contract’ında ve çağrı düzeninde görünmelidir. “Bütün servisler Unit of Work kullanıyor” ifadesi bu ayrıntıların doğru olduğunu kanıtlamaz.
Birden fazla save için açık kapsam
Aşağıdaki .NET 10 console örneği EF Core SQLite 10.0.12 kullanır. dotnet add package Microsoft.EntityFrameworkCore.Sqlite --version 10.0.12 ile paketi ekleyin. İkinci kayıttan sonra oluşan hata, transaction’ın commit edilmesini engeller. Son kontrol yeni context üzerinden hiçbir satırın kalmadığını doğrular.
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
await using var connection = new SqliteConnection(
"Data Source=:memory:"
);
await connection.OpenAsync();
var options = new DbContextOptionsBuilder<OrdersDb>()
.UseSqlite(connection)
.Options;
await using (var db = new OrdersDb(options))
{
await db.Database.EnsureCreatedAsync();
try
{
await using var tx = await db.Database.BeginTransactionAsync();
db.Orders.Add(new OrderRow { Description = "Keyboard" });
await db.SaveChangesAsync();
db.Audits.Add(new AuditRow { Message = "Order created" });
await db.SaveChangesAsync();
throw new DemoFailure();
}
catch (DemoFailure)
{
Console.WriteLine("Simulated failure before commit.");
}
}
await using var verification = new OrdersDb(options);
if (
await verification.Orders.AnyAsync()
|| await verification.Audits.AnyAsync()
)
throw new Exception("Rollback failed.");
Console.WriteLine("Both writes rolled back.");
public sealed class DemoFailure : Exception;
public sealed class OrderRow
{
public int Id { get; set; }
public string Description { get; set; } = "";
}
public sealed class AuditRow
{
public int Id { get; set; }
public string Message { get; set; } = "";
}
public sealed class OrdersDb(DbContextOptions<OrdersDb> options)
: DbContext(options)
{
public DbSet<OrderRow> Orders => Set<OrderRow>();
public DbSet<AuditRow> Audits => Set<AuditRow>();
}
Buradaki catch yalnızca demoda üretilen hata tipini yakalar. Bütün exception’ları yutup başarılı sonuç dönmez. await using, commit edilmemiş transaction’ı dispose eder; provider rollback davranışı bu örnekte gerçek SQLite ile kullanılır.
Repository commit yapmalı mı?
Tercihim, birden fazla değişikliği koordine eden application işleminin commit noktasını belirlemesi. Repository aggregate’i yükleyebilir veya değişikliği context’e ekleyebilir. Her metotta bağımsız commit yaparsa caller’ın atomik iş birimini sürdürmesi zorlaşır. Tek bir scoped DbContext, birçok uygulamada ayrıca generic Unit of Work wrapper’ı gerektirmeden bu koordinasyonu karşılar.
Bu tercih, bütün servislerin transaction’ı rastgele açabileceği anlamına gelmez. Sınır açık olmalı; nested çağrılar aynı transaction’a katılıyorsa ownership ve disposal sorumluluğu belirlenmelidir. Uzun süren bir iş için transaction’ı kullanıcı etkileşimi veya uzak servis beklemesi boyunca açık tutmak lock süresini artırır.
Database ile dış çağrı aynı kapsamda değildir
Sipariş commit edildikten sonra e-posta gönderimi başarısız olabilir. E-postayı önce gönderirsek bu kez database commit’i başarısız olabilir. Local transaction, dış sistemin davranışını geri almaz. Yayın niyetini iş verisiyle birlikte saklayan outbox veya iş gereksinimine uygun compensation seçenekleri burada değerlendirilir.
Retry de kapsamı etkiler. Provider execution strategy kullanılıyorsa explicit transaction’ı desteklenen strategy akışı içinde yürütmek gerekir. Commit yanıtının kaybolması halinde işlemin gerçekten tamamlanıp tamamlanmadığı belirsiz olabilir; idempotent iş kimliği bu riski azaltır. EF Core connection resiliency rehberi bu etkileşimi açıklıyor.
Data ownership yazısındaki modül ayrımıyla transaction sınırını birlikte düşünün. Ortak database kullanmak bütün tabloları aynı iş işlemine dahil etmeyi zorunlu kılmaz. Garanti gereken değişiklikleri belirleyip en kısa yeterli kapsamı kurmak, transaction’ı her katmanda tekrar açmaktan daha anlaşılırdır.
Rollback örneği hangi başarısızlığı gösteriyor?
Kod önce SQLite in-memory database’e açık bağlantı oluşturuyor. Bu bağlantı iki context arasında database’in yaşamını koruyor. İlk context schema’yı hazırladıktan sonra explicit transaction açıyor. Sipariş kaydı ekleniyor ve SaveChanges çalışıyor. Ardından audit kaydı eklenip ikinci SaveChanges tamamlanıyor. Bu noktada iki kayıt database işlemine gönderilmiş olsa da transaction commit edilmemiştir. Sonra yalnızca örnek için kullanılan DemoFailure atılıyor. Transaction scope tamamlanmadan hata oluştuğu için commit gerçekleşmiyor. await using ile scope sonlandığında transaction dispose ediliyor.
Kontrol için yeni context açılıyor ve iki tabloda da kayıt bulunmaması bekleniyor. Bu kontrol önceki context’in change tracker durumuna bakmaz; database’den okur. Dolayısıyla örnek, commit öncesindeki simüle edilmiş application hatasında iki yazmanın geri alındığını gerçek SQLite üzerinden gösterir. Database bağlantısının tam commit anında kesilmesi, process’in zorla kapanması veya farklı provider’ın davranışı bu koşumda uygulanmamıştır. Testin geçmesi bütün failure ihtimallerinin doğrulandığını göstermez. Rollback örneğinin kapsamını bu şekilde sınırlandırmak transaction garantisini daha doğru anlatır.
Catch yalnızca DemoFailure tipini yakalar. Beklenmeyen provider hatasını sessizce başarıya dönüştürmez. Production kodunda bütün exception’ları yakalayıp boş response vermek, işin kısmi veya belirsiz sonucunu gizleyebilir. Hata logging’i ile istemciye verilecek yanıt birbirinden ayrılmalıdır. İç hata ayrıntısını istemciye açmamak gerekir; fakat operasyon kaydında neden kaybolmamalıdır. Ayrıca bir transaction başarısız olduktan sonra aynı context ile devam edilip edilmeyeceği dikkatle ele alınmalıdır. Database rollback, change tracker’ın tüm state’ini eski haline çevirdiğini varsayma hakkı vermez.
Application service, repository ve Unit of Work rolleri
Application service kullanım senaryosunun adımlarını bir araya getirebilir: İlgili veriyi yüklemek, domain davranışını çağırmak, değişiklikleri persistence’a taşımak ve commit’i koordine etmek. Repository ise aggregate veya query contract’ına uygun veri erişimini sağlayabilir. Unit of Work abstraction’ı commit gibi ortak işlemi sınırlandırabilir. Bu roller her projede üç ayrı sınıf gerektirmez. Aynı sorumluluklar küçük bir feature içinde daha sade düzenlenebilir. Önemli olan hangi kararın nerede verildiğinin açık olmasıdır. Roller yalnızca sınıf adlarında bulunuyorsa tasarım davranış açısından açıklanmamıştır.
Repository’nin Add metodu entity’yi context’e ekleyip commit’i caller’a bırakabilir. Bunun avantajı birkaç değişikliğin tek iş biriminde tamamlanabilmesidir. Bedeli, caller’ın mutlaka uygun commit noktasına ulaşması gerekliliğidir. Metodun adından verinin kalıcı hale geldiği anlaşılmıyorsa contract yorumunda bu davranış belirtilmelidir. Başka bir repository’nin Add metodunun hemen SaveChanges yapması aynı uygulamada sürpriz yaratır. Tutarlılık yalnızca bütün interface’lerin aynı isimde olması değil, benzer işlemlerin benzer kayıt semantiği taşımasıdır. Farklı davranış gerekiyorsa isim ve kapsam bunu göstermelidir.
Generic Unit of Work wrapper’ı bazen persistence bağımlılığını tüketiciden gizlemek için anlamlı olabilir. Ancak sadece context’in SaveChanges metodunu yeniden adlandırıyorsa bu katmanın bakım faydası sorgulanmalıdır. Farklı repository’ler farklı context instance kullanıyorsa tek wrapper onları atomik hale getirmez. Ortak transaction gereksinimi gerçek connection ve provider davranışıyla çözülür. Buna karşılık business işleminin tek context üzerinde açık commit yapması küçük bir uygulamada yeterli olabilir. Sade çözümün sınırları kabul edilerek seçilmesi, gelecekteki bütün ihtiyaçları soyutlamak için büyük bir framework üretmekten daha kontrollüdür.
Transaction süresini neden kısa tutmalıyız?
Transaction içinde database lock veya başka kaynaklar tutulabilir. Uzak bir HTTP çağrısının yanıtını beklerken bu kapsam açık kalırsa süre uzar. Bu durum diğer işlemlerin gecikmesini artırabilir; etkisi provider’a, isolation’a ve workload’a bağlıdır. Ölçmeden sabit performans sonucu vermek doğru değildir. Ancak transaction’ın içine hangi beklemelerin konduğunu review’da görmek gerekir. Müşterinin ekrandaki başka bir adımı tamamlaması boyunca aynı database transaction’ını açık tutmak genellikle iş süreciyle teknik scope’u yanlış eşleştirir. Uzun iş akışı ayrı kalıcı state’lerle yönetilebilir.
Kapsamı kısaltırken de kuralları iki bağımsız işlemin arasına dağıtmamaya dikkat edin. Kontrolü transaction dışında yapıp değişikliği içeride uygulamak, kontrol ile yazma arasında veri değişmesine izin verebilir. Örneğin stok miktarını önce okuyup uzun bir işlemden sonra azaltmak doğru concurrency garantisini sağlamayabilir. Burada “kısa transaction” tek başına çözüm değildir. Koşul ve değişikliğin birlikte korunması gerekir. İş kuralı için atomik update, uygun concurrency token veya provider’a uygun isolation seçilebilir. Transaction süresiyle tutarlılık ihtiyacı birlikte değerlendirilmelidir.
Isolation ile atomikliği aynı kavram sanmamak
Atomiklik, kapsamdaki değişikliklerin birlikte uygulanması veya uygulanmamasıdır. Isolation ise eşzamanlı işlemlerin birbirlerinin state’ini nasıl gördüğüyle ilgilidir. Bir transaction açılmış olması her okuma-yazma yarışını önlemez. Aynı değeri iki işlem okuyup farklı sonuçla kaydedebilir. Kullanılan isolation seviyesinin garanti ettiği davranış provider’a göre incelenmelidir. Default ayarların bütün business invariant’lara uygun olduğunu varsaymak risklidir. Bunun yanında en güçlü isolation’ı her yere koymak da contention ve retry maliyetini artırabilir. Hangi anomalinin önlenmesi gerektiğini belirlemek kararın başlangıcıdır.
Örneğin iki yönetici aynı siparişin durumunu değiştirmeye çalışıyorsa optimistic concurrency ile eski sürüme dayalı yazma reddedilebilir. Bu durumda transaction rollback ile kullanıcıya çatışma yanıtı birlikte düşünülür. Ancak miktar limitini birden fazla kayıt toplamıyla kontrol eden başka bir kural daha farklı bir strateji gerektirebilir. Tek bir concurrency token bütün çok kayıtlı invariant’ları otomatik korumaz. İş kuralının hangi veriyi aynı anda kapsadığını açık yazın. Uygun test fixture’ı üzerinde paralel işlemleri gerçekten çalıştırarak seçilen stratejinin davranışını gözleyin.
Retry bütün iş birimini tekrar çalıştırabilir
Geçici bağlantı hatalarında provider execution strategy işlem tekrarını yönetebilir. Explicit transaction kullanıldığında bunun desteklenen strategy akışıyla uyumlu kurulması gerekir. Fakat retry yalnızca SaveChanges satırının yeniden denenmesi gibi düşünülmemelidir. Bazı düzenlerde bütün iş birimi tekrar çalışır. Bu birim içinde e-posta gönderme, ödeme başlatma veya başka harici yan etki bulunuyorsa ikinci etki oluşabilir. Dolayısıyla retry kapsamının içinde hangi adımların yer aldığı incelenmelidir. Database hatası için kurulmuş politika, dış sistemde aynı davranışın güvenli olduğunu kanıtlamaz.
Commit sırasında bağlantı kesilirse caller sonucun kesin başarısız olduğunu bilemeyebilir. Database commit etmiş ama yanıt kaybolmuş olabilir. Aynı siparişi tekrar oluşturmak duplicate kayıt üretebilir. Business işlem kimliği, uygun unique constraint ve önceki sonucu bulma davranışı belirsizliği yönetmeye yardımcı olabilir. Ancak kimlik eklemek tek başına bütün tekrar politikasını tamamlamaz. Aynı kimlikle farklı payload geldiğinde ne olacağı da belirlenmelidir. Bu makalenin rollback örneğinde commit denenmediği için belirsiz commit senaryosu çalıştırılmamıştır. İki failure türünü ayrı test ve tasarım konusu olarak tutmak gerekir.
Harici yan etkiler için niyet kaydı ve telafi
Sipariş kaydı sonrasında bildirim gönderilecekse bildirim niyetini aynı local transaction içinde saklamak değerlendirilebilir. Ayrı worker bu niyeti daha sonra işler. Böylece commit ile gönderim arasındaki process kapanması için kalıcı iz bulunur. Ancak bu düzen müşterinin bildirimi tek sefer almasını kendiliğinden garanti etmez. Worker gönderimi tamamlayıp işlendi işaretini kaydetmeden kapanırsa tekrar oluşabilir. Bildirim türüne göre duplicate kabul edilebilir veya uygun tekrar önleme gerekir. Transaction kapsamının dışında kalan davranışların ayrı contract ve operasyon alanı bulunduğu açık olmalıdır.
Ödeme gibi business etkisi yüksek işlemlerde compensation gerekebilir. Telafi, database rollback ile aynı şey değildir. Daha önce başarılı tahsilatı geri almak ayrı bir işlem ve ayrı başarısızlık ihtimalidir. Bu nedenle “hata olursa geri alırız” cümlesi yeterli tasarım açıklaması olmaz. Telafinin ne zaman başlatıldığı, tekrarının güvenli olup olmadığı ve tamamlanamayan işlemin nasıl görüldüğü belirlenmelidir. İş süreci kalıcı state ile takip edilebilir. Teknik transaction’ın sınırını business sürecinin tamamına yaymak yerine her adımın garantisini açıkça kurmak gerekir.
Cancellation ve kullanıcıya verilen yanıt
İstemci bağlantıyı kapattığında request token iptal olabilir. Token database çağrılarına aktarılabilir; fakat commit tamamlandıysa iptal sinyali geçmişteki değişikliği geri almaz. İşlem sonucu istemciye ulaşmadığında kullanıcı tekrar deneme yapabilir. Bu durumda başarılı yazmanın kimliği ve durum sorgulama imkânı önemlidir. Cancellation’ı doğrudan “hiçbir şey kaydedilmedi” sonucuna dönüştürmeyin. İptal zamanı ve işlem sınırı birlikte değerlendirilmelidir. Özellikle komut yan etkiliyse istemcinin yeniden denemesi için açık sözleşme bulunmalıdır. Request yaşamı ile business işlem yaşamı her zaman aynı değildir.
Background job içinde de cancellation scope’u önemlidir. Host durdurulurken işlem hangi noktada bırakılabilir? Transaction tamamlanmadan çıkılıyorsa provider davranışı ve job’ın tekrar alınması gerekir. Commit olmuş ama job tamamlandı işareti yazılmamışsa tekrar aynı etkiyi üretebilir. Bu yüzden graceful shutdown, local transaction ve job idempotency birlikte düşünülür. Tek bir token parametresi bu koordinasyonu çözmez. Worker’ın neyi garanti ettiği ve hangi işin yeniden denenebileceği açık yazılmalıdır. Bu makaledeki console kodu host shutdown akışı içermediğinden böyle bir davranış doğrulanmış değildir.
Failure testlerini doğru noktaya yerleştirmek
Commit öncesindeki application hatası, ilk SaveChanges sırasındaki constraint ihlali ve commit yanıtı kaybı farklı test senaryolarıdır. Birini simüle ederek hepsinin davranışını doğruladığınızı söylemeyin. Örnekte hata iki SaveChanges sonrasında, commit öncesinde üretiliyor. Başka bir test unique constraint ihlaliyle ikinci kaydın başarısızlığını kontrol edebilir. Paralel yazma testi concurrency stratejisini sınayabilir. Provider farklıysa hedef engine üzerinde uygun integration testi gerekir. Fixture’ın gerçek hata zamanlamasını ne kadar temsil ettiği raporda açıklanmalıdır. Güvence test sayısından çok gözlenen davranışa dayanır.
Rollback sonrasında yalnızca sipariş tablosuna bakmak audit kaydının da geri alındığını göstermez. Kapsamdaki bütün business etkileri kontrol edin. Yeni context kullanmak, eski change tracker’ın görüntüsüne yanlış güveni azaltır. Bunun yanında harici sistemdeki etkiyi local query ile doğrulayamazsınız. Fake servis kullanılmışsa onun neyi temsil ettiğini belirtin. Gerçek ödeme veya mesaj broker’ı çalıştırılmadığında testin integration kapsamı sınırlı kalır. Bu sınırı dürüstçe yazmak güvenceyi azaltmaz; hangi davranışın henüz doğrulanması gerektiğini anlaşılır hale getirir.
Migration ve toplu veri düzeltmesini request transaction’ından ayırmak
Schema migration veya büyük veri düzeltme işi, normal sipariş request’iyle aynı transaction beklentisini taşımayabilir. Büyük bir tabloda bütün kayıtları tek kapsamda değiştirmek uzun lock ve kaynak tüketimi oluşturabilir. Batch yaklaşımı seçildiğinde ise işlemin kısmi tamamlanması ve tekrar başlatılması düşünülmelidir. Bu nedenle request başına atomiklik kararını bütün bakım işlemlerine aynı biçimde taşımayın. Veri düzeltmenin business etkisi, hangi kayıtların değiştiği ve işlemin kaldığı yerden devam davranışı ayrı belgelenmelidir. Buradaki demo schema oluşturmayı iş transaction’ından önce yapar; migration rollback davranışını sınamaz.
Bir production düzeltmesinde başarılı batch’ler ile başarısız batch’in nasıl ayırt edildiği önemlidir. İş kimliği veya ilerleme kaydı kullanılabilir; fakat bunların kendisi de tutarlı kaydedilmelidir. Çalıştırılan kodun ve veri koşullarının izlenebilir olması geri dönüş değerlendirmesine yardımcı olur. Database transaction’ı açık olsa bile dışarı aktarılan rapor veya gönderilmiş mesaj geri alınmış sayılmaz. Bakım işinde de garanti alanı gerçek sistem sınırlarına göre yazılmalıdır.
Operation sırasında görülebilmesi gereken durumlar
Log kaydında iş kimliği, transaction’ın kapsadığı kullanım senaryosu ve hata nedeni ilişkilendirilebilir. Hassas payload’ı kaydetmek yerine teşhis için gerekli alanları seçin. Retry sayısı, transaction süresi ve concurrency çatışması ayrı sinyaller olabilir. Her failure aynı seviyede alarm üretmemelidir; kullanıcı kaynaklı iş reddi ile database erişim sorunu farklı durumdur. Ölçüm olmadan transaction süresi için evrensel eşik vermeyin. Uygulamanın workload ve gecikme beklentisini esas alın. Operasyon verisi, tasarımda kabul edilen trade-off’un gerçekte nasıl çalıştığını gösterir.
Review’da transaction açan bütün katmanları değil gerçek iş sınırını izleyin. Hangi kayıtlar birlikte korunuyor, hangi adım dış sistemde gerçekleşiyor, commit’i kim veriyor ve retry neyi tekrar ediyor? Sonra bu cevapların testlerle ne kadar doğrulandığını değerlendirin. Transaction sınırı açık olduğunda repository ve Unit of Work tercihleri bu amacı destekleyen araçlara dönüşür. Sınıf şeması önce seçilip garanti sonradan varsayıldığında ise kısmi başarı ve belirsiz sonuçlar kolayca gizlenir. En basit yeterli kapsam, business sonucu doğru ifade eden ve failure yolunda da korunabilen kapsamdır.
