EF Core “pending model changes” hatası, modelinizde son migration'a yansımamış bir değişiklik varken migration uygulamaya çalıştığınızda alınır: EF Core 9'dan itibaren dotnet ef database update, Migrate() ve MigrateAsync() bu durumda istisna fırlatır. Entity Framework Core bu hatayı RelationalEventId.PendingModelChangesWarning olay kimliğiyle üretir. En sık nedeni bir model değişikliğinden sonra migration eklemeyi unutmaktır ve çözümü yeni bir migration eklemektir; ama belgeler, migration eklemenin işe yaramadığı başka nedenler de sayar.
Bu yazıda hatanın tam metnini, neden EF Core 9 ile ortaya çıktığını, belgelerde listelenen altı nedeni ve her birinin çözümünü, hatayı deploy öncesinde CI'da yakalamayı ve uyarıyı bastırmanın ne zaman kabul edilebilir olduğunu anlatıyoruz. Aynı ailede iki komşu hatayı da ele alıyoruz: açık transaction içinde migration uygulama uyarısı ve geliştirme aşamasındaki EF Core 11'de gelen “migration bulunamadı” davranışı. Migration'ın günlük akışı için EF Core migration rehberine, serinin tamamı için EF Core öğrenme rehberi sayfasına bakın.
Hata mesajı

Belgelerde yer alan hata metni şöyledir; buradaki context adı sizin projenizde kendi DbContext sınıfınızın adıyla görünür:
The model for context 'DbContext' has pending changes. Add a new migration before updating the database. This exception can be suppressed or logged by passing event ID 'RelationalEventId.PendingModelChangesWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.Mesaj iki şey söyler: önerilen çözüm yeni bir migration eklemektir ve bu bir “uyarı” olayıdır; yani ConfigureWarnings ile bastırılabilir ya da yalnızca loglanabilir. Bastırmanın neden genellikle doğru olmadığına aşağıda değineceğiz.
Neden EF Core 9 ile başladı?
EF Core 9 öncesinde, model son migration'a göre değişmişse bu değişiklikler Migrate() çağrısında diğer migration'larla birlikte uygulanmaz, sessizce atlanırdı; migration'lar uygulandıktan sonra bile veritabanı şeması modelin beklediğinden farklı kalabilirdi. Belgeler değişikliğin gerekçesini şöyle açıklar: model değişikliğinden sonra migration eklemeyi unutmak yaygın ve bazı durumlarda teşhisi zor bir hatadır; yeni istisna, migration'lar uygulandıktan sonra uygulamanın modelinin veritabanıyla eşleşmesini garanti eder. Belgelerin EF Core 9 kırıcı değişiklik listesinde bu madde yüksek etkili olarak işaretlenmiştir.
Önemli bir ayrım: bu kontrol migration'ı uygulayan yollarda yapılır. dotnet ef migrations script ile üretilen SQL script'i bir SQL aracıyla çalıştırdığınızda EF Core devrede olmadığı için bu kontrol de yoktur. Bu, script ile deploy eden ekiplerin de kontrolü kendilerinin yapması gerektiği anlamına gelir; aşağıdaki CI bölümü bunun içindir.
Nedenler ve çözümleri

Belgeler istisnanın atıldığı yaygın durumları ve her biri için önerilen çözümü listeler. Hatayı aldığınızda bu listeyi sırayla gözden geçirmek, teşhisin en hızlı yoludur.
| Durum | Belirti | Önerilen çözüm |
|---|---|---|
| Hiç migration yok | Şema başka yollarla yönetiliyor ama Migrate çağrılıyor | Migration kullanmayacaksanız Migrate çağrısını kaldırın; kullanacaksanız migration ekleyin |
| Migration var, snapshot yok | Migration elle oluşturulmuş | EF araçlarıyla yeni migration ekleyin; snapshot güncellenir |
| Model deterministik değil | Her migration eklemede aynı değişiklik tekrar çıkıyor | HasData içindeki dinamik değerleri sabit değerlerle değiştirin |
| Farklı sağlayıcı | Son migration başka sağlayıcı için üretilmiş | Her sağlayıcı için ayrı migration seti tutun |
| EF servisleri değiştirilmiş | Migration'lar dinamik üretiliyor veya seçiliyor | Yanlış pozitiftir; uyarıyı bastırın |
| ASP.NET Core Identity seçenekleri | Modeli etkileyen Identity seçenekleri tasarım zamanında uygulanmıyor | Uygulamayı başlangıç projesi yapın veya design-time factory yazın |
1. Hiç migration yok
Veritabanını migration dışında, örneğin elle yazılmış SQL ile ya da başka bir araçla güncelliyorsanız ama kodda yine de Migrate() veya MigrateAsync() çağırıyorsanız bu durum ortaya çıkar. Migration ile şema yönetmeyi planlamıyorsanız çağrıyı kaldırın; planlıyorsanız ilk migration'ı ekleyin. Var olan bir veritabanıyla başlıyorsanız modeli scaffold ile üretmek de bir seçenektir.
2. Migration var ama model snapshot eksik
Bu genellikle elle oluşturulmuş migration'larda görülür: migration sınıfı vardır, ancak EF araçlarının ürettiği ModelSnapshot dosyası yoktur ya da güncel değildir. Çözüm, EF araçlarıyla yeni bir migration eklemektir; bu işlem snapshot'ı günceller. Snapshot'ın ne işe yaradığı migration rehberinde anlatılıyor.
3. Model deterministik olmayan biçimde kuruluyor
Bu, en kafa karıştırıcı durumdur: modeli siz değiştirmediniz, ama model her oluşturulduğunda farklı göründüğü için EF onu değişmiş sayar. Belgelere göre bu, HasData ile verilen nesnelerde new DateTime(), DateTime.Now, DateTime.UtcNow veya Guid.NewGuid() kullanıldığında sık görülür. Örneğin aşağıdaki gibi bir yapılandırma, her model oluşturulduğunda farklı bir değer üretir:
// Sorunlu: her model oluşturulduğunda farklı değer
modelBuilder.Entity<Blog>().HasData(
new Blog { Id = 1, Name = "Duyurular", CreatedTimestamp = DateTime.UtcNow });
// Düzeltilmiş: sabit değer
modelBuilder.Entity<Blog>().HasData(
new Blog { Id = 1, Name = "Duyurular", CreatedTimestamp = new DateTime(2025, 1, 1) });Belgelerin önerdiği teşhis yöntemi şudur: yeni bir migration ekleyin ve içeriğini inceleyerek nedeni bulun; siz hiçbir şey değiştirmediğiniz hâlde migration'da seed değerlerinizle ilgili işlemler görüyorsanız iz doğrudur. Ardından dinamik değeri modelde sabit, kod içine yazılmış bir değerle değiştirin ve model düzeldikten sonra migration'ı yeniden oluşturun (teşhis için eklediğiniz migration'ı kaldırıp yeniden ekleyin). Seed için gerçekten dinamik veri gerekiyorsa HasData yerine EF Core 9 ile gelen UseSeeding ve UseAsyncSeeding kalıbını kullanın. Belgeler HasData'yı artık “model tarafından yönetilen veri” olarak adlandırır ve DateTime.Now gibi sabit ve deterministik olmayan verilerin bu özellik için uygun olmadığını açıkça belirtir. Seed seçenekleri data seeding yazısında karşılaştırılıyor.
4. Son migration başka bir sağlayıcı için üretilmiş
Migration'ları SQL Server ile üretip SQLite veritabanına uygulamaya çalışmak gibi. Belgeler bunun desteklenmeyen bir senaryo olduğunu söyler: uyarı bastırılabilir, ancak bu yolun gelecekteki bir EF Core sürümünde muhtemelen çalışmayı bırakacağı belirtilir. Önerilen çözüm her sağlayıcı için ayrı bir migration seti üretmektir; nasıl yapılacağı migration özelleştirme yazısında anlatılıyor.
5. Migration'lar EF servisleri değiştirilerek üretiliyor veya seçiliyor
Bazı ileri senaryolarda EF Core'un iç servisleri değiştirilerek migration'lar dinamik olarak üretilir, değiştirilir veya seçilir. Belgelere göre bu durumda uyarı bir yanlış pozitiftir ve bastırılmalıdır:
options.ConfigureWarnings(w => w.Ignore(Microsoft.EntityFrameworkCore.Diagnostics.RelationalEventId.PendingModelChangesWarning))6. ASP.NET Core Identity seçenekleri modeli etkiliyor
ASP.NET Core Identity kullanıyor ve options.Stores.SchemaVersion veya options.Stores.MaxLengthForKeys gibi modeli etkileyen seçenekleri değiştiriyorsanız, bu seçeneklerin araçlar çalışırken de aynı şekilde uygulanması gerekir. Aksi hâlde araçların gördüğü model ile uygulamanın gördüğü model farklı olur. Belgelerin çözümü iki yoldan biridir: EF araçlarını çalıştırırken uygulamayı başlangıç projesi olarak belirtmek ya da context'i içeren projede Identity'yi aynı seçeneklerle kaydeden bir IDesignTimeDbContextFactory uygulamak. Belgelerdeki örnek, kısaltılmış hâliyle:
public class DatabaseContextDesignTimeFactory : IDesignTimeDbContextFactory<DatabaseContext>
{
public DatabaseContext CreateDbContext(string[] args)
{
var services = new ServiceCollection();
AddIdentity(services);
var serviceProvider = services.BuildServiceProvider();
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
optionsBuilder.UseApplicationServiceProvider(serviceProvider);
optionsBuilder.UseSqlServer();
return new DatabaseContext(optionsBuilder.Options);
}
public static IServiceCollection AddIdentity(IServiceCollection services)
{
services.AddDefaultIdentity<ApplicationUser>(options =>
{
options.Stores.SchemaVersion = IdentitySchemaVersions.Version2;
options.Stores.MaxLengthForKeys = 256;
options.SignIn.RequireConfirmedAccount = false;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<DatabaseContext>();
return services;
}
}Uygulamanın kendi kayıt kodu da aynı AddIdentity yardımcı metodunu çağırırsa seçenekler tek yerde tanımlanmış olur ve tasarım zamanıyla çalışma zamanı birbirinden ayrışmaz. Design-time factory'nin genel çalışması için design-time DbContext factory yazısına bakın.
Senaryonuz bu durumların hiçbirine uymuyorsa ve yeni bir migration eklemek her seferinde aynı migration'ı ya da boş bir migration üretiyorsa, belgeler küçük bir yeniden üretim (repro) projesi hazırlayıp EF ekibiyle GitHub üzerinden paylaşmanızı önerir.
Hatayı deploy öncesinde yakalamak
Bu hatayı production'da değil, kod birleşmeden önce görmek istersiniz. Belgeler bunun için iki araç verir. Birincisi EF Core 8 ile gelen komuttur; son migration'dan bu yana modelde değişiklik olup olmadığını kontrol eder ve CI/CD hattınızda çalıştırılması önerilir:
dotnet ef migrations has-pending-model-changesİkincisi aynı kontrolün kod karşılığıdır: context.Database.HasPendingModelChanges(). Belgeler bunun, migration eklemeyi unuttuğunuzda başarısız olan bir birim testi yazmak için kullanılabileceğini söyler. Basit bir test şöyle görünebilir (test çatısının Assert sözdizimi kullandığınız kütüphaneye göre değişir):
[Fact]
public void Model_ile_son_migration_ayni()
{
using var context = new BloggingContext();
Assert.False(context.Database.HasPendingModelChanges());
}Sık yapılan bir karıştırma, GetPendingMigrationsAsync() metodunu bu amaçla kullanmaktır. O metot projedeki migration'ları veritabanının geçmiş tablosuyla karşılaştırır; yani “kodda olup veritabanına uygulanmamış migration” bulur. Migration'a dönüştürülmemiş model değişikliklerini görmez. Bekleyen model değişikliği için doğru araç HasPendingModelChanges() ve has-pending-model-changes komutudur. Test stratejileri hakkında daha fazlası EF Core test yazma yazısında.
Uyarıyı bastırmak: ne zaman, nasıl?
Uyarı ConfigureWarnings ile bastırılabilir; bu, OnConfiguring içinde ya da AddDbContext kaydında yapılır. Belgeler bunun production senaryolarında genellikle önerilmediğini açıkça belirtir: bastırma, modelinizle veritabanınız arasındaki farkı ortadan kaldırmaz, yalnızca EF'in sizi uyarmasını engeller. Yukarıdaki listede bastırmanın uygun görüldüğü durum, migration'ların EF servisleri değiştirilerek dinamik üretildiği yanlış pozitiftir; farklı sağlayıcı senaryosunda ise bastırma yalnızca geçici bir çaredir. Bastırmak yerine olayı loglamak isterseniz Ignore yerine Log kullanabilirsiniz; uyarı yapılandırması genel olarak SQL loglama yazısında anlatılıyor.
Komşu hata: açık transaction içinde migration
EF Core 9 ile gelen ikinci yüksek etkili migration değişikliği şudur: Migrate() ve MigrateAsync() artık kendi transaction'ını başlatıyor ve komutları bir ExecutionStrategy ile çalıştırıyor. Eskiden dayanıklılık için yaygın olan, execution strategy içinde transaction başlatıp migrate edip commit eden kalıp artık şu uyarı istisnasına yol açıyor (belgelerdeki metin):
An error was generated for warning 'Microsoft.EntityFrameworkCore.Migrations.MigrationsUserTransactionWarning': A transaction was started before applying migrations. This prevents a database lock to be acquired and hence the database will not be protected from concurrent migration applications. The transactions and execution strategy are already managed by EF as needed. Remove the external transaction. This exception can be suppressed or logged by passing event ID 'RelationalEventId.MigrationsUserTransactionWarning' to the 'ConfigureWarnings' method in 'DbContext.OnConfiguring' or 'AddDbContext'.Nedeni, dış transaction'ın EF Core 9'daki migration kilidinin alınmasını engellemesidir; bu durumda veritabanı eşzamanlı migration uygulamalarına karşı korunmaz. Transaction içinde yalnızca migration çağrısı varsa çözüm dış transaction'ı ve execution strategy'yi kaldırıp doğrudan await dbContext.Database.MigrateAsync(cancellationToken); çağırmaktır. Senaryonuz gerçekten açık bir transaction gerektiriyorsa ve eşzamanlı migration'ı önleyen başka bir mekanizmanız varsa belgeler RelationalEventId.MigrationsUserTransactionWarning uyarısını yok saymanıza izin verir. Migration kilidi production yazısında ayrıntılı anlatılıyor.
EF Core 11 notu: migration bulunamazsa hata (geliştirme aşamasında)
Belgelere göre geliştirme aşamasındaki EF Core 11'de benzer bir davranış daha geliyor. Bugüne kadar assembly'de hiç migration yokken Migrate() veya MigrateAsync() çağrıldığında EF Core bilgi düzeyinde bir mesaj loglayıp hiçbir şey yapmadan dönüyordu. EF Core 11'den itibaren bu durumda varsayılan olarak istisna fırlatılacak; belgeler bunun EF 9'daki PendingModelChangesWarning davranışıyla tutarlı olduğunu ve genellikle yanlış yapılandırmaya işaret ettiğini söyler; sessizce devam edip veritabanını yanlış durumda bırakmak yerine sorun hemen bildirilir. Şemayı bilerek başka yollarla yönetiyorsanız Migrate() çağrısını kaldırın ya da RelationalEventId.MigrationsNotFound olayını Ignore veya Log ile yapılandırın. EF Core 10 kullanan projeler için bu değişiklik henüz geçerli değildir.
Adım adım teşhis akışı

dotnet ef migrations has-pending-model-changesçalıştırın. Araçlar değişiklik görmüyor ama uygulama hata veriyorsa, tasarım zamanı ile çalışma zamanının farklı yapılandırılmış olabileceğini düşünün (Identity seçenekleri, farklı ortam veya sağlayıcı).- Değişiklik varsa geçici bir migration ekleyin ve içeriğini okuyun.
- İçerik beklediğiniz bir model değişikliğiyse migration'ı adlandırıp tutun; sorun çözülmüştür.
- İçerikte
HasDataile verdiğiniz tarih veya GUID değerleri her seferinde değişiyorsa dinamik değeri sabitleyin, migration'ı kaldırıp yeniden ekleyin. - Son migration'ın uyguladığınız sağlayıcıdan farklı bir sağlayıcı için üretilip üretilmediğini kontrol edin.
- Her denemede aynı migration veya boş bir migration çıkıp hata sürüyorsa belgelerdeki önerilere göre bir repro proje hazırlayın.
Sık Sorulan Sorular
Hata yalnızca production'da çıkıyor, yerelde çıkmıyor. Neden?
Yerelde araçlar ve uygulama farklı bir model görüyor olabilir: farklı ortam yapılandırması, farklı sağlayıcı veya Identity seçenekleri gibi. Ayrıca yerelde migration'ları database update ile uygulamış, production'da ise uygulamanın açılışta Migrate() çağırmasına güveniyor olabilirsiniz. İki taraftaki modelin aynı yapılandırmayla kurulduğundan emin olun ve kontrolü CI'a ekleyin.
Uyarıyı bastırıp devam etsem ne olur?
Migration'lar uygulanır, ama modelinizdeki migration'a dönüşmemiş değişiklikler veritabanına yansımaz. EF Core 9 öncesindeki sessiz davranışa dönmüş olursunuz. Belgeler bunu production için genellikle önermez.
Boş bir migration eklemek hatayı çözer mi?
Değişiklik gerçekten varsa migration boş olmaz. Migration'ın boş çıkmasına rağmen hata sürüyorsa belgelerin dediği gibi durum listede yoksa repro ile EF ekibine bildirmeniz önerilir.
SQL script ile deploy ediyorum, bu hatayı alır mıyım?
Script'i EF Core dışında bir SQL aracıyla çalıştırdığınızda bu kontrol yapılmaz. Bu yüzden unutulan migration'ı yakalamak için has-pending-model-changes komutunu CI'da çalıştırmanız daha da önemlidir.
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'ı production'a uygulama · Data seeding · Design-time DbContext factory · EF Core test yazma