Hai Hari ini saya merilis versi baru ThinkingHome.Migrator - alat untuk migrasi versi skema database ke platform .NET Core.

Paket diterbitkan dalam NuGet , dokumentasi terperinci tertulis. Anda sudah dapat menggunakan migrator baru, dan saya akan memberi tahu Anda bagaimana tampilannya, mengapa ia memiliki versi nomor 3.0.0 (meskipun ini adalah rilis pertama) dan mengapa diperlukan ketika ada Migrasi EF dan FluentMigrator .
Bagaimana semuanya dimulai
9 tahun yang lalu, pada tahun 2009, saya bekerja sebagai pengembang ASP.NET. Ketika kami merilis proyek kami, orang khusus begadang dan, pada saat yang sama memperbarui file di server, mengeksekusi skrip SQL dengan tangannya memperbarui database di prod. Kami mencari alat yang akan melakukan ini secara otomatis dan menemukan proyek Migrator.NET .
Migrator mengusulkan ide baru untuk saat itu - untuk mengatur perubahan basis data dalam bentuk migrasi. Setiap migrasi berisi sebagian kecil dari perubahan dan memiliki nomor versi ke mana basis data akan pergi setelah selesai. Migrator sendiri melacak versi dan melakukan migrasi yang diperlukan dalam urutan yang diperlukan. Terutama keren adalah kenyataan bahwa migrator diizinkan untuk mengatur perubahan mundur untuk setiap migrasi. Dimungkinkan pada awal migrator untuk mengatur versi yang lebih rendah dari yang sekarang, dan secara otomatis akan memutar kembali database ke versi ini, melakukan migrasi yang diperlukan dalam urutan terbalik.
[Migration(1)] public class AddAddressTable : Migration { override public void Up() { Database.AddTable("Address", new Column("id", DbType.Int32, ColumnProperty.PrimaryKey), new Column("street", DbType.String, 50), new Column("city", DbType.String, 50) ); } override public void Down() { Database.RemoveTable("Address"); } }
Ada banyak kesalahan dalam migrator itu. Dia tidak tahu cara bekerja dengan skema database selain skema default. Dalam beberapa kasus, itu menghasilkan kueri SQL yang salah, dan jika Anda menentukan nomor versi yang tidak ada, itu jatuh ke loop tak terbatas. Sebagai hasilnya, saya dan kolega-fork saya mengerjakan proyek dan memperbaiki bug di sana.
GitHub.com dengan garpu dan permintaan tariknya tidak ada di sana (kode migran ada di code.google.com ). Karena itu, kami terutama tidak repot-repot memastikan bahwa perubahan kami kembali ke proyek asli - kami hanya melihat salinan kami dan menggunakannya sendiri. Seiring waktu, kami menulis ulang sebagian besar proyek, dan saya menjadi pengelola utamanya. Kemudian saya memposting kode migrator kami di kode google dan menulis artikel di Habr . Jadi ada ECM7.Migrator.
Selama bekerja pada migrator, kami hampir sepenuhnya menulis ulang itu. Pada saat yang sama, mereka menyederhanakan API sedikit dan menutupi semuanya dengan tes otomatis. Secara pribadi, saya sangat menikmati menggunakan apa yang terjadi. Berbeda dengan migrator asli, ada perasaan dapat diandalkan dan tidak ada perasaan bahwa keajaiban aneh terjadi.
Ternyata, tidak hanya saya menyukai migrator kami. Sejauh yang saya tahu, itu digunakan di perusahaan yang cukup besar. Saya tahu tentang ABBYY, BARS Group, dan concert.ru. Jika Anda mengetik permintaan pencarian "ecm7 migrator", Anda dapat melihat di artikel hasil tentang itu, menyebutkan dalam resume, deskripsi penggunaan dalam pekerjaan siswa. Terkadang saya menerima surat dari orang asing dengan pertanyaan atau kata-kata terima kasih.
Setelah 2012, proyek ini hampir tidak berkembang. Kemampuannya saat ini mencakup semua tugas yang saya miliki dan saya tidak melihat perlunya menyelesaikan sesuatu.
ThinkingHome.Migrator
Tahun lalu, saya mulai mengerjakan proyek di .NET Core. Di sana perlu untuk memungkinkan untuk menghubungkan plugin, dan plugin harus dapat membuat struktur database yang diperlukan untuk diri mereka sendiri untuk menyimpan data mereka di sana. Ini hanya tugas semacam itu, yang cocok untuk seorang migrator.
Ef migrasi
Saya menggunakan Entity Framework Core untuk bekerja dengan database, jadi hal pertama yang saya coba adalah Migrasi EF. Sayangnya, segera saya harus meninggalkan ide untuk menggunakannya.
Migrasi Entity Framework menyeret banyak dependensi ke dalam proyek, dan saat startup mereka melakukan beberapa keajaiban khusus. Langkah ke kiri / langkah ke kanan - Anda mengalami batasan. Misalnya, migrasi kerangka kerja Entitas karena alasan tertentu harus selalu dalam perakitan yang sama dengan DbContext
. Ini artinya tidak mungkin menyimpan migrasi di dalam plugin.
Fluentmigrator
Ketika menjadi jelas bahwa Migrasi EF tidak cocok, saya mencari solusi di google dan menemukan beberapa migran open source. Yang paling canggih dari mereka, dilihat dari jumlah unduhan di NuGet dan bintang di GitHub, ternyata adalah FluentMigrator . FM sangat bagus! Dia tahu banyak dan memiliki API yang sangat nyaman. Pada awalnya saya memutuskan bahwa inilah yang saya butuhkan, tetapi kemudian beberapa masalah ditemukan.
Masalah utama adalah bahwa FluentMigrator tidak tahu bagaimana memperhitungkan beberapa urutan versi dalam database yang sama. Seperti yang saya tulis di atas, saya perlu menggunakan migrator dalam aplikasi modular. Diperlukan agar modul (plugin) dapat diinstal dan diperbarui secara terpisah satu sama lain. FluentMigrator memiliki penomoran versi ujung ke ujung. Karena itu, mustahil untuk menjalankan / memutar kembali migrasi satu plugin dari basis data tanpa memengaruhi struktur basis data dari plugin yang tersisa.
Saya mencoba mengatur perilaku yang diinginkan menggunakan tag , tetapi ini juga tidak cukup yang Anda butuhkan. FluentMigrator tidak menyimpan informasi tag untuk migrasi selesai. Selain itu, tag terkait dengan migrasi, bukan rakitan. Ini sangat aneh, mengingat bahwa titik masuk untuk bermigrasi adalah tepat rakitan. Pada prinsipnya, itu mungkin untuk melakukan versi paralel dengan cara ini, tetapi Anda perlu menulis pembungkus yang agak rumit atas migrator.
Port ECM7.Migrator ke .NET Core
Pada awalnya, opsi ini bahkan tidak dipertimbangkan. Pada saat itu, versi .NET Core saat ini adalah 1.1 dan API-nya kurang kompatibel dengan .NET Framework, tempat ECM7.Migrator bekerja. Saya yakin porting itu ke .NET Core akan sulit dan memakan waktu. Ketika tidak ada pilihan untuk "menyelesaikannya", saya memutuskan untuk mencobanya. Tugas itu lebih mudah dari yang saya harapkan. Anehnya, itu bekerja segera. Hanya suntingan kecil yang diperlukan. Karena logika migrator ditutupi oleh tes, semua tempat yang rusak segera terlihat dan saya segera memperbaikinya.
Sekarang saya telah porting adapter hanya untuk empat DBMS: MS SQL Server, PostgreSQL, MySQL, SQLite. Saya tidak mem-port adapter untuk Oracle (karena masih belum ada klien yang stabil untuk .NET Core), MS SQL Server CE (karena hanya berfungsi di bawah Windows dan saya tidak punya tempat untuk menjalankannya) dan Firebird (karena itu tidak terlalu populer, port nanti). Pada prinsipnya, jika Anda perlu membuat penyedia untuk ini atau DBMS lainnya - ini cukup sederhana.
Kode sumber untuk migrator baru ada di GitHub . Mengkonfigurasi peluncuran tes untuk setiap DBMS di Travis CI. Utilitas baris perintah ( .NET Core Global Tool ) ditulis yang dapat dengan mudah diinstal dari NuGet . Dokumentasi ditulis - saya berusaha sangat keras untuk menulis secara terperinci dan jelas dan, sepertinya, itu terjadi. Anda dapat mengambil dan menggunakan!
Sedikit tentang namanya ...
Migrator baru tidak memiliki kompatibilitas mundur dengan yang lama. Mereka bekerja pada platform yang berbeda dan mereka memiliki API yang berbeda. Oleh karena itu, proyek ini diterbitkan dengan nama yang berbeda.
Nama itu dipilih oleh proyek ThinkingHome , di mana saya mengirim migrator. Sebenarnya, ECM7.Migrator juga dinamai untuk proyek yang sedang saya kerjakan saat itu.
Mungkin lebih baik memilih nama netral, tetapi tidak terpikir oleh saya untuk memiliki opsi yang baik. Jika Anda tahu ini - tulis di komentar. Belum terlambat untuk mengganti nama semuanya.
Nomor versi menunjukkan 3.0.0, karena migrator baru adalah kelanjutan logis dari yang lama.
Mulai cepat
Jadi, mari kita coba menggunakan migrator.
Semua perubahan basis data dicatat dalam kode migrasi - kelas yang ditulis dalam bahasa pemrograman (misalnya, dalam C #). Kelas migrasi mewarisi dari kelas basis Migration
dari paket ThinkingHome.Migrator.Framework . Di dalamnya, Anda perlu mengganti metode kelas dasar: Apply
(terapkan perubahan) dan Revert
(gulung balik perubahan). Di dalam metode ini, pengembang, menggunakan API khusus, menjelaskan tindakan yang perlu dilakukan pada database.
Juga, kelas migrasi harus ditandai dengan atribut [Migration]
dan menunjukkan versi ke mana database akan pergi setelah perubahan ini dibuat.
Contoh migrasi
using ThinkingHome.Migrator.Framework; [Migration(12)] public class MyTestMigration : Migration { public override void Apply() { // : Database.AddTable("CustomerAddress", new Column("customerId", DbType.Int32, ColumnProperty.PrimaryKey), new Column("addressId", DbType.Int32, ColumnProperty.PrimaryKey)); } public override void Revert() { // : Database.RemoveTable("CustomerAddress"); // , // Revert } }
Bagaimana cara menjalankannya
Migrasi dikompilasi menjadi file .dll. Setelah itu, Anda dapat melakukan perubahan database menggunakan utilitas konsol migrate-database
. Untuk memulai, instal dari NuGet .
dotnet tool install -g thinkinghome.migrator.cli
Jalankan migrate-database
, tentukan jenis DBMS yang diperlukan, string koneksi, dan path ke file .dll dengan migrasi.
migrate-database postgres "host=localhost;port=5432;database=migrations;" /path/to/migrations.dll
Jalankan melalui API
Anda dapat melakukan migrasi melalui API dari aplikasi Anda sendiri. Misalnya, Anda dapat menulis aplikasi yang, ketika diluncurkan, membuat sendiri struktur basis data yang diinginkan.
Untuk melakukan ini, hubungkan paket ThinkingHome.Migrator dari NuGet dan paket dengan penyedia transformasi untuk DBMS yang diperlukan untuk proyek Anda. Setelah itu, buat sebuah instance dari kelas ThinkingHome.Migrator.Migrator
dan panggil metode Migrate
, dengan meneruskan versi database yang diperlukan sebagai parameter.
var version = -1; // -1 var provider = "postgres"; var connectionString = "host=localhost;port=5432;database=migrations;"; var assembly = Assembly.LoadFrom("/path/to/migrations.dll"); using (var migrator = new Migrator(provider, connectionString, assembly)) { migrator.Migrate(version); }
Omong-omong, Anda dapat membandingkan dengan contoh peluncuran FluentMigrator.
Kesimpulan
Saya mencoba membuat alat sederhana tanpa kecanduan dan sihir kompleks. Tampaknya berhasil dengan cukup baik. Proyek belum mentah untuk waktu yang lama, semuanya tercakup dalam tes, ada dokumentasi rinci dalam bahasa Rusia. Jika Anda menggunakan .NET Core 2.1, coba migrator baru . Kemungkinan besar Anda akan menyukainya juga.