Kód első migrálása csapatkörnyezetekben

Megjegyzés:

Ez a cikk feltételezi, hogy tudja, hogyan használhatja a Code First Migrationst az alapforgatókönyvekben. Ha nem, akkor a folytatás előtt el kell olvasnia a Code First Migrationst .

Fogjon egy kávét, el kell olvasnia ezt az egész cikket

A csapatkörnyezetek problémái többnyire az áttelepítések egyesítése körül állnak, amikor két fejlesztő migrálást hozott létre a helyi kódbázisban. Bár ezek megoldásának lépései meglehetősen egyszerűek, megkövetelik, hogy alapos ismereteket biztosítson a migrálások működéséről. Kérjük, ne csak ugorjon előre a végére – szánjon időt a teljes cikk elolvasására, hogy biztosan sikeres legyen.

Néhány általános irányelv

Mielőtt megismerkednénk a több fejlesztő által generált egyesítő migrálások kezelésével, íme néhány általános irányelv, amely a sikeres üzembe helyezéséhez szükséges.

Minden csapattagnak rendelkeznie kell egy helyi fejlesztési adatbázissal

Az áttelepítési folyamat a __MigrationsHistory táblát használja az adatbázisra már alkalmazott migrálások tárolására. Ha több fejlesztő különböző migrációkat generál, miközben ugyanazt az adatbázist célozzák meg (és így megosztanak egy __MigrationsHistory táblát), az áttelepítések nagyon összezavarodnak.

Természetesen ha olyan csapattagokkal rendelkezik, akik nem hoznak létre migrálásokat, nincs probléma, ha egy központi fejlesztési adatbázist osztanak meg velük.

Az automatikus migrálás elkerülése

A lényeg az, hogy az automatikus migrálások kezdetben jól néznek ki a csapatkörnyezetekben, de a valóságban egyszerűen nem működnek. Ha tudni szeretné, hogy miért, folytassa az olvasást – ha nem, akkor ugorjon a következő szakaszra.

Az automatikus áttelepítések lehetővé teszik az adatbázisséma frissítését az aktuális modellnek megfelelően anélkül, hogy kódfájlokat (kódalapú migrálásokat) kellene létrehoznia. Az automatikus migrálások nagyon jól működnének csapatkörnyezetben, ha csak valaha is használná őket, és soha nem hozna létre kódalapú migrálásokat. A probléma az, hogy az automatikus áttelepítések korlátozottak, és nem kezelnek több műveletet – tulajdonság/oszlop átnevezése, adatok áthelyezése egy másik táblába stb. A forgatókönyvek kezeléséhez végül kódalapú migrálásokat (és az állványozott kód szerkesztését) kell létrehoznia, amelyek az automatikus migrálások által kezelt módosítások között keverednek. Így szinte lehetetlen egyesíteni a módosításokat, amikor két fejlesztő ellenőrzi a migrálásokat.

A migrálás működésének ismertetése

A csapatkörnyezetben végzett migrálás sikeres használatának kulcsa az, hogy a migrálások hogyan követik nyomon a modell adatait, és hogyan észlelik a modell változásait.

Az első migrálás

Amikor hozzáadja az első migrációt a projekthez, az Add-Migration First a Package Manager Console-ban fut. A parancs által végrehajtott magas szintű lépések az alábbiakban láthatóak.

Első migrálás

Az aktuális modell kiszámítása a kódból történik (1). A szükséges adatbázis-objektumokat ezután a modell kiszámítja (2) – mivel ez az első migrálás, a modell csak üres modellt használ az összehasonlításhoz. A szükséges módosításokat a rendszer átadja a kódgenerátornak a szükséges migrálási kód (3) létrehozásához, amelyet aztán hozzáad a Visual Studio-megoldáshoz (4).

A fő kódfájlban tárolt tényleges migrálási kód mellett az áttelepítések további kód mögötti fájlokat is létrehoznak. Ezek a fájlok a migrálások által használt metaadatok, amelyeket nem érdemes szerkeszteni. Az egyik ilyen fájl egy erőforrásfájl (.resx), amely a modell pillanatképét tartalmazza az áttelepítés létrehozásakor. A következő lépésben látni fogja, hogyan használják ezt.

Ezen a ponton valószínűleg az Update-Database futtatásával alkalmazza a módosításokat az adatbázisra, majd az alkalmazás más területeinek implementálásával foglalkozik.

További migrálások

Később visszatér, és módosítja a modellt – a példában egy URL-tulajdonságotadunk hozzá a Bloghoz. Ezután kiadhat egy parancsot, például Add-Migration AddUrl parancsot a migrálás létrehozásához a megfelelő adatbázis-módosítások alkalmazásához. A parancs által végrehajtott magas szintű lépések az alábbiakban láthatóak.

Második migrálás

A legutóbbihoz hasonlóan az aktuális modell is kódból (1) lesz kiszámítva. Most azonban már léteznek migrálások, így az előző modell a legújabb migrálásból (2) lesz lekérve. A két modell összehasonlítása megtörténik az adatbázis szükséges módosításainak felfedezéséhez (3), majd a folyamat a korábbiakhoz hasonlóan teljesen befejeződik.

Ugyanez a folyamat használható a projekthez hozzáadott további áttelepítésekhez is.

Miért foglalkozzunk a modell pillanatképével?

Felmerülhet a kérdés, hogy az EF miért foglalkozik a modell pillanatképével – miért nem tekinti egyszerűen az adatbázist. Ha igen, olvasson tovább. Ha nem érdekli, kihagyhatja ezt a szakaszt.

Az EF több okból is megőrzi a modell pillanatképét:

  • Lehetővé teszi, hogy az adatbázis eltávolodjon az EF-modelltől. Ezek a módosítások közvetlenül az adatbázisban végezhetők el, vagy megváltoztathatja a migrációkhoz generált kódot a módosítások végrehajtásához. Íme néhány példa erre a gyakorlatban:
    • Beszúrt és frissített oszlopot szeretne hozzáadni egy vagy több táblához, de ezeket az oszlopokat nem szeretné belefoglalni az EF-modellbe. Ha a migrációs folyamatok megvizsgálják az adatbázist, az folyamatosan megpróbálná eltávolítani ezeket az oszlopokat, valahányszor elkészíti a migrálás szerkezetét. A modell pillanatképének használatával az EF mindig csak a modell jogos módosításait észleli.
    • Módosítani szeretné egy tárolt eljárás törzsét, amelyet a frissítésekhez használnak, hogy tartalmazzanak némi naplózást. Ha a migrálások az adatbázisban található tárolt eljárást néznék, az folyamatosan próbálná visszaállítani az EF által elvárt definícióra. A modell pillanatképének használatával az EF csak akkor generál kódot a tárolt eljárás módosítására, ha megváltoztatja az eljárás struktúráját az EF-modellben.
    • Ugyanezek az alapelvek vonatkoznak az extra indexek hozzáadására, beleértve az adatbázisban lévő további táblákat, az EF-nek egy táblázat fölé ülő adatbázisnézetre való leképezését stb.
  • Az EF-modell nem csupán az adatbázis alakját tartalmazza. A teljes modell lehetővé teszi, hogy a migrálások megtekintsék a modell tulajdonságaival és osztályaival, valamint az oszlopokra és táblákra való leképezés módjával kapcsolatos információkat. Ezek az információk lehetővé teszik, hogy a migrálás intelligensebben legyen tervezve az általuk generált kódban. Ha például módosítja annak az oszlopnak a nevét, amelyet egy tulajdonság migrálásra képez le, észlelheti az átnevezést, ha azt látja, hogy ugyanaz a tulajdonság – ami nem végezhető el, ha csak az adatbázissémával rendelkezik. 

Mi okozza a csapatkörnyezetekben előforduló problémákat?

Az előző szakaszban tárgyalt munkafolyamat nagyszerűen működik, ha Ön egyetlen fejlesztő, aki egy alkalmazáson dolgozik. Csapatkörnyezetben is jól működik, ha Ön az egyetlen személy, aki módosítja a modellt. Ebben a forgatókönyvben modellmódosításokat hajthat végre, migrálásokat hozhat létre, és elküldheti őket a forrásvezérlőnek. Más fejlesztők szinkronizálhatják a módosításokat, és futtathatják az Update-Database-t a sémamódosítások alkalmazásához.

Problémák akkor merülnek fel, ha több fejlesztő is módosítja az EF-modellt, és egyszerre küldi el a forrásvezérlést. Az EF-ből hiányzik egy első osztályú módszer, amellyel egyesítheti a helyi migrálásokat azokkal a migrálásokkal, amelyeket egy másik fejlesztő a legutóbbi szinkronizálás óta küldött a forrásvezérlőnek.

Példa egyesítési ütközésre

Először tekintsünk meg egy konkrét példát egy ilyen egyesítési ütközésre. A korábban megvizsgált példával folytatjuk. Kiindulásként tegyük fel, hogy az előző szakasz módosításait az eredeti fejlesztő beadta. Két fejlesztőt követünk nyomon, amint módosítják a kódbázist.

Az EF-modellt és a migrálásokat számos változáson keresztül követjük nyomon. Kiindulópontként mindkét fejlesztő szinkronizált a forrásvezérlő-adattárral, ahogyan az az alábbi ábrán látható.

Kiindulópont

Az 1. fejlesztő és a fejlesztő #2 mostantól módosítja az EF-modellt a helyi kódbázisban. Az 1. fejlesztő hozzáad egy Rating tulajdonságot a Bloghoz , és létrehoz egy AddRating migrálást a módosítások adatbázisra való alkalmazásához. A 2. fejlesztő hozzáad egy Olvasók tulajdonságot a Bloghoz, és létrehozza a megfelelő AddReaders migrálást. Mindkét fejlesztő az Update-Database-t futtatja, hogy alkalmazza a módosításokat a helyi adatbázisokra, majd folytassa az alkalmazás fejlesztését.

Megjegyzés:

A migrálások időbélyeggel vannak előtagolva, így az ábránk azt jelzi, hogy az AddReaders migrálása a Developer #2-ből az AddRating migrálás után érkezik a Developer #1-ből. Függetlenül attól, hogy az 1. vagy a 2. fejlesztő létrehozta-e először a migrálást, nem számít a csapatban végzett munka, vagy az egyesítésük folyamata, amelyet a következő szakaszban tekintünk meg.

Helyi módosítások

Ez egy szerencsés nap a Fejlesztő #1 számára, mivel először elküldik a módosításokat. Mivel senki más nem jelentkezett be az adattár szinkronizálása óta, egyszerűen elküldheti a módosításokat egyesítés nélkül.

Módosítások elküldése

Eljött a 2. fejlesztő beküldésének ideje. Nem olyan szerencsések. Mivel valaki más is küldött be módosításokat a szinkronizálás óta, le kell telepítenie a módosításokat, és egyesítenie kell őket. A forrásvezérlő rendszer valószínűleg képes lesz automatikusan egyesíteni a módosításokat a kód szintjén, mivel nagyon egyszerűek. A developer #2 helyi adattárának állapota a szinkronizálás után az alábbi ábrán látható. 

Lekérés a forrásvezérlőből

Ebben a szakaszban a Developer #2 futtathatja az Update-Database-t , amely észleli az új AddRating migrálást (amely nem lett alkalmazva a Developer #2 adatbázisára), és alkalmazza azt. Most a Minősítés oszlop hozzáadódik a Blogok táblához, és az adatbázis szinkronban van a modellel.

Van azonban néhány probléma:

  1. Bár az Update-Database alkalmazza az AddRating migrálást, figyelmeztetést is jelez: Nem lehet frissíteni az adatbázist az aktuális modellnek megfelelően, mert függőben vannak a módosítások, és az automatikus migrálás le van tiltva... A probléma az, hogy a legutóbbi migrálásban (AddReader) tárolt modell-pillanatkép hiányzik a BlogRating tulajdonságából (mivel az nem része a modellnek az áttelepítés létrehozásakor). A Code First észleli, hogy a legutóbbi migrálás modellje nem egyezik az aktuális modellel, és figyelmeztetést ad.
  2. Az alkalmazás futtatása esetén az InvalidOperationException azt állítja, hogy "A BloggingContext környezet hátterében lévő modell megváltozott az adatbázis létrehozása óta. Fontolja meg a Code First Migrations használatát az adatbázis frissítéséhez..." A probléma ismét az, hogy a legutóbbi migrálásban tárolt modell-pillanatkép nem egyezik az aktuális modellel.
  3. Végül azt várnánk, hogy a bővítménymigrálás futtatása üres migrálást eredményezne (mivel az adatbázisra nem vonatkoznak módosítások). Mivel azonban a migrálások az aktuális modellt az utolsó migrálásból származó modellel hasonlítják össze (amely nem tartalmazza az Rating tulajdonságot), valójában egy újabb AddColumn-hívást fog összehozni a Minősítés oszlopban. Ez az áttelepítés természetesen az Update-Database során meghiúsulna, mert a Minősítés oszlop már létezik.

Az egyesítési ütközés feloldása

A jó hír az, hogy nem túl nehéz manuálisan kezelni az egyesítést – feltéve, hogy tisztában van a migrálások működésével. Tehát ha kihagyta ezt a szakaszt... sajnáljuk, akkor vissza kell mennie, és olvassa el a többi cikket először!

Két lehetőség közül választhat, a legegyszerűbben olyan üres migrálást hozhat létre, amely pillanatképként a megfelelő aktuális modellt használja. A második lehetőség a pillanatkép frissítése az utolsó migrálás során, hogy a modell pillanatképe a megfelelő legyen. A második lehetőség egy kicsit nehezebb, és nem használható minden forgatókönyvben, de az is tisztább, mert nem igényel további migrálást.

1. lehetőség: Üres "egyesítés" migráció hozzáadása

Ebben a beállításban csak azért hozunk létre üres migrálást, hogy a legújabb migrálásban a megfelelő modell pillanatképe legyen tárolva.

Ez a beállítás attól függetlenül használható, hogy ki generálta az utolsó migrálást. A példában, amelyet követünk, a 2. fejlesztő gondoskodik az egyesítésről, és véletlenül ő generálta a legutóbbi migrációt. Ezek a lépések azonban akkor használhatók, ha az 1. fejlesztő a legutóbbi migrálást generálta. A lépések akkor is érvényesek, ha több migrálásról van szó – most vizsgáljuk meg a kettőt annak érdekében, hogy egyszerű legyen.

Ehhez a megközelítéshez a következő folyamat használható, attól kezdve, hogy felismerte, hogy a forrásvezérlőből szinkronizálandó módosítások vannak.

  1. Győződjön meg arról, hogy a helyi kódbázis függőben lévő modellmódosításait migrálásra írták. Ez a lépés biztosítja, hogy az üres migrálás létrehozásakor ne maradjon le a megfelelő módosításokról.
  2. Szinkronizálás a forrásvezérlővel.
  3. Futtassa az Update-Database parancsot a többi fejlesztő által bejelentkezett új áttelepítések alkalmazásához. Megjegyzés:ha nem kap figyelmeztetést a Update-Database parancstól, akkor nem történt új migrálás más fejlesztőktől, és nincs szükség további egyesítésre.
  4. Futtassa Add-Migration <pick_a_name> –IgnoreChanges parancsot (például Add-Migration Merge –IgnoreChanges). Ez létrehoz egy migrálást az összes metaadattal (beleértve az aktuális modell pillanatképét is), de figyelmen kívül hagyja azokat a módosításokat, amikor az aktuális modellt összehasonlítja az utolsó migrálások pillanatképével (ami azt jelenti, hogy egy üres Fel és Le metódust kap).
  5. Az Update-Database futtatásával újra alkalmazhatja a legújabb migrálást a frissített metaadatokkal.
  6. Folytassa a fejlesztést, vagy küldje el a forráskontrollnak (természetesen az egységtesztek futtatása után).

Itt látható a Developer #2 helyi kódbázisának állapota a módszer használata után.

Egyesítés migráció

2. lehetőség: A modell pillanatképének frissítése az utolsó migrálás során

Ez a lehetőség nagyon hasonlít az 1. lehetőséghez, de eltávolítja a felesleges üres migrálást – mert lássuk be, ki szeretne további kódfájlokat használni a megoldásban.

Ez a módszer csak akkor valósítható meg, ha a legújabb migrálás csak a helyi kódbázisban létezik, és még nem lett elküldve a forrásvezérlőnek (például ha az utolsó migrálást az egyesítést végző felhasználó hozta létre). A más fejlesztők által a fejlesztői adatbázisra már alkalmazott migrálások metaadatainak szerkesztése – vagy még rosszabb esetben egy éles adatbázisra – váratlan mellékhatásokat okozhat. A folyamat során visszaállítjuk a legutóbbi migrálást a helyi adatbázisunkban, és újra alkalmazzuk a frissített metaadatokkal.

Bár az utolsó migrálásnak csak a helyi kódbázisban kell lennie, nincs korlátozás az azt követő áttelepítések számára vagy sorrendjére. Több különböző fejlesztőtől is több migrálás is lehet, és ugyanezek a lépések érvényesek– most két lépéssel foglalkoztunk az egyszerűség érdekében.

Ehhez a megközelítéshez a következő folyamat használható, attól kezdve, hogy felismerte, hogy a forrásvezérlőből szinkronizálandó módosítások vannak.

  1. Győződjön meg arról, hogy a helyi kódbázis függőben lévő modellmódosításait migrálásra írták. Ez a lépés biztosítja, hogy az üres migrálás létrehozásakor ne maradjon le a megfelelő módosításokról.
  2. Szinkronizálás a forrásvezérlővel.
  3. Futtassa az Update-Database parancsot a többi fejlesztő által bejelentkezett új áttelepítések alkalmazásához. Megjegyzés:ha nem kap figyelmeztetést a Update-Database parancstól, akkor nem történt új migrálás más fejlesztőktől, és nincs szükség további egyesítésre.
  4. Futtassa Update-Database –TargetMigration <second_last_migration> (a példánkban ez Update-Database –TargetMigration AddRating). Ezzel visszaállítja az adatbázist a második utolsó migrálás állapotába – gyakorlatilag "nem alkalmazza" az adatbázisból az utolsó migrálást. Megjegyzés:Ez a lépés biztonságossá teszi az áttelepítés metaadatainak szerkesztését, mivel a metaadatokat az adatbázis __MigrationsHistoryTable is tárolja. Ezért csak akkor érdemes ezt a lehetőséget használnia, ha az utolsó áttelepítés csak a helyi kódbázisban található. Ha más adatbázisok esetében az utolsó migrálás lett volna alkalmazva, akkor is vissza kell állítania őket, és újra kell alkalmaznia az utolsó migrálást a metaadatok frissítéséhez. 
  5. Futtassa Add-Migration <full_name_including_timestamp_of_last_migration> (az általunk követett példában ez a Add-Migration 201311062215252_AddReaders hasonló lenne). Megjegyzés:Az időbélyeget úgy kell megadnia, hogy a migrálások tudják, hogy a meglévő migrálást szeretné szerkeszteni, nem pedig egy újat. Ez frissíti az utolsó migrálás metaadatait az aktuális modellnek megfelelően. A parancs befejeződésekor a következő figyelmeztetést kapja, de pontosan ezt szeretné. "Csak a "201311062215252_AddReaders" áttelepítés tervezőkódja lett újraszerkesztve. A teljes migrálás újraszerkesztéséhez használja a -Force paramétert."
  6. Az Update-Database futtatásával újra alkalmazhatja a legújabb migrálást a frissített metaadatokkal.
  7. Folytassa a fejlesztést, vagy küldje el a forráskontrollnak (természetesen az egységtesztek futtatása után).

Itt látható a Developer #2 helyi kódbázisának állapota a módszer használata után.

Frissített metaadatok

Összefoglalás

A Code First Migrations csapatkörnyezetben való használata során bizonyos kihívások merülnek fel. A migrálások működésének alapszintű ismerete és az egyesítési ütközések megoldásának néhány egyszerű megközelítése azonban megkönnyíti ezeknek a kihívásoknak a leküzdését.

Az alapvető probléma a legutóbbi migrálás során tárolt helytelen metaadatok. Emiatt a Code First helytelenül észleli, hogy az aktuális modell és adatbázisséma nem egyezik, és helytelen kódot hoz létre a következő migrálás során. Ez a helyzet úgy oldható meg, hogy egy üres migrálást hoz létre a megfelelő modellel, vagy frissíti a metaadatokat a legújabb migrálás során.