Tutorial: Membuat model data kompleks - ASP.NET MVC dengan EF Core

Dalam tutorial sebelumnya, Anda bekerja dengan model data sederhana yang terdiri dari tiga entitas. Dalam tutorial ini, Anda akan menambahkan lebih banyak entitas dan hubungan dan Anda akan menyesuaikan model data dengan menentukan aturan pemformatan, validasi, dan pemetaan database.

Setelah selesai, kelas entitas akan membentuk model data lengkap yang ditampilkan dalam ilustrasi berikut:

Entity diagram

Di tutorial ini, Anda akan:

  • Mengkustomisasi model Data
  • Membuat perubahan pada entitas Siswa
  • Membuat entitas Instruktur
  • Membuat entitas OfficeAssignment
  • Ubah entitas Kursus
  • Membuat entitas Departemen
  • Mengubah entitas Pendaftaran
  • Memperbarui konteks database
  • Database benih dengan data pengujian
  • Menambahkan migrasi
  • Mengubah string koneksi
  • Memperbarui database

Prasyarat

Mengkustomisasi model Data

Di bagian ini Anda akan melihat cara mengkustomisasi model data dengan menggunakan atribut yang menentukan aturan pemformatan, validasi, dan pemetaan database. Kemudian di beberapa bagian berikut, Anda akan membuat model data Sekolah lengkap dengan menambahkan atribut ke kelas yang sudah Anda buat dan buat kelas baru untuk jenis entitas yang tersisa dalam model.

Atribut DataType

Untuk tanggal pendaftaran siswa, semua halaman web saat ini menampilkan waktu bersama dengan tanggal, meskipun yang Anda pedulikan untuk bidang ini adalah tanggal. Dengan menggunakan atribut anotasi data, Anda dapat membuat satu perubahan kode yang akan memperbaiki format tampilan di setiap tampilan yang menunjukkan data. Untuk melihat contoh cara melakukannya, Anda akan menambahkan atribut ke EnrollmentDate properti di Student kelas .

Di Models/Student.cs, tambahkan using pernyataan untuk System.ComponentModel.DataAnnotations namespace layanan dan tambahkan DataTypeDisplayFormat atribut ke EnrollmentDate properti , seperti yang ditunjukkan dalam contoh berikut:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        public string LastName { get; set; }
        public string FirstMidName { get; set; }
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

Atribut DataType digunakan untuk menentukan jenis data yang lebih spesifik daripada jenis intrinsik database. Dalam hal ini kita hanya ingin melacak tanggal, bukan tanggal dan waktu. DataType Enumerasi menyediakan banyak jenis data, seperti Tanggal, Waktu, Telepon Number, Mata Uang, EmailAddress, dan banyak lagi. Atribut ini DataType juga dapat memungkinkan aplikasi untuk secara otomatis menyediakan fitur khusus jenis. Misalnya, mailto: tautan dapat dibuat untuk DataType.EmailAddress, dan pemilih tanggal dapat disediakan untuk DataType.Date di browser yang mendukung HTML5. Atribut memancarkan DataType atribut HTML 5 data- (tanda hubung data yang diucapkan) yang dapat dipahami browser HTML 5. Atribut DataType tidak memberikan validasi apa pun.

DataType.Date tidak menentukan format tanggal yang ditampilkan. Secara default, bidang data ditampilkan sesuai dengan format default berdasarkan CultureInfo server.

Atribut DisplayFormat digunakan untuk secara eksplisit menentukan format tanggal:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]

Pengaturan ApplyFormatInEditMode menentukan bahwa pemformatan juga harus diterapkan saat nilai ditampilkan dalam kotak teks untuk pengeditan. (Anda mungkin tidak menginginkannya untuk beberapa bidang -- misalnya, untuk nilai mata uang, Anda mungkin tidak ingin simbol mata uang dalam kotak teks untuk diedit.)

Anda dapat menggunakan atribut dengan DisplayFormat sendirinya, tetapi umumnya merupakan ide yang baik untuk menggunakan DataType atribut juga. Atribut DataType ini menyampaikan semantik data dibandingkan dengan cara merendernya di layar, dan memberikan manfaat berikut yang tidak Anda dapatkan dengan DisplayFormat:

  • Browser dapat mengaktifkan fitur HTML5 (misalnya untuk menampilkan kontrol kalender, simbol mata uang yang sesuai dengan lokal, tautan email, beberapa validasi input sisi klien, dll.).

  • Secara default, browser akan merender data menggunakan format yang benar berdasarkan lokal Anda.

Untuk informasi selengkapnya, lihat dokumentasi pembantu< tag input>.

Jalankan aplikasi, buka halaman Indeks Siswa dan perhatikan bahwa waktu tidak lagi ditampilkan untuk tanggal pendaftaran. Hal yang sama akan berlaku untuk tampilan apa pun yang menggunakan model Siswa.

Students index page showing dates without times

Atribut StringLength

Anda juga dapat menentukan aturan validasi data dan pesan kesalahan validasi menggunakan atribut. Atribut StringLength mengatur panjang maksimum dalam database dan menyediakan validasi sisi klien dan sisi server untuk ASP.NET Core MVC. Anda juga dapat menentukan panjang string minimum dalam atribut ini, tetapi nilai minimum tidak berdampak pada skema database.

Misalkan Anda ingin memastikan bahwa pengguna tidak memasukkan lebih dari 50 karakter untuk nama. Untuk menambahkan batasan ini, tambahkan StringLength atribut ke LastName properti dan FirstMidName , seperti yang ditunjukkan dalam contoh berikut:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        [StringLength(50)]
        public string LastName { get; set; }
        [StringLength(50)]
        public string FirstMidName { get; set; }
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

Atribut StringLength tidak akan mencegah pengguna memasukkan spasi kosong untuk nama. Anda dapat menggunakan RegularExpression atribut untuk menerapkan pembatasan pada input. Misalnya, kode berikut mengharuskan karakter pertama menjadi huruf besar dan karakter yang tersisa menjadi alfabet:

[RegularExpression(@"^[A-Z]+[a-zA-Z]*$")]

Atribut MaxLength ini menyediakan fungsionalitas yang StringLength mirip dengan atribut tetapi tidak memberikan validasi sisi klien.

Model database sekarang telah berubah dengan cara yang memerlukan perubahan dalam skema database. Anda akan menggunakan migrasi untuk memperbarui skema tanpa kehilangan data apa pun yang mungkin telah Anda tambahkan ke database dengan menggunakan UI aplikasi.

Simpan perubahan Anda dan bangun proyek. Kemudian buka jendela perintah di folder proyek dan masukkan perintah berikut:

dotnet ef migrations add MaxLengthOnNames
dotnet ef database update

Perintah migrations add memperingatkan bahwa kehilangan data dapat terjadi, karena perubahan membuat panjang maksimum lebih pendek untuk dua kolom. Migrasi membuat file bernama <timeStamp>_MaxLengthOnNames.cs. File ini berisi kode dalam Up metode yang akan memperbarui database agar sesuai dengan model data saat ini. Perintah database update menjalankan kode itu.

Tanda waktu yang diawali dengan nama file migrasi digunakan oleh Kerangka Kerja Entitas untuk memesan migrasi. Anda dapat membuat beberapa migrasi sebelum menjalankan perintah update-database, lalu semua migrasi diterapkan dalam urutan pembuatannya.

Jalankan aplikasi, pilih tab Siswa , klik Buat Baru, dan coba masukkan nama yang lebih panjang dari 50 karakter. Aplikasi harus mencegah Anda melakukan ini.

Atribut Kolom

Anda juga dapat menggunakan atribut untuk mengontrol bagaimana kelas dan properti Anda dipetakan ke database. Misalkan Anda telah menggunakan nama FirstMidName untuk bidang nama depan karena bidang mungkin juga berisi nama tengah. Tetapi Anda ingin kolom database diberi nama FirstName, karena pengguna yang akan menulis kueri ad-hoc terhadap database terbiasa dengan nama tersebut. Untuk membuat pemetaan ini, Anda dapat menggunakan Column atribut .

Atribut Column menentukan bahwa ketika database dibuat, kolom Student tabel yang memetakan ke FirstMidName properti akan diberi nama FirstName. Dengan kata lain, ketika kode Anda merujuk ke Student.FirstMidName, data akan berasal dari atau diperbarui di FirstName kolom Student tabel. Jika Anda tidak menentukan nama kolom, nama kolom tersebut diberi nama yang sama dengan nama properti.

Student.cs Dalam file, tambahkan pernyataan untuk System.ComponentModel.DataAnnotations.Schema dan tambahkan atribut nama kolom ke FirstMidName properti , seperti yang using ditunjukkan dalam kode yang disorot berikut:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        [StringLength(50)]
        public string LastName { get; set; }
        [StringLength(50)]
        [Column("FirstName")]
        public string FirstMidName { get; set; }
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        public DateTime EnrollmentDate { get; set; }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

Penambahan Column atribut mengubah model yang SchoolContextmendukung , sehingga tidak akan cocok dengan database.

Simpan perubahan Anda dan bangun proyek. Kemudian buka jendela perintah di folder proyek dan masukkan perintah berikut untuk membuat migrasi lain:

dotnet ef migrations add ColumnFirstName
dotnet ef database update

Di SQL Server Object Explorer, buka perancang tabel Siswa dengan mengklik ganda tabel Siswa .

Students table in SSOX after migrations

Sebelum Anda menerapkan dua migrasi pertama, kolom nama berjenis nvarchar(MAX). Sekarang adalah nvarchar(50) dan nama kolom telah berubah dari FirstMidName menjadi FirstName.

Catatan

Jika Anda mencoba mengkompilasi sebelum selesai membuat semua kelas entitas di bagian berikut, Anda mungkin mendapatkan kesalahan kompilator.

Perubahan pada entitas Siswa

Student entity

Di Models/Student.cs, ganti kode yang Anda tambahkan sebelumnya dengan kode berikut. Perubahan disorot.

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Student
    {
        public int ID { get; set; }
        [Required]
        [StringLength(50)]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
        [Required]
        [StringLength(50)]
        [Column("FirstName")]
        [Display(Name = "First Name")]
        public string FirstMidName { get; set; }
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = "Enrollment Date")]
        public DateTime EnrollmentDate { get; set; }
        [Display(Name = "Full Name")]
        public string FullName
        {
            get
            {
                return LastName + ", " + FirstMidName;
            }
        }

        public ICollection<Enrollment> Enrollments { get; set; }
    }
}

Atribut Wajib

Atribut Required membuat properti nama menjadi bidang yang diperlukan. Atribut Required tidak diperlukan untuk jenis yang tidak dapat diubah ke null seperti jenis nilai (DateTime, int, double, float, dll.). Jenis yang tidak boleh null secara otomatis diperlakukan sebagai bidang yang diperlukan.

Atribut Required harus digunakan untuk MinimumLengthMinimumLength diberlakukan.

[Display(Name = "Last Name")]
[Required]
[StringLength(50, MinimumLength=2)]
public string LastName { get; set; }

Atribut Tampilan

Atribut Display menentukan bahwa keterangan untuk kotak teks harus "Nama Depan", "Nama Belakang", "Nama Lengkap", dan "Tanggal Pendaftaran" alih-alih nama properti di setiap instans (yang tidak memiliki ruang membagi kata).

Properti terhitung FullName

FullName adalah properti terhitung yang mengembalikan nilai yang dibuat dengan menggabungkan dua properti lainnya. Oleh karena itu hanya memiliki aksesor get, dan tidak ada FullName kolom yang akan dihasilkan dalam database.

Membuat entitas Instruktur

Instructor entity

Buat Models/Instructor.cs, mengganti kode templat dengan kode berikut:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Instructor
    {
        public int ID { get; set; }

        [Required]
        [Display(Name = "Last Name")]
        [StringLength(50)]
        public string LastName { get; set; }

        [Required]
        [Column("FirstName")]
        [Display(Name = "First Name")]
        [StringLength(50)]
        public string FirstMidName { get; set; }

        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = "Hire Date")]
        public DateTime HireDate { get; set; }

        [Display(Name = "Full Name")]
        public string FullName
        {
            get { return LastName + ", " + FirstMidName; }
        }

        public ICollection<CourseAssignment> CourseAssignments { get; set; }
        public OfficeAssignment OfficeAssignment { get; set; }
    }
}

Perhatikan bahwa beberapa properti sama di entitas Siswa dan Instruktur. Dalam tutorial Implementing Inheritance nanti dalam seri ini, Anda akan merefaktor kode ini untuk menghilangkan redundansi.

Anda dapat menempatkan beberapa atribut pada satu baris, sehingga Anda juga dapat menulis HireDate atribut sebagai berikut:

[DataType(DataType.Date),Display(Name = "Hire Date"),DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]

Properti navigasi CourseAssignments dan OfficeAssignment

Properti CourseAssignments dan OfficeAssignment adalah properti navigasi.

Instruktur dapat mengajarkan sejumlah kursus, sehingga CourseAssignments didefinisikan sebagai koleksi.

public ICollection<CourseAssignment> CourseAssignments { get; set; }

Jika properti navigasi dapat menampung beberapa entitas, jenisnya harus berupa daftar di mana entri dapat ditambahkan, dihapus, dan diperbarui. Anda dapat menentukan ICollection<T> atau jenis seperti List<T> atau HashSet<T>. Jika Anda menentukan ICollection<T>, EF membuat HashSet<T> koleksi secara default.

Alasan mengapa ini adalah CourseAssignment entitas dijelaskan di bawah ini di bagian tentang hubungan banyak ke banyak.

Aturan bisnis Contoso University menyatakan bahwa instruktur hanya dapat memiliki paling banyak satu kantor, sehingga OfficeAssignment properti memiliki satu entitas OfficeAssignment (yang mungkin null jika tidak ada kantor yang ditetapkan).

public OfficeAssignment OfficeAssignment { get; set; }

Membuat entitas OfficeAssignment

OfficeAssignment entity

Buat Models/OfficeAssignment.cs dengan kode berikut:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class OfficeAssignment
    {
        [Key]
        public int InstructorID { get; set; }
        [StringLength(50)]
        [Display(Name = "Office Location")]
        public string Location { get; set; }

        public Instructor Instructor { get; set; }
    }
}

Atribut Kunci

Ada hubungan satu-ke-nol-atau-satu antara Instructor dan OfficeAssignment entitas. Penugasan kantor hanya ada dalam kaitannya dengan instruktur yang ditetapkannya, dan oleh karena itu kunci utamanya juga merupakan kunci asingnya untuk Instructor entitas. Tetapi Kerangka Kerja Entitas tidak dapat secara otomatis dikenali InstructorID sebagai kunci utama entitas ini karena namanya tidak mengikuti ID konvensi penamaan atau classnameID . Oleh karena itu, Key atribut digunakan untuk mengidentifikasinya sebagai kunci:

[Key]
public int InstructorID { get; set; }

Anda juga dapat menggunakan Key atribut jika entitas memang memiliki kunci utamanya sendiri tetapi Anda ingin memberi nama properti sesuatu selain classnameID atau ID.

Secara default, EF memperlakukan kunci sebagai non-database yang dihasilkan karena kolom adalah untuk hubungan identifikasi.

Properti navigasi Instruktur

Entitas Instruktur memiliki properti navigasi yang dapat diubah ke OfficeAssignment null (karena instruktur mungkin tidak memiliki penetapan kantor), dan entitas OfficeAssignment memiliki properti navigasi yang tidak dapat Instructor diubah ke null (karena penetapan kantor tidak dapat ada tanpa instruktur -- InstructorID tidak dapat diubah ke null). Ketika entitas Instruktur memiliki entitas OfficeAssignment terkait, setiap entitas akan memiliki referensi ke entitas lainnya di properti navigasinya.

Anda dapat meletakkan [Required] atribut pada properti navigasi Instruktur untuk menentukan bahwa harus ada instruktur terkait, tetapi Anda tidak perlu melakukannya karena InstructorID kunci asing (yang juga merupakan kunci untuk tabel ini) tidak dapat diubah ke null.

Ubah entitas Kursus

Course entity

Di Models/Course.cs, ganti kode yang Anda tambahkan sebelumnya dengan kode berikut. Perubahan disorot.

using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Course
    {
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        [Display(Name = "Number")]
        public int CourseID { get; set; }

        [StringLength(50, MinimumLength = 3)]
        public string Title { get; set; }

        [Range(0, 5)]
        public int Credits { get; set; }

        public int DepartmentID { get; set; }

        public Department Department { get; set; }
        public ICollection<Enrollment> Enrollments { get; set; }
        public ICollection<CourseAssignment> CourseAssignments { get; set; }
    }
}

Entitas kursus memiliki properti DepartmentID kunci asing yang menunjuk ke entitas Departemen terkait dan memiliki Department properti navigasi.

Kerangka Kerja Entitas tidak mengharuskan Anda menambahkan properti kunci asing ke model data Anda saat Anda memiliki properti navigasi untuk entitas terkait. EF secara otomatis membuat kunci asing dalam database di mana pun mereka diperlukan dan membuat properti bayangan untuk mereka. Tetapi memiliki kunci asing dalam model data dapat membuat pembaruan lebih sederhana dan lebih efisien. Misalnya, saat Anda mengambil Course entitas untuk diedit, Department entitas null jika Anda tidak memuatnya, jadi ketika Anda memperbarui Course entitas, Anda harus terlebih dahulu mengambil Department entitas. Saat properti DepartmentID kunci asing disertakan dalam model data, Anda tidak perlu mengambil Department entitas sebelum memperbarui.

Atribut DatabaseGenerated

Atribut DatabaseGenerated dengan None parameter pada CourseID properti menentukan bahwa nilai kunci utama disediakan oleh pengguna daripada yang dihasilkan oleh database.

[DatabaseGenerated(DatabaseGeneratedOption.None)]
[Display(Name = "Number")]
public int CourseID { get; set; }

Secara default, Entity Framework mengasumsikan bahwa nilai kunci utama dihasilkan oleh database. Itulah yang Anda inginkan dalam sebagian besar skenario. Namun, untuk Course entitas, Anda akan menggunakan nomor kursus yang ditentukan pengguna seperti seri 1000 untuk satu departemen, seri 2000 untuk departemen lain, dan sebagainya.

Atribut DatabaseGenerated juga dapat digunakan untuk menghasilkan nilai default, seperti dalam kasus kolom database yang digunakan untuk merekam tanggal baris dibuat atau diperbarui. Untuk informasi selengkapnya, lihat Properti yang Dihasilkan.

Properti kunci dan navigasi asing

Properti kunci asing dan properti navigasi di Course entitas mencerminkan hubungan berikut:

Kursus ditugaskan ke satu departemen, jadi ada DepartmentID kunci asing dan Department properti navigasi karena alasan yang disebutkan di atas.

public int DepartmentID { get; set; }
public Department Department { get; set; }

Kursus dapat memiliki sejumlah siswa yang terdaftar di dalamnya, sehingga Enrollments properti navigasi adalah koleksi:

public ICollection<Enrollment> Enrollments { get; set; }

Kursus dapat diajarkan oleh beberapa instruktur, sehingga CourseAssignments properti navigasi adalah koleksi (jenisnya CourseAssignment dijelaskan nanti):

public ICollection<CourseAssignment> CourseAssignments { get; set; }

Membuat entitas Departemen

Department entity

Buat Models/Department.cs dengan kode berikut:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class Department
    {
        public int DepartmentID { get; set; }

        [StringLength(50, MinimumLength = 3)]
        public string Name { get; set; }

        [DataType(DataType.Currency)]
        [Column(TypeName = "money")]
        public decimal Budget { get; set; }

        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = "Start Date")]
        public DateTime StartDate { get; set; }

        public int? InstructorID { get; set; }

        public Instructor Administrator { get; set; }
        public ICollection<Course> Courses { get; set; }
    }
}

Atribut Kolom

Sebelumnya Anda menggunakan Column atribut untuk mengubah pemetaan nama kolom. Dalam kode untuk Department entitas, Column atribut sedang digunakan untuk mengubah pemetaan jenis data SQL sehingga kolom akan ditentukan menggunakan jenis SQL Server money dalam database:

[Column(TypeName="money")]
public decimal Budget { get; set; }

Pemetaan kolom umumnya tidak diperlukan, karena Kerangka Kerja Entitas memilih jenis data SQL Server yang sesuai berdasarkan jenis CLR yang Anda tentukan untuk properti . Jenis CLR decimal memetakan ke jenis SQL Server decimal . Tetapi dalam hal ini Anda tahu bahwa kolom akan menyimpan jumlah mata uang, dan jenis data uang lebih sesuai untuk itu.

Properti kunci dan navigasi asing

Properti kunci asing dan navigasi mencerminkan hubungan berikut:

Departemen mungkin atau mungkin tidak memiliki administrator, dan administrator selalu menjadi instruktur. InstructorID Oleh karena itu properti disertakan sebagai kunci asing ke entitas Instruktur, dan tanda tanya ditambahkan setelah int penunjukan jenis untuk menandai properti sebagai nullable. Properti navigasi diberi nama Administrator tetapi menyimpan entitas Instruktur:

public int? InstructorID { get; set; }
public Instructor Administrator { get; set; }

Departemen mungkin memiliki banyak kursus, jadi ada properti navigasi Kursus:

public ICollection<Course> Courses { get; set; }

Catatan

Menurut konvensi, Kerangka Kerja Entitas memungkinkan penghapusan berjenjang untuk kunci asing yang tidak dapat diubah ke null dan untuk hubungan banyak ke banyak. Ini dapat mengakibatkan aturan penghapusan kaskade melingkar, yang akan menyebabkan pengecualian ketika Anda mencoba menambahkan migrasi. Misalnya, jika Anda tidak menentukan Department.InstructorID properti sebagai nullable, EF akan mengonfigurasi aturan penghapusan berjenjang untuk menghapus departemen saat Anda menghapus instruktur, yang bukan yang ingin Anda lakukan. Jika aturan bisnis Anda mengharuskan InstructorID properti tidak dapat diubah ke null, Anda harus menggunakan pernyataan API fasih berikut untuk menonaktifkan penghapusan bertingkat pada hubungan:

modelBuilder.Entity<Department>()
   .HasOne(d => d.Administrator)
   .WithMany()
   .OnDelete(DeleteBehavior.Restrict)

Mengubah entitas Pendaftaran

Enrollment entity

Di Models/Enrollment.cs, ganti kode yang Anda tambahkan sebelumnya dengan kode berikut:

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public enum Grade
    {
        A, B, C, D, F
    }

    public class Enrollment
    {
        public int EnrollmentID { get; set; }
        public int CourseID { get; set; }
        public int StudentID { get; set; }
        [DisplayFormat(NullDisplayText = "No grade")]
        public Grade? Grade { get; set; }

        public Course Course { get; set; }
        public Student Student { get; set; }
    }
}

Properti kunci dan navigasi asing

Properti kunci asing dan properti navigasi mencerminkan hubungan berikut:

Catatan pendaftaran adalah untuk satu kursus, jadi ada CourseID properti kunci asing dan Course properti navigasi:

public int CourseID { get; set; }
public Course Course { get; set; }

Catatan pendaftaran adalah untuk satu siswa, jadi ada StudentID properti kunci asing dan Student properti navigasi:

public int StudentID { get; set; }
public Student Student { get; set; }

Hubungan banyak-ke-Banyak

Ada hubungan banyak ke banyak antara Student entitas dan Course , dan Enrollment entitas berfungsi sebagai tabel gabungan banyak-ke-banyak dengan payload dalam database. "Dengan payload" berarti bahwa Enrollment tabel berisi data tambahan selain kunci asing untuk tabel yang digabungkan (dalam hal ini, kunci primer dan Grade properti).

Ilustrasi berikut menunjukkan seperti apa hubungan ini dalam diagram entitas. (Diagram ini dihasilkan menggunakan Entity Framework Power Tools untuk EF 6.x; membuat diagram bukan bagian dari tutorial, itu hanya digunakan di sini sebagai ilustrasi.)

Student-Course many to many relationship

Setiap garis hubungan memiliki 1 di satu ujung dan tanda bintang (*) di ujung lainnya, menunjukkan hubungan satu-ke-banyak.

Enrollment Jika tabel tidak menyertakan informasi nilai, tabel hanya perlu berisi dua kunci CourseID asing dan StudentID. Dalam hal ini, itu akan menjadi tabel gabungan banyak ke banyak tanpa payload (atau tabel gabungan murni) dalam database. Entitas Instructor dan Course memiliki hubungan banyak ke banyak, dan langkah Anda selanjutnya adalah membuat kelas entitas untuk berfungsi sebagai tabel gabungan tanpa payload.

EF Core mendukung tabel gabungan implisit untuk hubungan banyak ke banyak, tetapi tutoral ini belum diperbarui untuk menggunakan tabel gabungan implisit. Lihat Hubungan Banyak ke Banyak, Razor versi Halaman dari tutorial ini yang telah diperbarui.

Entitas CourseAssignment

CourseAssignment entity

Buat Models/CourseAssignment.cs dengan kode berikut:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace ContosoUniversity.Models
{
    public class CourseAssignment
    {
        public int InstructorID { get; set; }
        public int CourseID { get; set; }
        public Instructor Instructor { get; set; }
        public Course Course { get; set; }
    }
}

Menggabungkan nama entitas

Tabel gabungan diperlukan dalam database untuk hubungan banyak ke banyak Kursus Instruktur, dan harus diwakili oleh kumpulan entitas. Adalah umum untuk memberi nama entitas EntityName1EntityName2gabungan , yang dalam hal ini adalah CourseInstructor. Namun, kami sarankan Anda memilih nama yang menjelaskan hubungan. Model data dimulai dengan sederhana dan berkembang, dengan gabungan tanpa payload sering mendapatkan payload nanti. Jika Anda memulai dengan nama entitas deskriptif, Anda tidak perlu mengubah nama nanti. Idealnya, entitas gabungan akan memiliki nama alami sendiri (mungkin kata tunggal) di domain bisnis. Misalnya, Buku dan Pelanggan dapat ditautkan melalui Peringkat. Untuk hubungan ini, CourseAssignment adalah pilihan yang lebih baik daripada CourseInstructor.

Kunci komposit

Karena kunci asing tidak dapat diubah ke null dan bersama-sama secara unik mengidentifikasi setiap baris tabel, tidak perlu kunci primer terpisah. Properti InstructorID dan CourseID harus berfungsi sebagai kunci primer komposit. Satu-satunya cara untuk mengidentifikasi kunci primer komposit ke EF adalah dengan menggunakan API yang fasih (tidak dapat dilakukan dengan menggunakan atribut). Anda akan melihat cara mengonfigurasi kunci primer komposit di bagian berikutnya.

Kunci komposit memastikan bahwa meskipun Anda dapat memiliki beberapa baris untuk satu kursus, dan beberapa baris untuk satu instruktur, Anda tidak dapat memiliki beberapa baris untuk instruktur dan kursus yang sama. Entitas Enrollment gabungan mendefinisikan kunci utamanya sendiri, sehingga duplikat dari jenis ini dimungkinkan. Untuk mencegah duplikat tersebut, Anda dapat menambahkan indeks unik pada bidang kunci asing, atau mengonfigurasi Enrollment dengan kunci komposit utama yang mirip CourseAssignmentdengan . Untuk informasi selengkapnya, lihat Indeks.

Memperbarui konteks database

Tambahkan kode yang disorot berikut ke Data/SchoolContext.cs file:

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

namespace ContosoUniversity.Data
{
    public class SchoolContext : DbContext
    {
        public SchoolContext(DbContextOptions<SchoolContext> options) : base(options)
        {
        }

        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
        public DbSet<Student> Students { get; set; }
        public DbSet<Department> Departments { get; set; }
        public DbSet<Instructor> Instructors { get; set; }
        public DbSet<OfficeAssignment> OfficeAssignments { get; set; }
        public DbSet<CourseAssignment> CourseAssignments { get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable("Course");
            modelBuilder.Entity<Enrollment>().ToTable("Enrollment");
            modelBuilder.Entity<Student>().ToTable("Student");
            modelBuilder.Entity<Department>().ToTable("Department");
            modelBuilder.Entity<Instructor>().ToTable("Instructor");
            modelBuilder.Entity<OfficeAssignment>().ToTable("OfficeAssignment");
            modelBuilder.Entity<CourseAssignment>().ToTable("CourseAssignment");

            modelBuilder.Entity<CourseAssignment>()
                .HasKey(c => new { c.CourseID, c.InstructorID });
        }
    }
}

Kode ini menambahkan entitas baru dan mengonfigurasi kunci primer komposit entitas CourseAssignment.

Tentang alternatif API yang fasih

Kode dalam OnModelCreating metode DbContext kelas menggunakan API fasih untuk mengonfigurasi perilaku EF. API disebut "fasih" karena sering digunakan dengan merangkai serangkaian panggilan metode bersama-sama ke dalam satu pernyataan, seperti dalam contoh ini dari EF Core dokumentasi:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Url)
        .IsRequired();
}

Dalam tutorial ini, Anda menggunakan API fasih hanya untuk pemetaan database yang tidak dapat Anda lakukan dengan atribut. Namun, Anda juga dapat menggunakan API fasih untuk menentukan sebagian besar aturan pemformatan, validasi, dan pemetaan yang dapat Anda lakukan dengan menggunakan atribut. Beberapa atribut seperti MinimumLength tidak dapat diterapkan dengan API yang fasih. Seperti disebutkan sebelumnya, MinimumLength tidak mengubah skema, itu hanya menerapkan aturan validasi sisi klien dan server.

Beberapa pengembang lebih suka menggunakan API yang fasih secara eksklusif sehingga mereka dapat menjaga kelas entitas mereka tetap "bersih." Anda dapat mencampur atribut dan API yang fasih jika mau, dan ada beberapa penyesuaian yang hanya dapat dilakukan dengan menggunakan API yang fasih, tetapi secara umum praktik yang direkomendasikan adalah memilih salah satu dari dua pendekatan ini dan menggunakannya secara konsisten sebanyak mungkin. Jika Anda menggunakan keduanya, perhatikan bahwa di mana pun ada konflik, Fluent API mengambil alih atribut.

Untuk informasi selengkapnya tentang atribut vs. API yang fasih, lihat Metode konfigurasi.

Diagram Entitas Memperlihatkan Hubungan

Ilustrasi berikut menunjukkan diagram yang dibuat Entity Framework Power Tools untuk model Sekolah yang telah selesai.

Entity diagram

Selain garis hubungan satu ke banyak (1 hingga *), Anda dapat melihat di sini garis hubungan satu-ke-nol-atau-satu (1 hingga 0,.1) antara Instructor entitas dan OfficeAssignment dan garis hubungan nol atau satu-ke-banyak (0,.1 ke *) antara entitas Instruktur dan Departemen.

Database benih dengan data pengujian

Ganti kode dalam Data/DbInitializer.cs file dengan kode berikut untuk menyediakan data benih untuk entitas baru yang telah Anda buat.

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using ContosoUniversity.Models;

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            //context.Database.EnsureCreated();

            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }

            var students = new Student[]
            {
                new Student { FirstMidName = "Carson",   LastName = "Alexander",
                    EnrollmentDate = DateTime.Parse("2010-09-01") },
                new Student { FirstMidName = "Meredith", LastName = "Alonso",
                    EnrollmentDate = DateTime.Parse("2012-09-01") },
                new Student { FirstMidName = "Arturo",   LastName = "Anand",
                    EnrollmentDate = DateTime.Parse("2013-09-01") },
                new Student { FirstMidName = "Gytis",    LastName = "Barzdukas",
                    EnrollmentDate = DateTime.Parse("2012-09-01") },
                new Student { FirstMidName = "Yan",      LastName = "Li",
                    EnrollmentDate = DateTime.Parse("2012-09-01") },
                new Student { FirstMidName = "Peggy",    LastName = "Justice",
                    EnrollmentDate = DateTime.Parse("2011-09-01") },
                new Student { FirstMidName = "Laura",    LastName = "Norman",
                    EnrollmentDate = DateTime.Parse("2013-09-01") },
                new Student { FirstMidName = "Nino",     LastName = "Olivetto",
                    EnrollmentDate = DateTime.Parse("2005-09-01") }
            };

            foreach (Student s in students)
            {
                context.Students.Add(s);
            }
            context.SaveChanges();

            var instructors = new Instructor[]
            {
                new Instructor { FirstMidName = "Kim",     LastName = "Abercrombie",
                    HireDate = DateTime.Parse("1995-03-11") },
                new Instructor { FirstMidName = "Fadi",    LastName = "Fakhouri",
                    HireDate = DateTime.Parse("2002-07-06") },
                new Instructor { FirstMidName = "Roger",   LastName = "Harui",
                    HireDate = DateTime.Parse("1998-07-01") },
                new Instructor { FirstMidName = "Candace", LastName = "Kapoor",
                    HireDate = DateTime.Parse("2001-01-15") },
                new Instructor { FirstMidName = "Roger",   LastName = "Zheng",
                    HireDate = DateTime.Parse("2004-02-12") }
            };

            foreach (Instructor i in instructors)
            {
                context.Instructors.Add(i);
            }
            context.SaveChanges();

            var departments = new Department[]
            {
                new Department { Name = "English",     Budget = 350000,
                    StartDate = DateTime.Parse("2007-09-01"),
                    InstructorID  = instructors.Single( i => i.LastName == "Abercrombie").ID },
                new Department { Name = "Mathematics", Budget = 100000,
                    StartDate = DateTime.Parse("2007-09-01"),
                    InstructorID  = instructors.Single( i => i.LastName == "Fakhouri").ID },
                new Department { Name = "Engineering", Budget = 350000,
                    StartDate = DateTime.Parse("2007-09-01"),
                    InstructorID  = instructors.Single( i => i.LastName == "Harui").ID },
                new Department { Name = "Economics",   Budget = 100000,
                    StartDate = DateTime.Parse("2007-09-01"),
                    InstructorID  = instructors.Single( i => i.LastName == "Kapoor").ID }
            };

            foreach (Department d in departments)
            {
                context.Departments.Add(d);
            }
            context.SaveChanges();

            var courses = new Course[]
            {
                new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3,
                    DepartmentID = departments.Single( s => s.Name == "Engineering").DepartmentID
                },
                new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3,
                    DepartmentID = departments.Single( s => s.Name == "Economics").DepartmentID
                },
                new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3,
                    DepartmentID = departments.Single( s => s.Name == "Economics").DepartmentID
                },
                new Course {CourseID = 1045, Title = "Calculus",       Credits = 4,
                    DepartmentID = departments.Single( s => s.Name == "Mathematics").DepartmentID
                },
                new Course {CourseID = 3141, Title = "Trigonometry",   Credits = 4,
                    DepartmentID = departments.Single( s => s.Name == "Mathematics").DepartmentID
                },
                new Course {CourseID = 2021, Title = "Composition",    Credits = 3,
                    DepartmentID = departments.Single( s => s.Name == "English").DepartmentID
                },
                new Course {CourseID = 2042, Title = "Literature",     Credits = 4,
                    DepartmentID = departments.Single( s => s.Name == "English").DepartmentID
                },
            };

            foreach (Course c in courses)
            {
                context.Courses.Add(c);
            }
            context.SaveChanges();

            var officeAssignments = new OfficeAssignment[]
            {
                new OfficeAssignment {
                    InstructorID = instructors.Single( i => i.LastName == "Fakhouri").ID,
                    Location = "Smith 17" },
                new OfficeAssignment {
                    InstructorID = instructors.Single( i => i.LastName == "Harui").ID,
                    Location = "Gowan 27" },
                new OfficeAssignment {
                    InstructorID = instructors.Single( i => i.LastName == "Kapoor").ID,
                    Location = "Thompson 304" },
            };

            foreach (OfficeAssignment o in officeAssignments)
            {
                context.OfficeAssignments.Add(o);
            }
            context.SaveChanges();

            var courseInstructors = new CourseAssignment[]
            {
                new CourseAssignment {
                    CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID,
                    InstructorID = instructors.Single(i => i.LastName == "Kapoor").ID
                    },
                new CourseAssignment {
                    CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID,
                    InstructorID = instructors.Single(i => i.LastName == "Harui").ID
                    },
                new CourseAssignment {
                    CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID,
                    InstructorID = instructors.Single(i => i.LastName == "Zheng").ID
                    },
                new CourseAssignment {
                    CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID,
                    InstructorID = instructors.Single(i => i.LastName == "Zheng").ID
                    },
                new CourseAssignment {
                    CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID,
                    InstructorID = instructors.Single(i => i.LastName == "Fakhouri").ID
                    },
                new CourseAssignment {
                    CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID,
                    InstructorID = instructors.Single(i => i.LastName == "Harui").ID
                    },
                new CourseAssignment {
                    CourseID = courses.Single(c => c.Title == "Composition" ).CourseID,
                    InstructorID = instructors.Single(i => i.LastName == "Abercrombie").ID
                    },
                new CourseAssignment {
                    CourseID = courses.Single(c => c.Title == "Literature" ).CourseID,
                    InstructorID = instructors.Single(i => i.LastName == "Abercrombie").ID
                    },
            };

            foreach (CourseAssignment ci in courseInstructors)
            {
                context.CourseAssignments.Add(ci);
            }
            context.SaveChanges();

            var enrollments = new Enrollment[]
            {
                new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Alexander").ID,
                    CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID,
                    Grade = Grade.A
                },
                    new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Alexander").ID,
                    CourseID = courses.Single(c => c.Title == "Microeconomics" ).CourseID,
                    Grade = Grade.C
                    },
                    new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Alexander").ID,
                    CourseID = courses.Single(c => c.Title == "Macroeconomics" ).CourseID,
                    Grade = Grade.B
                    },
                    new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").ID,
                    CourseID = courses.Single(c => c.Title == "Calculus" ).CourseID,
                    Grade = Grade.B
                    },
                    new Enrollment {
                        StudentID = students.Single(s => s.LastName == "Alonso").ID,
                    CourseID = courses.Single(c => c.Title == "Trigonometry" ).CourseID,
                    Grade = Grade.B
                    },
                    new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Alonso").ID,
                    CourseID = courses.Single(c => c.Title == "Composition" ).CourseID,
                    Grade = Grade.B
                    },
                    new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Anand").ID,
                    CourseID = courses.Single(c => c.Title == "Chemistry" ).CourseID
                    },
                    new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Anand").ID,
                    CourseID = courses.Single(c => c.Title == "Microeconomics").CourseID,
                    Grade = Grade.B
                    },
                new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Barzdukas").ID,
                    CourseID = courses.Single(c => c.Title == "Chemistry").CourseID,
                    Grade = Grade.B
                    },
                    new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Li").ID,
                    CourseID = courses.Single(c => c.Title == "Composition").CourseID,
                    Grade = Grade.B
                    },
                    new Enrollment {
                    StudentID = students.Single(s => s.LastName == "Justice").ID,
                    CourseID = courses.Single(c => c.Title == "Literature").CourseID,
                    Grade = Grade.B
                    }
            };

            foreach (Enrollment e in enrollments)
            {
                var enrollmentInDataBase = context.Enrollments.Where(
                    s =>
                            s.Student.ID == e.StudentID &&
                            s.Course.CourseID == e.CourseID).SingleOrDefault();
                if (enrollmentInDataBase == null)
                {
                    context.Enrollments.Add(e);
                }
            }
            context.SaveChanges();
        }
    }
}

Seperti yang Anda lihat di tutorial pertama, sebagian besar kode ini hanya membuat objek entitas baru dan memuat data sampel ke dalam properti sebagaimana diperlukan untuk pengujian. Perhatikan bagaimana hubungan banyak-ke-banyak ditangani: kode membuat hubungan dengan membuat entitas di Enrollments dan CourseAssignment menggabungkan set entitas.

Menambahkan migrasi

Simpan perubahan Anda dan bangun proyek. Kemudian buka jendela perintah di folder proyek dan masukkan migrations add perintah (jangan lakukan perintah update-database):

dotnet ef migrations add ComplexDataModel

Anda mendapatkan peringatan tentang kemungkinan kehilangan data.

An operation was scaffolded that may result in the loss of data. Please review the migration for accuracy.
Done. To undo this action, use 'ef migrations remove'

Jika Anda mencoba menjalankan database update perintah pada saat ini (jangan melakukannya), Anda akan mendapatkan kesalahan berikut:

Pernyataan ALTER TABLE berkonflik dengan batasan KUNCI ASING "FK_dbo. Course_dbo. Department_DepartmentID". Konflik terjadi dalam database "ContosoUniversity", tabel "dbo. Departemen", kolom 'DepartmentID'.

Terkadang ketika Anda menjalankan migrasi dengan data yang ada, Anda perlu menyisipkan data stub ke dalam database untuk memenuhi batasan kunci asing. Kode yang dihasilkan dalam Up metode menambahkan kunci Course asing yang tidak dapat DepartmentID diubah ke tabel. Jika sudah ada baris dalam tabel Kursus saat kode berjalan, AddColumn operasi gagal karena SQL Server tidak tahu nilai apa yang harus dimasukkan ke dalam kolom yang tidak boleh null. Untuk tutorial ini, Anda akan menjalankan migrasi pada database baru, tetapi dalam aplikasi produksi Anda harus membuat migrasi menangani data yang ada, sehingga petunjuk berikut menunjukkan contoh cara melakukannya.

Untuk membuat migrasi ini berfungsi dengan data yang ada, Anda harus mengubah kode untuk memberi kolom baru nilai default, dan membuat departemen stub bernama "Temp" untuk bertindak sebagai departemen default. Akibatnya, baris Kursus yang ada semuanya akan terkait dengan departemen "Temp" setelah Up metode berjalan.

  • Buka file {timestamp}_ComplexDataModel.cs.

  • Komentari baris kode yang menambahkan kolom DepartmentID ke tabel Kursus.

    migrationBuilder.AlterColumn<string>(
        name: "Title",
        table: "Course",
        maxLength: 50,
        nullable: true,
        oldClrType: typeof(string),
        oldNullable: true);
                
    //migrationBuilder.AddColumn<int>(
    //    name: "DepartmentID",
    //    table: "Course",
    //    nullable: false,
    //    defaultValue: 0);
    
  • Tambahkan kode yang disorot berikut setelah kode yang membuat tabel Departemen:

    migrationBuilder.CreateTable(
        name: "Department",
        columns: table => new
        {
            DepartmentID = table.Column<int>(nullable: false)
                .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
            Budget = table.Column<decimal>(type: "money", nullable: false),
            InstructorID = table.Column<int>(nullable: true),
            Name = table.Column<string>(maxLength: 50, nullable: true),
            StartDate = table.Column<DateTime>(nullable: false)
        },
        constraints: table =>
        {
            table.PrimaryKey("PK_Department", x => x.DepartmentID);
            table.ForeignKey(
                name: "FK_Department_Instructor_InstructorID",
                column: x => x.InstructorID,
                principalTable: "Instructor",
                principalColumn: "ID",
                onDelete: ReferentialAction.Restrict);
        });
    
    migrationBuilder.Sql("INSERT INTO dbo.Department (Name, Budget, StartDate) VALUES ('Temp', 0.00, GETDATE())");
    // Default value for FK points to department created above, with
    // defaultValue changed to 1 in following AddColumn statement.
    
    migrationBuilder.AddColumn<int>(
        name: "DepartmentID",
        table: "Course",
        nullable: false,
        defaultValue: 1);
    

Dalam aplikasi produksi, Anda akan menulis kode atau skrip untuk menambahkan baris Departemen dan menghubungkan baris Kursus ke baris Departemen baru. Anda kemudian tidak akan lagi memerlukan departemen "Temp" atau nilai default pada Course.DepartmentID kolom.

Simpan perubahan Anda dan bangun proyek.

Mengubah string koneksi

Anda sekarang memiliki kode baru di DbInitializer kelas yang menambahkan data benih untuk entitas baru ke database kosong. Untuk membuat EF membuat database kosong baru, ubah nama database di string koneksi appsettings.json menjadi ContosoUniversity3 atau beberapa nama lain yang belum Anda gunakan di komputer yang Anda gunakan.

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=ContosoUniversity3;Trusted_Connection=True;MultipleActiveResultSets=true"
  },

Simpan perubahan Anda ke appsettings.json.

Catatan

Sebagai alternatif untuk mengubah nama database, Anda bisa menghapus database. Gunakan SQL Server Object Explorer (SSOX) atau database drop perintah CLI:

dotnet ef database drop

Memperbarui database

Setelah Anda mengubah nama database atau menghapus database, jalankan database update perintah di jendela perintah untuk menjalankan migrasi.

dotnet ef database update

Jalankan aplikasi untuk menyebabkan DbInitializer.Initialize metode berjalan dan mengisi database baru.

Buka database di SSOX seperti yang Anda lakukan sebelumnya, dan perluas simpul Tabel untuk melihat bahwa semua tabel telah dibuat. (Jika Anda masih membuka SSOX dari waktu sebelumnya, klik Tombol Refresh .)

Tables in SSOX

Jalankan aplikasi untuk memicu kode penginisialisasi yang menyemai database.

Klik kanan tabel CourseAssignment dan pilih Tampilkan Data untuk memverifikasi bahwa ia memiliki data di dalamnya.

CourseAssignment data in SSOX

Mendapatkan kode

Unduh atau lihat aplikasi yang telah selesai.

Langkah berikutnya

Di tutorial ini, Anda akan:

  • Mengkustomisasi model Data
  • Membuat perubahan pada entitas Siswa
  • Entitas Instruktur yang Dibuat
  • Entitas OfficeAssignment yang dibuat
  • Entitas Kursus yang Dimodifikasi
  • Entitas Departemen yang Dibuat
  • Entitas Pendaftaran yang Dimodifikasi
  • Memperbarui konteks database
  • Database benih dengan data pengujian
  • Menambahkan migrasi
  • Mengubah string koneksi
  • Memperbarui database

Lanjutkan ke tutorial berikutnya untuk mempelajari selengkapnya tentang cara mengakses data terkait.