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

Not

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 tabanlarında ürettiği geçişleri birleştirmeyle ilgilidir. 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. Şayet yalnızca otomatik geçişleri kullanır ve hiç kod tabanlı geçiş oluşturmazsanız, otomatik geçişler ekip ortamında ç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 sisteme kaydettiğ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.

İlk Geçiş

Geçerli model kodunuz (1) üzerinden hesaplanır. Daha sonra gerekli veritabanı nesneleri model farkı (2) tarafından hesaplanır. Bu ilk geçiş olduğu için, model farkı 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.

İkinci Geçiş

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şalım?

EF'nin neden model anlık görüntüsüyle ilgilendiğini merak ediyor olabilirsiniz; neden sadece veritabanını kullanmıyor? Öyleyse okumaya devam edin. İlgilenmiyorsanız bu bölümü atlayabilirsiniz.

EF'nin model anlık görüntüsünü saklaması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ş isteği oluşturduğunuzda sürekli olarak bu sütunları düşürmeye ç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ı yordamı veritabanından incelediğinde, EF'nin beklediği tanıma sürekli olarak geri döndürmeyi denerdi. Model anlık görüntüsünü kullanarak EF, yalnızca EF modelindeki yordamın yapısını değiştirdiğinizde saklı yordamı güncellemek için kod yapısını oluşturur.
    • Bu ilkeler, veritabanınızdaki ek tablolar ve ek dizinler eklemek, EF'yi bir tablonun üzerinde konumlanmış bir veritabanı görünümüne eşlemek gibi durumlar 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 kurulan kodda daha akıllıca hale gelmesini 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'de eksik olan şey, yerel geçişlerinizi, son eşitlemeden bu yana başka bir geliştiricinin kaynak denetimine gönderdiği geçişlerle birleştirmeye yönelik birinci sınıf bir yoldur.

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 sisteme aktarıldığını 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. Başlangıç olarak, her iki geliştirici de aşağıdaki grafikte gösterildiği gibi kaynak denetimi deposuyla eşitlenmiştir.

Başlangıç Noktası

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.

Not

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.

Yerel Değişiklikler

Geliştirici #1 için şanslı bir gün çünkü değişikliklerini ilk olarak gönderen kişi onlar oldu. Depolarını senkronize ettikten sonra başka hiç kimse değişikliklerini teslim etmediğinden, herhangi bir birleştirme gerçekleştirmeden değişikliklerini teslim edebilirler.

Değişiklikleri gönderme

Ş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. 

Kaynak Denetiminden Çekme

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. Although Update-DatabaseAddRating geçişini uygulayacak olsa da, bir uyarı da verecektir: 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 durumunun (AddReader), Blog'da Derecelendirme (Rating) ö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. Uygulamayı çalıştırmak, "Veritabanı oluşturulduktan sonra 'BloggingContext' contextini destekleyen model değişti. Veritabanını güncellemek için Code First Migrations kullanmayı düşünün..." diyen bir InvalidOperationException atarak sonuçlanır. 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 mevcut modeli son geçişteki modelle (bu model Rating özelliğinden yoksundur) karşılaştırdığı için, gerçekten AddColumn çağrısının başka bir tanesini oluşturarak Rating sütununu ekleyecektir. 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.

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

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

Bu seçenek, son geçişi kimin oluşturduğundan bağımsız olarak kullanılabilir. Takip ettiğimiz örnekte, Geliştirici #2 birleştirmeyi yapıyor ve tesadüfen son geçişi de onlar oluşturuyor. 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 amacıyla sadece 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 bir migrasyona yazıldığından 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ı almazsınız, başka geliştiricilerden yeni geçişler yapılmaz ve daha fazla birleştirme gerçekleştirmeniz gerekmez.
  4. Run Add-Migration <bir_ad_seç> –IgnoreChanges (ö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.

Geçişi Birleştir

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 dürüst olalım, kim çözümünde fazladan kod dosyaları ister ki? Bu nedenle, gereksiz 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 migrasyona kaydedildiğinden 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 paylaşmış olduğu yeni geçişleri uygulamak için Update-Database'i çalıştırın. Not:Update-Database komutundan herhangi bir uyarı almazsınız, başka geliştiricilerden yeni geçişler yapılmaz ve daha fazla birleştirme gerçekleştirmeniz gerekmez.
  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:Meta veriler de veritabanının __MigrationsHistoryTable depolandığından, geçişin meta verilerini düzenlemeyi güvenli hale getirmek için bu adım 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 (izlediğimiz örnekte bu, > gibi bir şey olabilir). Not:Geçişlerin yeni bir geçiş 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. "Yalnızca '201311062215252_AddReaders' geçişi için Tasarımcı Kodu yeniden iskelet oluşturuldu. Geçişin tamamını yeniden iskelet oluşturmak 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.

Güncelleştirilmiş Meta Veriler

Ö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.