Bagikan melalui


Tutorial: Menerapkan Pewarisan dengan EF dalam aplikasi MVC 5 ASP.NET

Dalam tutorial sebelumnya Anda menangani pengecualian konkurensi. Tutorial ini akan menunjukkan kepada Anda cara menerapkan pewarisan dalam model data.

Dalam pemrograman berorientasi objek, Anda dapat menggunakan pewarisan untuk memfasilitasi penggunaan kembali kode. Dalam tutorial ini, Anda akan mengubah Instructor kelas dan Student sehingga mereka berasal dari Person kelas dasar yang berisi properti seperti LastName yang umum bagi instruktur dan siswa. Anda tidak akan menambahkan atau mengubah halaman web apa pun, tetapi Anda akan mengubah beberapa kode dan perubahan tersebut akan secara otomatis tercermin dalam database.

Di tutorial ini, Anda akan:

  • Pelajari cara memetakan pewarisan ke database
  • Membuat kelas Orang
  • Memperbarui Instruktur dan Siswa
  • Menambahkan Orang ke Model
  • Membuat dan Memperbarui Migrasi
  • Menguji implementasi
  • Sebarkan ke Azure

Prasyarat

Pewarisan peta ke database

Kelas Instructor dan Student dalam School model data memiliki beberapa properti yang identik:

Student_and_Instructor_classes

Misalkan Anda ingin menghilangkan kode redundan untuk properti yang dibagikan oleh Instructor entitas dan Student . Atau Anda ingin menulis layanan yang dapat memformat nama tanpa peduli apakah nama tersebut berasal dari instruktur atau siswa. Anda dapat membuat Person kelas dasar yang hanya berisi properti bersama tersebut Instructor , lalu membuat entitas dan Student mewarisi dari kelas dasar tersebut, seperti yang ditunjukkan dalam ilustrasi berikut:

Student_and_Instructor_classes_deriving_from_Person_class

Ada beberapa cara struktur pewarisan ini dapat diwakili dalam database. Anda bisa memiliki Person tabel yang menyertakan informasi tentang siswa dan instruktur dalam satu tabel. Beberapa kolom hanya dapat berlaku untuk instruktur (HireDate), beberapa hanya untuk siswa (EnrollmentDate), beberapa untuk keduanya (LastName, FirstName). Biasanya, Anda akan memiliki kolom diskriminator untuk menunjukkan jenis mana yang diwakili setiap baris. Misalnya, kolom diskriminator mungkin memiliki "Instruktur" untuk instruktur dan "Siswa" untuk siswa.

Tabel per hierarchy_example

Pola pembuatan struktur pewarisan entitas dari tabel database tunggal ini disebut pewarisan tabel per hierarki (TPH).

Alternatifnya adalah membuat database terlihat lebih seperti struktur pewarisan. Misalnya, Anda hanya dapat memiliki bidang nama dalam Person tabel dan memiliki tabel dan Student terpisah Instructor dengan bidang tanggal.

Tabel per type_inheritance

Pola pembuatan tabel database untuk setiap kelas entitas ini disebut warisan tabel per jenis (TPT).

Namun opsi lain adalah memetakan semua jenis non-abstrak ke tabel individual. Semua properti kelas, termasuk properti yang diwariskan, memetakan ke kolom tabel terkait. Pola ini disebut warisan Table-per-Concrete Class (TPC). Jika Anda menerapkan pewarisan TPC untuk Personkelas , , Studentdan Instructor seperti yang ditunjukkan sebelumnya, Student tabel dan Instructor tidak akan terlihat berbeda setelah menerapkan pewarisan daripada yang mereka lakukan sebelumnya.

Pola pewarisan TPC dan TPH umumnya memberikan performa yang lebih baik dalam Kerangka Kerja Entitas daripada pola pewarisan TPT, karena pola TPT dapat menghasilkan kueri gabungan yang kompleks.

Tutorial ini menunjukkan cara menerapkan pewarisan TPH. TPH adalah pola pewarisan default dalam Kerangka Kerja Entitas, jadi yang harus Anda lakukan adalah membuat Person kelas, mengubah Instructor kelas dan Student untuk berasal dari Person, menambahkan kelas baru ke DbContext, dan membuat migrasi. (Untuk informasi tentang cara menerapkan pola pewarisan lainnya, lihat Memetakan Pewarisan Tabel Per Jenis (TPT) dan Memetakan Warisan Kelas Tabel Per Beton (TPC) dalam dokumentasi Kerangka Kerja Entitas MSDN.)

Membuat kelas Orang

Di folder Model , buat Person.cs dan ganti kode templat dengan kode berikut:

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

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

        [Required]
        [StringLength(50)]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }
        [Required]
        [StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]
        [Column("FirstName")]
        [Display(Name = "First Name")]
        public string FirstMidName { get; set; }

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

Memperbarui Instruktur dan Siswa

Sekarang perbarui Instructor.cs dan Student.cs untuk mewarisi nilai dari Person.sc.

Di Instructor.cs, dapatkan Instructor kelas dari Person kelas dan hapus bidang kunci dan nama. Kode akan terlihat seperti contoh berikut:

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

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

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

Buat perubahan serupa dengan Student.cs. Kelas Student akan terlihat seperti contoh berikut:

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

namespace ContosoUniversity.Models
{
    public class Student : Person
    {
        [DataType(DataType.Date)]
        [DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
        [Display(Name = "Enrollment Date")]
        public DateTime EnrollmentDate { get; set; }

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

Menambahkan Orang ke Model

Di SchoolContext.cs, tambahkan DbSet properti untuk Person jenis entitas:

public DbSet<Person> People { get; set; }

Ini semua yang dibutuhkan Entity Framework untuk mengonfigurasi warisan tabel per hierarki. Seperti yang akan Anda lihat, saat database diperbarui, database akan memiliki Person tabel sebagai pengganti Student tabel dan Instructor .

Membuat dan Memperbarui Migrasi

Di Package Manager Console (PMC), masukkan perintah berikut:

Add-Migration Inheritance

Jalankan Update-Database perintah di PMC. Perintah akan gagal pada saat ini karena kami memiliki data yang ada yang tidak tahu cara menangani migrasi. Anda mendapatkan pesan kesalahan seperti berikut ini:

Tidak dapat menjatuhkan objek 'dbo. Instruktur' karena dirujuk oleh batasan KUNCI ASING.

Buka Migrasi< >tanda waktu_Inheritance.cs dan ganti Up metode dengan kode berikut:

public override void Up()
{
    // Drop foreign keys and indexes that point to tables we're going to drop.
    DropForeignKey("dbo.Enrollment", "StudentID", "dbo.Student");
    DropIndex("dbo.Enrollment", new[] { "StudentID" });

    RenameTable(name: "dbo.Instructor", newName: "Person");
    AddColumn("dbo.Person", "EnrollmentDate", c => c.DateTime());
    AddColumn("dbo.Person", "Discriminator", c => c.String(nullable: false, maxLength: 128, defaultValue: "Instructor"));
    AlterColumn("dbo.Person", "HireDate", c => c.DateTime());
    AddColumn("dbo.Person", "OldId", c => c.Int(nullable: true));

    // Copy existing Student data into new Person table.
    Sql("INSERT INTO dbo.Person (LastName, FirstName, HireDate, EnrollmentDate, Discriminator, OldId) SELECT LastName, FirstName, null AS HireDate, EnrollmentDate, 'Student' AS Discriminator, ID AS OldId FROM dbo.Student");

    // Fix up existing relationships to match new PK's.
    Sql("UPDATE dbo.Enrollment SET StudentId = (SELECT ID FROM dbo.Person WHERE OldId = Enrollment.StudentId AND Discriminator = 'Student')");

    // Remove temporary key
    DropColumn("dbo.Person", "OldId");

    DropTable("dbo.Student");

    // Re-create foreign keys and indexes pointing to new table.
    AddForeignKey("dbo.Enrollment", "StudentID", "dbo.Person", "ID", cascadeDelete: true);
    CreateIndex("dbo.Enrollment", "StudentID");
}

Kode ini mengurus tugas pembaruan database berikut:

  • Menghapus batasan dan indeks kunci asing yang menunjuk ke tabel Siswa.

  • Mengganti nama tabel Instruktur sebagai Orang dan membuat perubahan yang diperlukan untuk menyimpan data Siswa:

    • Menambahkan EnrollmentDate yang dapat diubah ke null untuk siswa.
    • Menambahkan kolom Diskriminator untuk menunjukkan apakah baris adalah untuk siswa atau instruktur.
    • Membuat HireDate dapat diubah ke null karena baris siswa tidak akan memiliki tanggal sewa.
    • Menambahkan bidang sementara yang akan digunakan untuk memperbarui kunci asing yang menunjuk ke siswa. Saat Anda menyalin siswa ke dalam tabel Orang, mereka akan mendapatkan nilai kunci primer baru.
  • Menyalin data dari tabel Siswa ke dalam tabel Orang. Hal ini menyebabkan siswa mendapatkan nilai kunci primer baru yang ditetapkan.

  • Memperbaiki nilai kunci asing yang menunjuk ke siswa.

  • Membuat ulang batasan dan indeks kunci asing, sekarang mengarahkannya ke tabel Orang.

(Jika Anda telah menggunakan GUID alih-alih bilangan bulat sebagai jenis kunci utama, nilai kunci primer siswa tidak perlu berubah, dan beberapa langkah ini bisa saja dihilangkan.)

Jalankan lagi perintah update-database.

(Dalam sistem produksi Anda akan membuat perubahan yang sesuai dengan metode Down jika Anda harus menggunakannya untuk kembali ke versi database sebelumnya. Untuk tutorial ini, Anda tidak akan menggunakan metode Down.)

Catatan

Dimungkinkan untuk mendapatkan kesalahan lain saat memigrasikan data dan membuat perubahan skema. Jika Anda mendapatkan kesalahan migrasi yang tidak dapat Anda atasi, Anda dapat melanjutkan tutorial dengan mengubah string koneksi dalam file Web.config atau dengan menghapus database. Pendekatan paling sederhana adalah mengganti nama database dalam file Web.config . Misalnya, ubah nama database menjadi ContosoUniversity2 seperti yang diperlihatkan dalam contoh berikut:

<add name="SchoolContext" 
    connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=ContosoUniversity2;Integrated Security=SSPI;" 
    providerName="System.Data.SqlClient" />

Dengan database baru, tidak ada data untuk dimigrasikan, dan update-database perintah jauh lebih mungkin diselesaikan tanpa kesalahan. Untuk instruksi tentang cara menghapus database, lihat Cara Menghapus Database dari Visual Studio 2012. Jika Anda mengambil pendekatan ini untuk melanjutkan tutorial, lewati langkah penyebaran di akhir tutorial ini atau sebarkan ke situs dan database baru. Jika Anda menyebarkan pembaruan ke situs yang sama dengan yang telah Anda sebarkan, EF akan mendapatkan kesalahan yang sama di sana saat menjalankan migrasi secara otomatis. Jika Anda ingin memecahkan masalah kesalahan migrasi, sumber daya terbaik adalah salah satu forum Kerangka Kerja Entitas atau StackOverflow.com.

Menguji implementasi

Jalankan situs dan coba berbagai halaman. Semuanya bekerja sama seperti sebelumnya.

Di Server Explorer, perluas Koneksi Data\SchoolContext lalu Tabel, dan Anda melihat bahwa tabel Siswa dan Instruktur telah digantikan oleh tabel Orang . Perluas tabel Orang dan Anda melihat bahwa tabel tersebut memiliki semua kolom yang dulunya berada dalam tabel Siswa dan Instruktur .

Klik kanan tabel Orang, lalu klik Perlihatkan Data Tabel untuk melihat kolom diskriminator.

Diagram berikut mengilustrasikan struktur database Sekolah baru:

School_database_diagram

Sebarkan ke Azure

Bagian ini mengharuskan Anda untuk menyelesaikan bagian Menyebarkan aplikasi ke Azure opsional di Bagian 3, Pengurutan, Pemfilteran, dan Penomoran seri tutorial ini. Jika Anda mengalami kesalahan migrasi yang Anda selesaikan dengan menghapus database di proyek lokal Anda, lewati langkah ini; atau buat situs dan database baru, dan sebarkan ke lingkungan baru.

  1. Di Visual Studio, klik kanan proyek di Penjelajah Solusi dan pilih Terbitkan dari menu konteks.

  2. Klik Terbitkan.

    Aplikasi Web terbuka di browser default Anda.

  3. Uji aplikasi untuk memverifikasi bahwa aplikasi berfungsi.

    Pertama kali Anda menjalankan halaman yang mengakses database, Kerangka Kerja Entitas menjalankan semua metode migrasi Up yang diperlukan untuk memperbarui database dengan model data saat ini.

Mendapatkan kode

Unduh Proyek yang Selesai

Sumber Daya Tambahan:

Tautan ke sumber daya Kerangka Kerja Entitas lainnya dapat ditemukan di Akses Data ASP.NET - Sumber Daya yang Direkomendasikan.

Untuk informasi selengkapnya tentang ini dan struktur pewarisan lainnya, lihat Pola Warisan TPT dan Pola Warisan TPH pada MSDN. Dalam tutorial berikutnya, Anda akan melihat cara menangani berbagai skenario Kerangka Kerja Entitas yang relatif canggih.

Langkah berikutnya

Di tutorial ini, Anda akan:

  • Belajar memetakan pewarisan ke database
  • Membuat kelas Orang
  • Instruktur dan Siswa yang Diperbarui
  • Menambahkan Orang ke Model
  • Membuat dan Memperbarui Migrasi
  • Menguji implementasi
  • Disebarkan ke Azure

Lanjutkan ke artikel berikutnya untuk mempelajari tentang topik yang berguna untuk diperhatikan ketika Anda melampaui dasar-dasar pengembangan aplikasi web ASP.NET yang menggunakan Kode Kerangka Kerja Entitas Terlebih Dahulu.