EF Core migration'larını production veritabanına uygulamanın resmî belgelerde önerilen iki yolu vardır: otomatik dağıtım için migration bundle, SQL'in deploy öncesi incelenmesi veya bir DBA'ya verilmesi gerektiğinde ise SQL script. Entity Framework Core'un dotnet ef database update komutu yerel geliştirme için en kolay yoldur; uygulamanın açılışta Migrate() çağırması da mümkündür, ama ikisi de production'da ek riskler taşır.
Bu yazıda dört stratejiyi belgelerdeki ölçütlerle karşılaştırıyor, SQL script ve idempotent script üretimini, bundle oluşturma ve çalıştırmayı, ortam değişkeni ve bağlantı dizesi yönetimini, çalışma zamanında migration'ın ödünleşimlerini ve EF Core 9 ile gelen migration kilidini anlatıyoruz. Migration ekleme ve kaldırma gibi günlük akış için EF Core migration rehberine, seriye genel bakış için EF Core öğrenme rehberi sayfasına bakabilirsiniz.
Önce: her stratejide geçerli kural
Hangi yolu seçerseniz seçin, belgeler üretilen migration'ları production'a uygulamadan önce incelemenizi ve test etmenizi ister. Bir migration, niyetiniz bir kolonu yeniden adlandırmakken onu silebilir; ya da farklı nedenlerle veritabanında başarısız olabilir. Pratikte bu, migration'ı önce production şemasının bir kopyasında denemek ve uygulamadan önce güncel bir yedek almak demektir. Yedekleme yöntemleri için veritabanı yedekleme stratejileri yazısına bakabilirsiniz.
Dört strateji karşılaştırması

Belgeler stratejileri şu ölçütlerle karşılaştırır: SQL'in çalıştırılmadan önce incelenip incelenemeyeceği, çalıştırma anında .NET SDK ve kaynak kodun gerekip gerekmediği, EF'in migration kilidinin kullanılıp kullanılmadığı ve UseSeeding gibi seed delegelerinin çalışıp çalışmadığı.
| Strateji | Önerilen kullanım | SQL incelenebilir | SDK ve kaynak gerekir | Migration kilidi | Seed delegeleri |
|---|---|---|---|---|---|
| SQL script | DBA kontrollü veya onaya bağlı deploy | Evet | Hayır | Hayır | Hayır |
| Migration bundle | Otomatik deploy | Hayır | Hayır | Evet | Evet |
| EF komut satırı araçları | Yerel geliştirme ve test | Hayır | Evet | Evet | Evet |
| Çalışma zamanında Migrate | Açılışta migration ödünleşimlerini kabul eden uygulamalar | Hayır | Hayır | Evet | Evet |
Tabloyu okurken iki şeye dikkat edin. Birincisi, SQL script EF Core dışında çalıştırıldığı için ne migration kilidinden ne de UseSeeding mantığından yararlanır; seed verisi gerekiyorsa migration işlemleri olarak ifade edilmelidir. Seed seçenekleri için data seeding yazısına bakın. İkincisi, senkron işlemler ve araçlar UseSeeding delegesini, asenkron işlemler ise UseAsyncSeeding delegesini çağırır; bundle ve araçlar senkron delegeyi kullandığı için uygulamanız asenkron çalışsa bile UseSeeding tanımlamanız gerekir.
SQL script üretmek
SQL script, deploy sürecinde üretilen SQL'in incelenmesi veya değiştirilmesi gerektiğinde önerilen stratejidir. Avantajları belgelerde şöyle sıralanır: script doğruluk açısından gözden geçirilebilir (production şemasını değiştirmek veri kaybı riski taşıdığı için bu önemlidir), bazı durumlarda production veritabanının özel ihtiyaçlarına göre ayarlanabilir, bir dağıtım teknolojisiyle birlikte kullanılıp CI içinde üretilebilir, bir DBA'ya verilebilir ve ayrıca arşivlenebilir.
En basit hâli, boş bir veritabanından son migration'a kadar tüm şemayı üreten script'tir. Komut varsayılan olarak script'i standart çıktıya yazar; dağıtım çıktısı olarak öngörülebilir adla bir dosya istiyorsanız --output (kısaca -o) seçeneğini kullanırsınız:
dotnet ef migrations script
dotnet ef migrations script --idempotent --output artifacts/migrations.sqlScript-Migration
Script-Migration -Idempotent -Output artifacts\migrations.sqlScript üretimi, hangi migration aralığının üretileceğini belirleyen iki argüman alır. from, script çalıştırılmadan önce veritabanına uygulanmış son migration olmalıdır; hiç migration uygulanmadıysa 0 verilir ve varsayılan da budur. to, script çalıştıktan sonra veritabanına uygulanmış olacak son migration'dır ve varsayılan olarak projenizdeki son migration'dır. Migration'ları ad veya kimlik (zaman damgalı tam ad) ile belirtebilirsiniz:
# AddNewTables'tan sonuncuya kadar
dotnet ef migrations script AddNewTables
# AddNewTables'tan AddAuditTable'a kadar
dotnet ef migrations script AddNewTables AddAuditTable
# yalnızca InitialCreate
dotnet ef migrations script 0 InitialCreatefrom değeri to değerinden daha yeni bir migration ise komut geri dönüş (rollback) script'i üretir; yani migration'ların Down işlemlerini yazar. Belgeler burada olası veri kaybı senaryolarına dikkat çeker: bir rollback script'i, ileri yöndeki migration'ın sildiği veya dönüştürdüğü veriyi genel olarak geri getiremez. Bu yüzden rollback'i de production şemasının bir kopyasında test etmelisiniz.
Migration script'leri var olan bir veritabanını günceller; veritabanının kendisini oluşturmaz. Belgeler veritabanını altyapı dağıtımınız veya veritabanı yönetim süreciniz üzerinden önceden hazırlamanızı söyler, çünkü veritabanı oluşturmak çoğunlukla farklı bir bağlantı, daha yüksek yetkiler ve sağlayıcıya özgü ayarlar gerektirir.
Idempotent script: veritabanının hangi migration'da olduğunu bilmiyorsanız
Normal script yalnızca bir migration'dan diğerine geçiş içindir; doğru durumda olan veritabanlarına uygulamak sizin sorumluluğunuzdadır. Idempotent script ise geçmiş tablosuna bakarak hangi migration'ların uygulandığını kendi içinde kontrol eder ve yalnızca eksik olanları çalıştırır. Veritabanına uygulanan son migration'ı tam bilmediğinizde ya da her biri farklı migration'da olabilecek birden çok veritabanına deploy ettiğinizde kullanışlıdır.
dotnet ef migrations script --idempotentScript üretirken kullanılabilecek bir seçenek daha var: --no-transactions seçeneği script'e SQL transaction ifadeleri eklenmesini engeller. Belgeler ayrıca SQL Server'da bir ifadenin batch'teki ilk veya tek ifade olması gerektiğinde ya da idempotent script'te o an tabloda bulunmayan kolonlara başvurulduğu için ayrıştırıcı hataları çıktığında EXEC kullanılabileceğini belirtir; bu da migration özelleştirme yazısında anlatılıyor.
İnceleme ve onay hattı
Production deploy'ları çoğu zaman şema değişikliği için onay ister. Belgelerin takım ortamı sayfası şu akışı tarif eder: CI'da idempotent script ve rollback script'i birlikte üretilir, çıktı olarak saklanır, bir inceleme aşamasında DBA tarafından onaylanır ve deploy aşamasında onaylanan dosyanın kendisi çalıştırılır. Deploy anında SQL'i yeniden üretmek yerine incelenmiş script'i uygulamak, onay verenin tam olarak çalışacak işlemleri onaylamasını garanti eder. Belgelerdeki örnek Azure DevOps onay ve kapılarını kullanır; aynı mantığı kendi CI sisteminizde kurabilirsiniz.
dotnet ef migrations script --idempotent -o artifacts/migrate.sql
dotnet ef migrations script PreviousMigration Latest -o artifacts/rollback.sqlKomut satırı araçları neden production için ideal değil?
dotnet ef database update (PMC'de Update-Database) veritabanını son migration'a ya da belirttiğiniz bir migration'a getirir; daha eski bir hedef vererek geri dönüş de yapabilirsiniz. Komut, hedef olarak verdiğiniz migration'ın veritabanının komut sonunda bulunacağı durumu belirttiğini varsayar: veritabanı daha yeni bir migration'daysa hedeften yeni olan her migration'ın Down işlemleri çalışır. Yerel geliştirme ve migration testi için çok verimlidir; ancak belgeler production için iki sorun sayar: SQL komutları geliştiriciye inceleme veya değiştirme fırsatı verilmeden doğrudan uygulanır ve production sunucularına .NET SDK ile EF aracının kurulması, ayrıca projenin kaynak kodunun bulunması gerekir.
dotnet ef database update
dotnet ef database update AddNewTablesOrtam ve yapılandırma: Development varsayılanına dikkat
Araçlar DbContext nesnesini oluşturmak için uygulama kodunuzu çalıştırır. Bu yüzden sağlayıcı seçimi, bağlantı dizesi ve model yapılandırması uygulamanın ortamına bağlı olabilir. Belgelerin vurguladığı nokta şudur: ne ASPNETCORE_ENVIRONMENT ne de DOTNET_ENVIRONMENT ayarlıysa EF Core tasarım zamanı araçları Development ortamını kullanır. Yani dikkat etmezseniz production bundle'ı geliştirme ayarlarıyla, hatta geliştirme user secrets değerleriyle üretilebilir. Belgeler, dağıtım çıktısını üretirken ve bundle'ı çalıştırırken ortamı açıkça ayarlamanızı ister:
ASPNETCORE_ENVIRONMENT=Production \
dotnet ef migrations bundle --output artifacts/efbundle
ASPNETCORE_ENVIRONMENT=Production \
./efbundle --connection "$DEPLOYMENT_CONNECTION_STRING"$env:ASPNETCORE_ENVIRONMENT = 'Production'
dotnet ef migrations bundle --output artifacts\efbundle.exeProduction bağlantı dizelerini kaynak kontrolüne koymayın ve bundle'ın içine gömmeyin. Dağıtım bağlantısını dağıtım sisteminizin gizli değer deposundan sağlayın; dağıtım kimliğinin şema yetkisi olmalı, normal uygulama kimliğinin genellikle olmamalıdır. Bağlantı dizelerini güvenli saklama yolları connection string yönetimi yazısında anlatılıyor.
Migration bundle: tek dosyalık dağıtım çıktısı

Migration bundle, migration'ları bir veritabanına uygulayan tek dosyalık bir çalıştırılabilir dosyadır. Belgeler bundle'ın SQL script ve komut satırı araçlarının bazı eksiklerini giderdiğini anlatır: SQL script çalıştırmak ek araç gerektirir; bu araçların transaction yönetimi ve hata sonrası devam etme davranışı tutarsız ve bazen beklenmedik olabilir, bu da bir hata anında veritabanını tanımsız bir durumda bırakabilir. Bundle ise CI içinde üretilip daha sonra deploy sürecinde çalıştırılabilir; .NET SDK, EF aracı ve kaynak kodu gerektirmez, self-contained üretilirse .NET Runtime bile gerekmez. Ayrıca EF Core'un migration kilidini kullanır ve yapılandırılmış UseSeeding mantığını çalıştırır.
dotnet ef migrations bundle --output artifacts/efbundle
dotnet ef migrations bundle --self-contained --target-runtime linux-x64 --output artifacts/efbundleBundle-Migration -Output artifacts\efbundle.exe
Bundle-Migration -SelfContained -TargetRuntime linux-x64 -Output artifacts\efbundleKendi Linux sunucunuzda çalışan bir uygulama için ikinci komut özellikle işe yarar: --target-runtime linux-x64 ile hedef sunucunun çalışma zamanı kimliğine (RID) uygun, --self-contained ile runtime'ı da içeren bir dosya üretirsiniz. Mevcut bir bundle'ın üzerine yazmak için --force kullanılır. Bundle'ın bir eksiği de var: SQL script'in aksine şu anda çalıştıracağı SQL'i incelemenin veya içerdiği migration'ları listelemenin bir yolu yok. Deploy sürecinizde SQL incelemesi zorunluysa script üretmelisiniz.
efbundle nasıl çalıştırılır?
Üretilen dosyanın varsayılan adı efbundle'dır ve veritabanını son migration'a getirir; davranış olarak dotnet ef database update ile eşdeğerdir. İsteğe bağlı <MIGRATION> argümanı hedef migration'ı belirtir; 0 verilirse tüm migration'lar geri alınır. Seçenekler:
| Seçenek | Açıklama |
|---|---|
| --connection <CONNECTION> | Veritabanı bağlantı dizesi. Varsayılan, AddDbContext veya OnConfiguring içinde belirtilendir. |
| --verbose (-v) | Ayrıntılı çıktı gösterir. |
| --no-color | Çıktıyı renklendirmez. |
| --prefix-output | Çıktı satırlarının başına seviye ekler. |
Belgelerdeki örnek oturumda bundle ilk çalıştırmada bir migration uygular, ikinci çalıştırmada uygulanacak yeni migration olmadığı için hiçbir şey yapmaz. Aşağıdaki çıktı belgelerin örnek çıktısıdır:
PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
Applying migration '20210903083845_MyMigration'.
Done.
PS C:\local\AllTogetherNow\SixOh> .\efbundle.exe
No migrations were applied. The database is already up to date.
Done.Varsayılan olarak bundle uygulamanızın yapılandırmasındaki bağlantı dizesini kullanır; --connection ile başka bir veritabanını hedefleyebilirsiniz. Geri dönüş için, uygulanmış kalması gereken migration'ı argüman olarak verirsiniz:
.\efbundle.exe PreviousMigration --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;Integrated Security=True'
.\efbundle.exe 0 --connection 'Data Source=(local)\MSSQLSERVER;Initial Catalog=Blogging;Integrated Security=True'Container ve deploy işleri
Belgelerin container önerisi açıktır: bundle'ı build sırasında üretin ve veritabanı sağlıklı hâle geldikten sonra tek seferlik bir deploy işi olarak çalıştırın. Uygulama imajına SDK kurmayın, orada dotnet ef çalıştırmayın ve her uygulama kopyasının giriş noktasından migration çalıştırmasına izin vermeyin. Dağıtım platformunu, migration container'ı başarıyla çıktıktan sonra yeniden başlatmayacak şekilde ayarlayın. Kendi sunucunuzda da aynı mantık geçerlidir: migration, uygulamanın yeni sürümünü başlatmadan önce çalışan ayrı bir adım olmalıdır. .NET uygulamasını sunucuda barındırma tarafı için .NET web hosting rehberi ve Windows hosting rehberi yazılarına bakabilirsiniz.
Çalışma zamanında Migrate() ve ödünleşimleri

Uygulamanın kendisi de migration'ları kodla, genellikle açılışta uygulayabilir. Belgelerdeki tipik örnek bir scope oluşturur, context'i alır ve MigrateAsync() çağırır:
public static async Task Main(string[] args)
{
var host = CreateHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
await db.Database.MigrateAsync();
}
host.Run();
}EF Core 9 ve sonrası migration'ı veritabanı genelinde bir kilitle koruduğu için bu yaklaşım, basit deploy'u tercih eden ve açılışta migration davranışını tolere edebilen uygulamalar için kabul edilebilir olabilir. Yine de belgeler gözden geçirme, en az yetkili kimlik, koordineli yayın veya yüksek erişilebilirlik önemliyse ayrı bir migration deploy adımını tercih eder. Sayılan ödünleşimler şunlardır:
- EF 9 öncesi sürümlerde birden çok uygulama örneği aynı anda migration uygulamaya çalışıp başarısız olabilir, daha kötüsü veri bozulmasına yol açabilirdi.
- Bir uygulama veritabanına erişirken başka bir uygulama onu migrate ediyorsa ciddi sorunlar çıkabilir.
- Uygulamanın şemayı değiştirebilmek için yükseltilmiş yetkiye sahip olması gerekir; production'da uygulama yetkilerini sınırlamak iyi bir uygulamadır.
- Bir sorun çıktığında uygulanmış migration'ı geri alabilmek önemlidir; diğer stratejiler bunu kolayca sağlar.
- SQL komutları inceleme veya değiştirme fırsatı olmadan doğrudan program tarafından uygulanır.
MigrateAsync(), ileri senaryolar için kullanılabilecek IMigrator servisinin üzerine kuruludur; servise myDbContext.GetInfrastructure().GetService<IMigrator>() ile erişebilirsiniz. Ayrıca EF Core 9'dan bu yana model bekleyen değişiklik içeriyorsa Migrate() ve MigrateAsync() istisna fırlatır; bunun nedenleri PendingModelChangesWarning yazısında anlatılıyor.
Migration kilidi (EF Core 9 ve sonrası)
EF Core 9'dan itibaren Migrate ve MigrateAsync, herhangi bir migration uygulamadan önce veritabanı genelinde bir kilit alır. Bu, birden fazla uygulama örneğinin aynı anda migration çalıştırmasından doğabilecek bozulmaya karşı koruma sağlar. Kilit, seed kodu dahil migration yürütmesi boyunca tutulur ve işlem bitince otomatik bırakılır. Kilit şu yollarda devreye girer: dotnet ef database update, Update-Database, migration bundle ve çalışma zamanında Migrate/MigrateAsync. SQL script'ler EF Core dışında uygulandığı için kilitten etkilenmez.
Kilit mekanizması sağlayıcılar arasında belirgin şekilde farklıdır. SQL Server, bağlantı kapanınca otomatik bırakılan oturum düzeyinde bir uygulama kilidi (sp_getapplock) kullanır. SQLite'ta yerleşik uygulama kilidi olmadığı için EF Core bir __EFMigrationsLock tablosu oluşturup satır ekleyerek kilit alır; süreç migration sırasında beklenmedik şekilde sonlanırsa bu satır temizlenmeyebilir ve sonraki migration'lar kilidin bırakılmasını süresiz bekler. Belgelere göre çözüm bu tabloyu düşürmek veya içindeki satırları silmektir:
DROP TABLE "__EFMigrationsLock";Kilidin bir sınırlaması daha var: MigrateAsync çağrısını açık bir transaction içine almak desteklenmiyor. EF Core 9 öncesinde dayanıklılık için yaygın olan “execution strategy içinde transaction başlat, migrate et, commit et” kalıbı artık bir uyarı istisnasına yol açıyor; çünkü dış transaction kilidin alınmasını engelliyor. Belgelerin önerisi dış transaction'ı ve execution strategy'yi kaldırıp yalnızca MigrateAsync çağırmaktır; EF transaction'ları ve execution strategy'yi zaten gerektiği gibi yönetiyor.
Transaction davranışında bir sürüm notu da önemlidir: EF Core çoğu durumda her migration'ı kendi transaction'ı içinde uygular. EF Core 9 bekleyen tüm migration'ları tek bir transaction içinde uygulamaya başlamıştı; bu değişiklik çeşitli migration senaryolarında sorun çıkardığı için EF Core 10'da geri alındı ve her migration yeniden kendi transaction'ına sarılıyor. Transaction'lar hakkında genel bilgi için EF Core transaction yönetimi yazısına bakabilirsiniz.
Hangi stratejiyi seçmeli?
- Tek sunucu, kendi yönettiğiniz deploy betiği: CI'da Linux için self-contained bundle üretin, yeni sürümü başlatmadan önce ortamı
Productionolarak ayarlayıp bağlantıyı gizli değer deposundan vererek çalıştırın. - DBA onayı gereken kurumsal ortam: Idempotent script ve rollback script'ini birlikte üretin, onaylanan dosyayı aynen çalıştırın. Seed verisini migration işlemleri olarak ifade edin.
- Küçük, tek örnekli uygulama: Açılışta
MigrateAsync()kabul edilebilir olabilir; ama uygulama kimliğinin şema yetkisine ihtiyaç duyacağını ve SQL'i inceleyemeyeceğinizi bilerek karar verin. - Yerel geliştirme:
dotnet ef database updateen basit yoldur.
Sık yapılan hatalar
- Ortam değişkenini ayarlamadan bundle üretmek ve geliştirme yapılandırmasıyla production'a gitmek.
- Bundle'ın yanına gereken
appsettings.jsondosyasını koymamak ya da bu dosyaya parola yazmak. - SQLite için idempotent script beklemek.
- Her uygulama replikasının açılışta migration çalıştırması.
MigrateAsyncçağrısını açık bir transaction içine almak.- Deploy anında SQL'i yeniden üretip onaylanmamış bir script çalıştırmak.
- Rollback'in veri kaybını geri getireceğini varsaymak.
Sık Sorulan Sorular
Bundle ile SQL script arasında nasıl seçim yapmalıyım?
Belgelere göre otomatik deploy için bundle, SQL'in incelenmesi, değiştirilmesi, arşivlenmesi veya bir DBA'ya verilmesi gerekiyorsa SQL script önerilir. Bundle kilit ve seed mantığını kullanır ama içeriğini incelemenize izin vermez; script ise incelenebilir ama ne kilidi ne de seed delegelerini çalıştırır.
Bundle çalıştırmak için sunucuda .NET kurulu olmalı mı?
Bundle .NET SDK ve EF aracı gerektirmez. --self-contained ile üretirseniz .NET Runtime da bundle içine alınır ve sunucuda kurulu olması gerekmez.
Aynı bundle'ı iki kez çalıştırırsam ne olur?
Migration'lar yalnızca daha önce uygulanmamışsa uygulanır. Belgelerin örnek oturumunda ikinci çalıştırma veritabanının güncel olduğunu bildirir ve hiçbir şey yapmaz.
Migration sırasında veritabanını kim oluşturur?
SQL script'ler var olan bir veritabanını günceller; belgeler veritabanını altyapı veya veritabanı yönetim süreciyle önceden hazırlamanızı önerir. Yerel geliştirmede ise belgelerin başlangıç örneğinde dotnet ef database update veritabanını ve şemayı ilk migration'dan oluşturur.
Marka adları sahiplerine aittir. Bu yazı bağımsız bir teknik rehberdir; adı geçen kuruluşlarla bayilik veya ortaklık ilişkisi bulunduğu anlamına gelmez.
İlgili içerikler: EF Core öğrenme rehberi · EF Core migration rehberi · Migration özelleştirme · Pending model changes hatası · Veritabanı yedekleme stratejileri · .NET web hosting