Perancah (Rekayasa Terbalik)
Rekayasa terbalik adalah proses perancah kelas jenis entitas dan kelas DbContext berdasarkan skema database. Hal ini dapat dilakukan menggunakan Scaffold-DbContext
perintah alat EF Core Package Manager Console (PMC) atau dotnet ef dbcontext scaffold
perintah alat .NET Command-line Interface (CLI).
Catatan
Perancah jenis entitas dan yang DbContext
didokumentasikan di sini berbeda dari perancah pengontrol di ASP.NET Core menggunakan Visual Studio, yang tidak didokumentasikan di sini.
Tip
Jika Anda menggunakan Visual Studio, cobalah ekstensi komunitas EF Core Power Tools . Alat-alat ini menyediakan alat grafis yang dibangun di atas alat baris perintah EF Core dan menawarkan alur kerja tambahan dan opsi kustomisasi.
Prasyarat
- Sebelum perancah, Anda harus menginstal alat PMC, yang hanya berfungsi pada Visual Studio, atau alat .NET CLI, yang di semua platform yang didukung oleh .NET.
- Instal paket NuGet untuk
Microsoft.EntityFrameworkCore.Design
pada proyek tempat Anda membuat perancah. - Instal paket NuGet untuk penyedia database yang menargetkan skema database yang ingin Anda perancah.
Argumen yang diperlukan
Perintah PMC dan .NET CLI memiliki dua argumen yang diperlukan: string koneksi ke database, dan penyedia database EF Core untuk digunakan.
String koneksi
Peringatan
Artikel ini menggunakan database lokal yang tidak mengharuskan pengguna untuk diautentikasi. Aplikasi produksi harus menggunakan alur autentikasi paling aman yang tersedia. Untuk informasi selengkapnya tentang autentikasi untuk aplikasi pengujian dan produksi yang disebarkan, lihat Mengamankan alur autentikasi.
Argumen pertama untuk perintah merupakan string koneksi ke database. Alat menggunakan string koneksi ini untuk membaca skema database.
Bagaimana string koneksi dikutip dan diloloskan tergantung pada shell yang digunakan untuk menjalankan perintah. Lihat dokumentasi shell. Misalnya, PowerShell memerlukan pelepasan $
, tetapi tidak \
.
Contoh berikut membuat perancah jenis entitas dan dari Chinook
database yang DbContext
terletak di instans SQL Server LocalDB komputer, yang menggunakan Microsoft.EntityFrameworkCore.SqlServer
penyedia database.
dotnet ef dbcontext scaffold "Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Chinook" Microsoft.EntityFrameworkCore.SqlServer
String koneksi dalam kode perancah
Secara default, perancah akan menyertakan string koneksi dalam kode perancah, tetapi dengan peringatan. Contohnya:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. You can avoid scaffolding the connection string by using the Name= syntax to read it from configuration - see https://go.microsoft.com/fwlink/?linkid=2131148. For more guidance on storing connection strings, see http://go.microsoft.com/fwlink/?LinkId=723263.
=> optionsBuilder.UseSqlServer("Data Source=(LocalDb)\\MSSQLLocalDB;Database=AllTogetherNow");
Ini dilakukan agar kode yang dihasilkan tidak crash ketika pertama kali digunakan, yang akan menjadi pengalaman pembelajaran yang sangat buruk. Namun, seperti yang dikatakan peringatan, string koneksi seharusnya tidak ada dalam kode produksi. Lihat DbContext Lifetime, Configuration, and Initialization untuk berbagai cara yang dapat dikelola string koneksi.
Tip
Opsi -NoOnConfiguring
(Visual Studio PMC) atau --no-onconfiguring
(.NET CLI) dapat diteruskan untuk menekan pembuatan OnConfiguring
metode yang berisi string koneksi.
Nama penyedia
Argumen kedua merupakan nama penyedia. Nama penyedia pada umumnya sama dengan nama paket NuGet penyedia. Misalnya, untuk SQL Server atau Azure SQL, gunakan Microsoft.EntityFrameworkCore.SqlServer
.
Opsi baris Perintah
Proses perancah dapat dikontrol oleh berbagai opsi baris perintah.
Menentukan tabel dan tampilan
Secara default, semua tabel dan tampilan dalam skema database di-scaffold ke dalam jenis entitas. Anda dapat membatasi tabel dan tampilan mana yang di-scaffold dengan menentukan skema dan tabel.
Argumen -Schemas
(Visual Studio PMC) atau --schema
(.NET CLI) menentukan skema tabel dan tampilan untuk jenis entitas mana yang akan dihasilkan. Jika argumen ini dihilangkan, maka semua skema disertakan. Jika opsi ini digunakan, maka semua tabel dan tampilan dalam skema akan disertakan dalam model, bahkan jika mereka tidak secara eksplisit disertakan menggunakan -Tables
atau --table
.
Argumen -Tables
(Visual Studio PMC) atau --table
(.NET CLI) menentukan tabel dan tampilan untuk jenis entitas mana yang akan dihasilkan. Tabel atau tampilan dalam skema tertentu dapat disertakan menggunakan format 'schema.table' atau 'schema.view'. Jika opsi ini dihilangkan, maka semua tabel dan tampilan disertakan. |
Misalnya, untuk membuat perancah hanya Artists
tabel dan Albums
:
dotnet ef dbcontext scaffold ... --table Artist --table Album
Untuk membuat perancah semua tabel dan tampilan dari Customer
skema dan Contractor
:
dotnet ef dbcontext scaffold ... --schema Customer --schema Contractor
Misalnya, untuk membuat perancah Purchases
tabel dari Customer
skema, dan Accounts
tabel dan Contracts
dari Contractor
skema:
dotnet ef dbcontext scaffold ... --table Customer.Purchases --table Contractor.Accounts --table Contractor.Contracts
Mempertahankan nama database
Nama tabel serta kolom diperbaiki agar lebih cocok dengan konvensi penamaan .NET untuk jenis dan properti secara default. -UseDatabaseNames
Menentukan (Visual Studio PMC) atau --use-database-names
(.NET CLI) akan menonaktifkan perilaku ini mempertahankan nama database asli sebanyak mungkin. Pengidentifikasi .NET yang tidak valid masih akan diperbaiki serta nama yang disintesis seperti properti navigasi masih akan sesuai dengan konvensi penamaan .NET.
Misalnya, pertimbangkan tabel berikut:
CREATE TABLE [BLOGS] (
[ID] int NOT NULL IDENTITY,
[Blog_Name] nvarchar(max) NOT NULL,
CONSTRAINT [PK_Blogs] PRIMARY KEY ([ID]));
CREATE TABLE [posts] (
[id] int NOT NULL IDENTITY,
[postTitle] nvarchar(max) NOT NULL,
[post content] nvarchar(max) NOT NULL,
[1 PublishedON] datetime2 NOT NULL,
[2 DeletedON] datetime2 NULL,
[BlogID] int NOT NULL,
CONSTRAINT [PK_Posts] PRIMARY KEY ([id]),
CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogID]) REFERENCES [Blogs] ([ID]) ON DELETE CASCADE);
Secara default, jenis entitas berikut akan di-scaffold dari tabel ini:
public partial class Blog
{
public int Id { get; set; }
public string BlogName { get; set; } = null!;
public virtual ICollection<Post> Posts { get; set; } = new List<Post>();
}
public partial class Post
{
public int Id { get; set; }
public string PostTitle { get; set; } = null!;
public string PostContent { get; set; } = null!;
public DateTime _1PublishedOn { get; set; }
public DateTime? _2DeletedOn { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; } = null!;
public virtual ICollection<Tag> Tags { get; set; } = new List<Tag>();
}
Namun, menggunakan -UseDatabaseNames
atau --use-database-names
menghasilkan jenis entitas berikut:
public partial class BLOG
{
public int ID { get; set; }
public string Blog_Name { get; set; } = null!;
public virtual ICollection<post> posts { get; set; } = new List<post>();
}
public partial class post
{
public int id { get; set; }
public string postTitle { get; set; } = null!;
public string post_content { get; set; } = null!;
public DateTime _1_PublishedON { get; set; }
public DateTime? _2_DeletedON { get; set; }
public int BlogID { get; set; }
public virtual BLOG Blog { get; set; } = null!;
}
Menggunakan atribut pemetaan (alias Anotasi Data)
Jenis entitas dikonfigurasi menggunakan ModelBuilder
API secara OnModelCreating
default. Tentukan -DataAnnotations
(PMC) atau --data-annotations
(.NET Core CLI) untuk menggunakan atribut pemetaan jika memungkinkan.
Misalnya, penggunaan API Fasih akan membuat perancah ini:
entity.Property(e => e.Title)
.IsRequired()
.HasMaxLength(160);
Ketika menggunakan Anotasi Data akan membuat perancah ini:
[Required]
[StringLength(160)]
public string Title { get; set; }
Tip
Beberapa aspek model tidak dapat dikonfigurasi menggunakan atribut pemetaan. Perancah masih akan menggunakan API pembuatan model untuk menangani kasus-kasus ini.
Nama DbContext
Nama kelas perancah DbContext
akan menjadi nama database yang diakhiri dengan Konteks secara default. Untuk menentukan yang berbeda, gunakan -Context
dalam PMC dan --context
di CLI .NET Core.
Direktori dan namespace target
Kelas entitas serta kelas DbContext diperancah ke direktori akar proyek serta menggunakan namespace default proyek.
Anda dapat menentukan direktori tempat kelas di-scaffold menggunakan --output-dir
, dan --context-dir
dapat digunakan untuk menyusun kelas DbContext ke direktori terpisah dari kelas jenis entitas:
dotnet ef dbcontext scaffold ... --context-dir Data --output-dir Models
Secara default, namespace layanan akan menjadi namespace layanan akar plus nama subdirektori apa pun yang berada di bawah direktori akar proyek. Namun, Anda dapat mengambil alih namespace untuk semua kelas output dengan menggunakan --namespace
. Anda juga dapat mengganti namespace hanya untuk kelas DbContext menggunakan --context-namespace
:
dotnet ef dbcontext scaffold ... --namespace Your.Namespace --context-namespace Your.DbContext.Namespace
Kode perancah
Hasil perancah dari database yang ada adalah:
- File yang berisi kelas yang mewarisi dari
DbContext
- File untuk setiap jenis entitas
Tip
Mulai EF7, Anda juga bisa menggunakan template teks T4 untuk menyesuaikan kode yang dihasilkan. Lihat Template Rekayasa Terbalik Kustom untuk detail selengkapnya.
Jenis referensi C# Nullable
Perancah dapat membuat model EF dan jenis entitas yang menggunakan jenis referensi nullable C# (NRTs). Penggunaan NRT di-scaffold secara otomatis ketika dukungan NRT diaktifkan dalam proyek C# tempat kode sedang dibuat perancahnya.
Misalnya, tabel berikut berisi Tags
kedua kolom string yang tidak dapat diubah ke null:
CREATE TABLE [Tags] (
[Id] int NOT NULL IDENTITY,
[Name] nvarchar(max) NOT NULL,
[Description] nvarchar(max) NULL,
CONSTRAINT [PK_Tags] PRIMARY KEY ([Id]));
Ini menghasilkan properti string nullable dan non-nullable yang sesuai di kelas yang dihasilkan:
public partial class Tag
{
public Tag()
{
Posts = new HashSet<Post>();
}
public int Id { get; set; }
public string Name { get; set; } = null!;
public string? Description { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
Demikian pula, tabel berikut berisi Posts
hubungan yang diperlukan ke Blogs
tabel:
CREATE TABLE [Posts] (
[Id] int NOT NULL IDENTITY,
[Title] nvarchar(max) NOT NULL,
[Contents] nvarchar(max) NOT NULL,
[PostedOn] datetime2 NOT NULL,
[UpdatedOn] datetime2 NULL,
[BlogId] int NOT NULL,
CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]));
Ini menghasilkan perancah hubungan yang tidak dapat diubah ke null (diperlukan) antara blog:
public partial class Blog
{
public Blog()
{
Posts = new HashSet<Post>();
}
public int Id { get; set; }
public string Name { get; set; } = null!;
public virtual ICollection<Post> Posts { get; set; }
}
Dan posting:
public partial class Post
{
public Post()
{
Tags = new HashSet<Tag>();
}
public int Id { get; set; }
public string Title { get; set; } = null!;
public string Contents { get; set; } = null!;
public DateTime PostedOn { get; set; }
public DateTime? UpdatedOn { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; } = null!;
public virtual ICollection<Tag> Tags { get; set; }
}
Hubungan banyak ke banyak
Proses perancah mendeteksi tabel gabungan sederhana dan secara otomatis menghasilkan pemetaan banyak ke banyak untuk mereka. Misalnya, pertimbangkan tabel untuk Posts
dan Tags
, dan tabel PostTag
gabungan yang menghubungkannya:
CREATE TABLE [Tags] (
[Id] int NOT NULL IDENTITY,
[Name] nvarchar(max) NOT NULL,
[Description] nvarchar(max) NULL,
CONSTRAINT [PK_Tags] PRIMARY KEY ([Id]));
CREATE TABLE [Posts] (
[Id] int NOT NULL IDENTITY,
[Title] nvarchar(max) NOT NULL,
[Contents] nvarchar(max) NOT NULL,
[PostedOn] datetime2 NOT NULL,
[UpdatedOn] datetime2 NULL,
CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]));
CREATE TABLE [PostTag] (
[PostsId] int NOT NULL,
[TagsId] int NOT NULL,
CONSTRAINT [PK_PostTag] PRIMARY KEY ([PostsId], [TagsId]),
CONSTRAINT [FK_PostTag_Posts_TagsId] FOREIGN KEY ([TagsId]) REFERENCES [Tags] ([Id]) ON DELETE CASCADE,
CONSTRAINT [FK_PostTag_Tags_PostsId] FOREIGN KEY ([PostsId]) REFERENCES [Posts] ([Id]) ON DELETE CASCADE);
Saat di-scaffold, ini menghasilkan kelas untuk Post:
public partial class Post
{
public Post()
{
Tags = new HashSet<Tag>();
}
public int Id { get; set; }
public string Title { get; set; } = null!;
public string Contents { get; set; } = null!;
public DateTime PostedOn { get; set; }
public DateTime? UpdatedOn { get; set; }
public int BlogId { get; set; }
public virtual Blog Blog { get; set; } = null!;
public virtual ICollection<Tag> Tags { get; set; }
}
Dan kelas untuk Tag:
public partial class Tag
{
public Tag()
{
Posts = new HashSet<Post>();
}
public int Id { get; set; }
public string Name { get; set; } = null!;
public string? Description { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
Tapi tidak ada kelas untuk PostTag
meja. Sebagai gantinya, konfigurasi untuk hubungan banyak ke banyak di-scaffold:
entity.HasMany(d => d.Tags)
.WithMany(p => p.Posts)
.UsingEntity<Dictionary<string, object>>(
"PostTag",
l => l.HasOne<Tag>().WithMany().HasForeignKey("PostsId"),
r => r.HasOne<Post>().WithMany().HasForeignKey("TagsId"),
j =>
{
j.HasKey("PostsId", "TagsId");
j.ToTable("PostTag");
j.HasIndex(new[] { "TagsId" }, "IX_PostTag_TagsId");
});
Bahasa pemrograman lainnya
Paket EF Core yang diterbitkan oleh kode C# perancah Microsoft. Namun, sistem perancah yang mendasar mendukung model plugin untuk perancah ke bahasa lain. Model plugin ini digunakan oleh berbagai proyek yang dijalankan komunitas, misalnya:
- EntityFrameworkCore.VisualBasic menyediakan dukungan untuk Visual Basic
- EFCore.FSharp menyediakan dukungan untuk F#
Menyesuaikan kode
Dimulai dengan EF7, salah satu cara terbaik untuk menyesuaikan kode yang dihasilkan adalah dengan menyesuaikan templat T4 yang digunakan untuk menghasilkannya.
Kode juga dapat diubah setelah dibuat, tetapi cara terbaik untuk melakukan ini tergantung pada apakah Anda ingin menjalankan kembali proses perancah ketika model database berubah.
Perancah sekali saja
Dengan pendekatan ini, kode perancah menyediakan titik awal untuk pemetaan berbasis kode ke depannya. Setiap perubahan pada kode yang dihasilkan dapat dibuat sesuai keinginan - itu menjadi kode normal seperti kode lain dalam proyek Anda.
Menjaga database dan model EF tetap sinkron dapat dilakukan dengan salah satu dari dua cara:
- Beralih menggunakan migrasi database EF Core, dan gunakan jenis entitas dan konfigurasi model EF sebagai sumber kebenaran, menggunakan migrasi untuk mendorong skema.
- Perbarui jenis entitas dan konfigurasi EF secara manual saat database berubah. Misalnya, jika kolom baru ditambahkan ke tabel, tambahkan properti untuk kolom ke jenis entitas yang dipetakan, dan tambahkan konfigurasi yang diperlukan menggunakan atribut pemetaan dan/atau kode di
OnModelCreating
. Ini relatif mudah, dengan satu-satunya tantangan nyata adalah proses untuk memastikan bahwa perubahan database dicatat atau terdeteksi dalam beberapa cara sehingga pengembang yang bertanggung jawab atas kode dapat bereaksi.
Perancah berulang
Pendekatan alternatif untuk perancah sekali adalah dengan perancah ulang setiap kali database berubah. Ini akan menimpa kode yang sebelumnya dibuat perancah, yang berarti setiap perubahan yang dilakukan pada jenis entitas atau konfigurasi EF dalam kode tersebut akan hilang.
[TIP] Secara default, perintah EF tidak akan menimpa kode yang ada untuk melindungi dari kehilangan kode yang tidak disengaja. Argumen
-Force
(Visual Studio PMC) atau--force
(.NET CLI) dapat digunakan untuk memaksa penimpaan file yang ada.
Karena kode perancah akan ditimpa, yang terbaik adalah tidak memodifikasinya secara langsung, tetapi sebaliknya mengandalkan kelas dan metode parsial, dan mekanisme di EF Core yang memungkinkan konfigurasi ditimpa. Khususnya:
DbContext
Kelas dan kelas entitas dihasilkan sebagai parsial. Ini memungkinkan pengenalan anggota dan kode tambahan dalam file terpisah yang tidak akan ditimpa saat perancah dijalankan.- Kelas
DbContext
berisi metode parsial yang disebutOnModelCreatingPartial
. Implementasi metode ini dapat ditambahkan ke kelas parsial untukDbContext
. Kemudian akan dipanggil setelahOnModelCreating
dipanggil. - Konfigurasi model yang
ModelBuilder
dibuat menggunakan API mengambil alih konfigurasi apa pun yang dilakukan oleh konvensi atau atribut pemetaan, serta konfigurasi sebelumnya yang dilakukan pada pembuat model. Ini berarti bahwa kode diOnModelCreatingPartial
dapat digunakan untuk mengambil alih konfigurasi yang dihasilkan oleh proses perancah, tanpa perlu menghapus konfigurasi tersebut.
Terakhir, ingatlah bahwa dimulai dengan EF7, templat T4 yang digunakan untuk menghasilkan kode dapat disesuaikan. Ini seringkali merupakan pendekatan yang lebih efektif daripada perancah dengan default dan kemudian memodifikasi dengan kelas dan/atau metode parsial.
Cara kerjanya
Rekayasa terbalik dimulai dengan pembacaan skema database. Hal ini membaca informasi tentang tabel, kolom, batasan, serta indeks.
Selanjutnya, ia menggunakan informasi skema untuk membuat model EF Core. Tabel akan digunakan untuk membuat jenis entitas; kolom digunakan untuk membuat properti; serta kunci asing digunakan untuk membuat hubungan.
Akhirnya, model akan digunakan untuk menghasilkan kode. Kelas jenis entitas yang sesuai, API Fasih, dan anotasi data akan dibuat untuk membuat ulang model yang sama dari aplikasi Anda.
Batasan
- Tidak semua hal tentang model dapat diwakili menggunakan skema database. Misalnya, informasi tentang hierarki warisan, tipe >, dan table splitting tidak ada di skema database. Karena itu, konstruksi-konstruksi ini tidak akan pernah di-scaffold.
- Selain itu, sejumlah jenis kolom mungkin tidak didukung oleh penyedia EF Core. Kolom ini tidak disertakan dalam model.
- Anda dapat menentukan token konkurensi dalam model EF Core untuk mencegah dua pengguna memperbarui entitas yang sama secara bersamaan. Beberapa database memiliki jenis khusus untuk mewakili jenis kolom ini (misalnya, rowversion di SQL Server) dalam hal ini kita dapat merekayasa balik informasi ini; namun, token konkurensi lainnya tidak akan di-scaffold.