Ekip Ortamlarında İlk Kod Geçişleri

Dekont

Bu makalede, temel senaryolarda Code First Migrations'ın nasıl kullanılacağını bildiğiniz varsayılır. Aksi takdirde devam etmeden önce Code First Migrations'ı okumanız gerekir.

Bir kahve alın, bu makalenin tamamını okumalısınız

Ekip ortamlarındaki sorunlar çoğunlukla iki geliştiricinin kendi yerel kod tabanında geçiş oluşturduğu geçişleri birleştirmeyle ilgili. Bunları çözme adımları oldukça basit olsa da, geçişlerin nasıl çalıştığını tam olarak anlamanız gerekir. Lütfen yalnızca sonuna atlamayın; başarılı olduğunuzdan emin olmak için makalenin tamamını okumak için zaman ayırın.

Bazı genel yönergeler

Birden çok geliştirici tarafından oluşturulan birleştirme geçişlerinin nasıl yönetileceğini incelemeden önce, başarı için sizi ayarlamaya yönelik bazı genel yönergeleri aşağıda bulabilirsiniz.

Her ekip üyesinin bir yerel geliştirme veritabanı olmalıdır

Geçişler, veritabanına uygulanan geçişleri depolamak için __MigrationsHistory tablosunu kullanır. Aynı veritabanını hedeflemeye (ve dolayısıyla bir __MigrationsHistory tablosunu paylaşmaya) çalışırken farklı geçişler oluşturan birden çok geliştiriciniz varsa, geçişler çok karıştırılır.

Elbette, geçiş oluşturmayan ekip üyeleriniz varsa merkezi bir geliştirme veritabanını paylaşmaları sorun olmaz.

Otomatik geçişlerden kaçının

Sonuç olarak, otomatik geçişler başlangıçta ekip ortamlarında iyi görünür, ancak gerçekte çalışmaz. Nedenini öğrenmek istiyorsanız okumaya devam edin; değilse sonraki bölüme atlayabilirsiniz.

Otomatik geçişler, kod dosyaları (kod tabanlı geçişler) oluşturmaya gerek kalmadan veritabanı şemanızın geçerli modelle eşleşecek şekilde güncelleştirilmesini sağlar. Otomatik geçişler, ekip ortamında yalnızca kullandığınız ve hiç kod tabanlı geçiş oluşturmadığınız durumlarda çok iyi çalışır. Sorun, otomatik geçişlerin sınırlı olması ve bir dizi işlemi işlememektir: özellik/sütun yeniden adlandırma, verileri başka bir tabloya taşıma vb. Bu senaryoları işlemek için, otomatik geçişler tarafından işlenen değişiklikler arasında karma kod tabanlı geçişler (ve iskelelenmiş kodu düzenleme) oluşturursunuz. Bu, iki geliştirici geçişleri iade ettiğinde değişiklikleri birleştirmeyi neredeyse imkansız hale getirir.

Geçişlerin nasıl çalıştığını anlama

Ekip ortamında geçişleri başarıyla kullanmanın anahtarı, geçişlerin model değişikliklerini algılamak için model hakkındaki bilgileri nasıl izlediğini ve kullandığını temel bir anlamadır.

İlk geçiş

Projenize ilk geçişi eklediğinizde, Paket Yöneticisi Konsolu'nda Önce Geçiş Ekle gibi bir şey çalıştırırsınız. Bu komutun gerçekleştirdiği üst düzey adımlar aşağıda gösterilir.

First Migration

Geçerli model kodunuz (1) üzerinden hesaplanır. Daha sonra gerekli veritabanı nesneleri model tarafından hesaplanır (2) – bu ilk geçiş olduğundan model farklılık gösterir, karşılaştırma için yalnızca boş bir model kullanır. Gerekli değişiklikler, gerekli geçiş kodunu (3) oluşturmak için kod oluşturucuya geçirilir ve bu da Visual Studio çözümünüze (4) eklenir.

Geçişler, ana kod dosyasında depolanan gerçek geçiş koduna ek olarak bazı ek arka planda kod dosyaları da oluşturur. Bu dosyalar, geçişler tarafından kullanılan meta verilerdir ve düzenlemeniz gereken bir şey değildir. Bu dosyalardan biri, geçiş oluşturulduğu sırada modelin anlık görüntüsünü içeren bir kaynak dosyasıdır (.resx). Sonraki adımda bunun nasıl kullanıldığını göreceksiniz.

Bu noktada, değişikliklerinizi veritabanına uygulamak için Update-Database'i çalıştırabilir ve ardından uygulamanızın diğer alanlarını uygulamaya geçebilirsiniz.

Sonraki geçişler

Daha sonra geri dönüp modelinizde bazı değişiklikler yapacaksınız; örneğimizde Blog'a bir Url özelliği ekleyeceğiz. Daha sonra, ilgili veritabanı değişikliklerini uygulamak üzere geçişin iskelesini oluşturmak için Add-Migration AddUrl gibi bir komut yayımlayabilirsiniz. Bu komutun gerçekleştirdiği üst düzey adımlar aşağıda gösterilir.

Second Migration

Geçen sefer olduğu gibi geçerli model de koddan (1) hesaplanır. Ancak bu kez mevcut geçişler olduğundan, önceki model en son geçişten (2) alınır. Bu iki model gerekli veritabanı değişikliklerini (3) bulmak için fark edilir ve işlem daha önce olduğu gibi tamamlanır.

Bu işlem, projeye eklediğiniz diğer tüm geçişler için de kullanılır.

Model anlık görüntüsüyle neden uğraşasın?

EF'nin neden model anlık görüntüsüyle uğraştığını merak ediyor olabilirsiniz; neden yalnızca veritabanına bakmıyorsun? Öyleyse okumaya devam edin. İlgilenmiyorsanız bu bölümü atlayabilirsiniz.

EF'nin model anlık görüntüsünün etrafında kalmasının çeşitli nedenleri vardır:

  • Veritabanınızın EF modelinden kaymasını sağlar. Bu değişiklikler doğrudan veritabanında yapılabilir veya değişiklikleri yapmak için geçişlerinizdeki iskeleli kodu değiştirebilirsiniz. Uygulamada bunun birkaç örneği aşağıda verilmiştir:
    • Bir veya daha fazla tablonuza Eklenen ve Güncelleştirilen sütun eklemek istiyorsunuz, ancak bu sütunları EF modeline eklemek istemiyorsunuz. Geçişler veritabanına baksaydı, her geçiş iskelesi oluşturduğunuzda sürekli olarak bu sütunları bırakmaya çalışırdı. EF, model anlık görüntüsünü kullanarak modelde yalnızca geçerli değişiklikleri algılar.
    • Güncelleştirmeler için kullanılan saklı yordamın gövdesini bazı günlükleri içerecek şekilde değiştirmek istiyorsunuz. Geçişler bu saklı yordama veritabanından baksaydı, sürekli olarak EF'nin beklediği tanıma geri döndürmeyi denerdi. Model anlık görüntüsünü kullanarak, EF yalnızca EF modelindeki yordamın şeklini değiştirdiğinizde saklı yordamı değiştirmek için kod iskelesi oluşturur.
    • Bu ilkeler, veritabanınızdaki ek tablolar, EF'yi bir tablonun üzerinde duran bir veritabanı görünümüne eşleme gibi ek dizinler eklemek için de geçerlidir.
  • EF modeli yalnızca veritabanının şeklinden fazlasını içerir. Modelin tamamına sahip olmak, geçişlerin modelinizdeki özellikler ve sınıflar hakkındaki bilgilere ve sütunlara ve tablolara nasıl eşlediklerine bakmasını sağlar. Bu bilgiler, geçişlerin yapı iskelesi yaptığı kodda daha akıllı olmasını sağlar. Örneğin, bir özelliğin geçişlerle eşlediği sütunun adını değiştirirseniz, bunun aynı özellik olduğunu görerek yeniden adlandırmayı algılayabilir; yalnızca veritabanı şemanız varsa yapılamaz. 

Ekip ortamlarında sorunlara neden olan şeyler

Önceki bölümde ele alınan iş akışı, bir uygulama üzerinde çalışan tek bir geliştirici olduğunuzda harika çalışır. Modelde değişiklik yapan tek kişi sizseniz ekip ortamında da iyi çalışır. Bu senaryoda model değişiklikleri yapabilir, geçişler oluşturabilir ve bunları kaynak denetiminize gönderebilirsiniz. Diğer geliştiriciler, şema değişikliklerinin uygulanması için değişikliklerinizi eşitleyebilir ve Update-Database'i çalıştırabilir.

EF modelinde değişiklik yapan ve kaynak denetimine aynı anda gönderen birden çok geliştiriciniz olduğunda sorunlar ortaya çıkar. EF'nin eksik olduğu, yerel geçişlerinizi, son eşitlemenizden bu yana başka bir geliştiricinin kaynak denetimine gönderdiği geçişlerle birleştirmenin birinci sınıf bir yoludur.

Birleştirme çakışması örneği

İlk olarak böyle bir birleştirme çakışmasının somut bir örneğine bakalım. Daha önce baktığımız örnekle devam edeceğiz. Başlangıç noktası olarak, önceki bölümdeki değişikliklerin özgün geliştirici tarafından iade edilmiş olduğunu varsayalım. Kod tabanında değişiklik yaparken iki geliştiriciyi takip edeceğiz.

EF modelini ve geçişleri bir dizi değişiklikle takip edeceğiz. Bir başlangıç noktası için her iki geliştirici de aşağıdaki grafikte gösterildiği gibi kaynak denetimi deposuyla eşitlenmiştir.

Starting Point

Geliştirici #1 ve geliştirici #2 artık YEREL kod tabanında EF modelinde bazı değişiklikler yapıyor. Geliştirici #1, Blog'a bir Derecelendirme özelliği ekler ve değişiklikleri veritabanına uygulamak için bir AddRating geçişi oluşturur. Geliştirici #2, Blog'a bir Okuyucu özelliği ekler ve ilgili AddReaders geçişini oluşturur. Her iki geliştirici de Update-Database'i çalıştırarak değişiklikleri yerel veritabanlarına uygular ve uygulamayı geliştirmeye devam eder.

Dekont

Geçişlere bir zaman damgası eklenmiştir, bu nedenle grafiğimiz Geliştirici #2'den AddReaders geçişinin Geliştirici #1'den AddRating geçişinin ardından geldiğini gösterir. Geçişi ilk olarak geliştirici #1 veya #2'nin oluşturup oluşturmadığı, bir ekipte çalışma sorunları veya sonraki bölümde ele alacağımız bunları birleştirme işlemi için hiçbir fark oluşturmaz.

Local Changes

Geliştirici #1 için şanslı bir gün çünkü ilk olarak değişikliklerini göndermeleri gerekiyor. Deposunu eşitledikten sonra başka hiç kimse iade etmediğinden, herhangi bir birleştirme gerçekleştirmeden değişikliklerini gönderebilir.

Submit Changes

Şimdi Geliştirici #2'nin gönderme zamanı geldi. O kadar şanslı değiller. Eşitlemeden sonra başka biri değişiklik gönderdiğinden, değişiklikleri aşağı çekmesi ve birleştirmesi gerekir. Kaynak denetim sistemi, değişiklikleri çok basit olduğundan kod düzeyinde otomatik olarak birleştirir. Eşitlemeden sonra Geliştirici #2'nin yerel deposunun durumu aşağıdaki grafikte gösterilmiştir. 

Pull From Source Control

Bu aşamada Geliştirici #2, yeni AddRating geçişini algılayan (Geliştirici #2'nin veritabanına uygulanmamış olan) Update-Database'i çalıştırabilir ve bunu uygulayabilir. Artık Derecelendirme sütunu Bloglar tablosuna eklenir ve veritabanı modelle eşitlenir.

Ancak birkaç sorun vardır:

  1. Update-Database AddRating geçişini uygulayacak olsa da bir uyarı da oluşturur: Bekleyen değişiklikler olduğundan ve otomatik geçiş devre dışı bırakıldığından veritabanı geçerli modelle eşleşecek şekilde güncelleştirilemiyor... Sorun, son geçişte depolanan model anlık görüntüsünün (AddReader) Blog'daDerecelendirme özelliğinin eksik olmasıdır (geçiş oluşturulduğunda modelin bir parçası olmadığından). Code First, son geçişteki modelin geçerli modelle eşleşmediğini algılar ve uyarıyı oluşturur.
  2. Uygulamanın çalıştırılması invalidOperationException'ın "Veritabanı oluşturulduktan sonra 'BloggingContext' bağlamını destekleyen model değişti. Veritabanını güncelleştirmek için Code First Migrations kullanmayı düşünün..." Sorun, son geçişte depolanan model anlık görüntüsünün geçerli modelle eşleşmemesidir.
  3. Son olarak, Add-Migration'ın şimdi çalıştırılmasının boş bir geçiş oluşturmasını bekleriz (veritabanına uygulanacak hiçbir değişiklik olmadığından). Ancak geçişler geçerli modeli son geçişteki modelle (Derecelendirme özelliği eksik) karşılaştırdığından, Derecelendirme sütununa eklemek üzere başka bir AddColumn çağrısının iskelesini oluşturur. Elbette, Derecelendirme sütunu zaten mevcut olduğundan bu geçiş Update-Database sırasında başarısız olur.

Birleştirme çakışmasını çözme

İyi haber, geçişlerin nasıl çalıştığını anlamanız koşuluyla birleştirme işlemini el ile halletmenin çok zor olmamasıdır. Bu nedenle, bu bölümü atladıysanız... Üzgünüm, önce geri dönüp makalenin geri kalanını okumalısınız!

İki seçenek vardır; en kolayı, anlık görüntü olarak doğru geçerli modele sahip boş bir geçiş oluşturmaktır. İkinci seçenek, son geçişteki anlık görüntüyü doğru model anlık görüntüsüne sahip olacak şekilde güncelleştirmektir. İkinci seçenek biraz daha zordur ve her senaryoda kullanılamaz, ancak ek geçiş eklemeyi içermediğinden de daha temizdir.

1. Seçenek: Boş bir 'birleştirme' geçişi ekleme

Bu seçenekte, yalnızca en son geçişin içinde doğru model anlık görüntüsünün depolandığından emin olmak amacıyla boş bir geçiş oluştururuz.

Bu seçenek, son geçişi kimin oluşturduğundan bağımsız olarak kullanılabilir. Geliştirici #2'yi takip ettiğimiz örnekte birleştirme işlemiyle ilgileniliyor ve son geçişi onlar oluşturuyordu. Ancak son geçişi Geliştirici #1 oluşturduysa aynı adımlar kullanılabilir. Adımlar, birden çok geçiş söz konusuysa da geçerlidir. Basit tutmak için iki geçişe bakıyorduk.

Kaynak denetiminden eşitlenmesi gereken değişiklikleriniz olduğunu fark ettiğiniz zamandan başlayarak bu yaklaşım için aşağıdaki işlem kullanılabilir.

  1. Yerel kod tabanınızdaki bekleyen model değişikliklerinin geçişe yazılmış olduğundan emin olun. Bu adım, boş geçiş oluşturma zamanı geldiğinde hiçbir yasal değişikliği kaçırmamanızı sağlar.
  2. Kaynak denetimiyle eşitleyin.
  3. Diğer geliştiricilerin iade etmiş olduğu yeni geçişleri uygulamak için Update-Database'i çalıştırın. Not:Update-Database komutundan herhangi bir uyarı almazsan, diğer geliştiricilerden yeni geçişler yapılmadı ve daha fazla birleştirme gerçekleştirmeye gerek yok.
  4. Add-Migration pick_a_name –IgnoreChanges komutunu çalıştırın (örneğin, Add-Migration Merge –IgnoreChanges).>< Bu, tüm meta verileri (geçerli modelin anlık görüntüsü dahil) içeren bir geçiş oluşturur, ancak geçerli modeli son geçişlerdeki anlık görüntüyle karşılaştırırken algılanan değişiklikleri yoksayar (boş bir Yukarı ve Aşağı yöntemi elde ettiğiniz anlamına gelir).
  5. Güncelleştirilmiş meta verilerle en son geçişi yeniden uygulamak için Update-Database'i çalıştırın.
  6. Geliştirmeye devam edin veya kaynak denetimine gönderin (elbette birim testlerinizi çalıştırdıktan sonra).

Bu yaklaşımı kullandıktan sonra Geliştirici #2'nin yerel kod tabanının durumu aşağıda belirtilmiştir.

Merge Migration

Seçenek 2: Son geçişte model anlık görüntüsünü güncelleştirme

Bu seçenek, 1. seçeneğe çok benzer ancak çözümünde ek kod dosyaları isteyen kişiler için fazladan boş geçişi kaldırır.

Bu yaklaşım yalnızca en son geçiş yalnızca yerel kod tabanınızda mevcutsa ve henüz kaynak denetimine gönderilmediyse (örneğin, son geçiş birleştirmeyi yapan kullanıcı tarafından oluşturulduysa) uygulanabilir. Diğer geliştiricilerin geliştirme veritabanına zaten uygulamış olabileceği (hatta daha kötüsü bir üretim veritabanına uygulanan) geçişlerin meta verilerinin düzenlenmesi beklenmeyen yan etkilere neden olabilir. İşlem sırasında yerel veritabanımızda son geçişi geri alıp güncelleştirilmiş meta verilerle yeniden uygulayacağız.

Son geçişin yalnızca yerel kod tabanında olması gerekirken, devam eden geçiş sayısı veya sırası için herhangi bir kısıtlama yoktur. Birden çok farklı geliştiriciden birden fazla geçiş olabilir ve aynı adımlar geçerlidir. Basit tutmak için iki tanesine bakıyorduk.

Kaynak denetiminden eşitlenmesi gereken değişiklikleriniz olduğunu fark ettiğiniz zamandan başlayarak bu yaklaşım için aşağıdaki işlem kullanılabilir.

  1. Yerel kod tabanınızdaki bekleyen model değişikliklerinin geçişe yazılmış olduğundan emin olun. Bu adım, boş geçiş oluşturma zamanı geldiğinde hiçbir yasal değişikliği kaçırmamanızı sağlar.
  2. Kaynak denetimiyle eşitleyin.
  3. Diğer geliştiricilerin iade etmiş olduğu yeni geçişleri uygulamak için Update-Database'i çalıştırın. Not:Update-Database komutundan herhangi bir uyarı almazsan, diğer geliştiricilerden yeni geçişler yapılmadı ve daha fazla birleştirme gerçekleştirmeye gerek yok.
  4. Update-Database –TargetMigration <second_last_migration> komutunu çalıştırın (takip ettiğimiz örnekte Update-Database –TargetMigration AddRating olabilir). Bu işlem, veritabanını ikinci son geçişin durumuna geri döndürür; veritabanından son geçişi etkili bir şekilde 'uygulamadan' kaldırır. Not:Bu adım, meta veriler de veritabanının __MigrationsHistoryTable depolandığından geçişin meta verilerini düzenlemeyi güvenli hale getirmek için gereklidir. Bu nedenle bu seçeneği yalnızca son geçiş yalnızca yerel kod tabanınızdaysa kullanmalısınız. Diğer veritabanlarında son geçiş uygulanmışsa, meta verileri güncelleştirmek için bunları geri alıp son geçişi yeniden uygulamanız da gerekir. 
  5. Add-Migration <full_name_including_timestamp_of_last_migration> komutunu çalıştırın (takip ettiğimiz örnekte bu, Add-Migration 201311062215252_AddReaders gibi bir şey olabilir). Not:Geçişlerin yeni bir tane iskelesi oluşturmak yerine var olan geçişi düzenlemek istediğinizi bilmesi için zaman damgasını eklemeniz gerekir. Bu işlem, son geçişin meta verilerini geçerli modelle eşleşecek şekilde güncelleştirir. Komut tamamlandığında aşağıdaki uyarıyı alırsınız, ancak tam olarak istediğiniz budur. "'201311062215252_AddReaders' geçişi için yalnızca Tasarım Aracı Kodu yeniden iskelesi oluşturuldu. Geçişin tamamını yeniden iskeleye almak için -Force parametresini kullanın."
  6. Güncelleştirilmiş meta verilerle en son geçişi yeniden uygulamak için Update-Database'i çalıştırın.
  7. Geliştirmeye devam edin veya kaynak denetimine gönderin (elbette birim testlerinizi çalıştırdıktan sonra).

Bu yaklaşımı kullandıktan sonra Geliştirici #2'nin yerel kod tabanının durumu aşağıda belirtilmiştir.

Updated Metadata

Özet

Bir ekip ortamında Code First Migrations kullanırken bazı zorluklar yaşanıyor. Ancak, geçişlerin nasıl çalıştığına ilişkin temel bir anlayış ve birleştirme çakışmalarını çözmeye yönelik bazı basit yaklaşımlar bu zorlukların üstesinden gelmeyi kolaylaştırır.

Temel sorun, en son geçişte depolanan yanlış meta verilerdir. Bu, Code First'ın geçerli model ve veritabanı şemasının eşleşmediğini yanlış algılamasına ve sonraki geçişte yanlış kod iskelesi oluşturmasına neden olur. Bu durum, doğru modelle boş bir geçiş oluşturularak veya en son geçişte meta veriler güncelleştirilerek aşılabilir.