Öğretici: Devralmayı uygulama - ile MVC ASP.NET EF Core

Önceki öğreticide eşzamanlılık özel durumlarını işlemişsinizdir. Bu öğreticide, veri modelinde devralmayı nasıl uygulayacağınız gösterilir.

Nesne odaklı programlamada, kodun yeniden kullanılmasını kolaylaştırmak için devralmayı kullanabilirsiniz. Bu öğreticide, ve Student sınıflarını değiştirerek Instructor hem eğitmenler hem de öğrenciler için ortak özellikler içeren LastName bir Person temel sınıftan türetilir. Hiçbir web sayfası eklemez veya değiştirmezsiniz, ancak kodun bir bölümünü değiştirirsiniz ve bu değişiklikler otomatik olarak veritabanına yansıtılır.

Bu öğreticide şunları yaptınız:

  • Devralmayı veritabanına eşleme
  • Person sınıfını oluşturma
  • Eğitmeni ve Öğrenciyi Güncelleştirme
  • Modele Kişi Ekleme
  • Geçişleri oluşturma ve güncelleştirme
  • Uygulamayı test edin

Ön koşullar

Devralmayı veritabanına eşleme

Instructor School veri modelindeki ve Student sınıfları aynı olan çeşitli özelliklere sahiptir:

Student and Instructor classes

ve Student varlıkları tarafından Instructor paylaşılan özellikler için yedekli kodu ortadan kaldırmak istediğinizi varsayalım. Ya da adın bir eğitmenden mi yoksa öğrenciden mi geldiğiyle ilgilenmeden adları biçimlendirebilen bir hizmet yazmak istiyorsunuz. Aşağıdaki çizimde gösterildiği gibi, yalnızca bu paylaşılan özellikleri içeren bir Person temel sınıf oluşturabilir ve sınıflarının bu temel sınıftan devralınmalarını sağlayabilirsiniz InstructorStudent :

Student and Instructor classes deriving from Person class

Bu devralma yapısının veritabanında temsil edilebileceği çeşitli yollar vardır. Tek bir Person tabloda hem öğrenciler hem de eğitmenler hakkında bilgi içeren bir tablonuz olabilir. Sütunlardan bazıları yalnızca eğitmenlere (HireDate), bazıları yalnızca öğrencilere (KayıtTarihi), bazıları her ikisine de (LastName, FirstName) uygulanabilir. Normalde, her satırın hangi türü temsil ettiğini belirten bir ayırıcı sütuna sahip olursunuz. Örneğin, ayrımcı sütunda eğitmenler için "Eğitmen" ve öğrenciler için "Öğrenci" olabilir.

Table-per-hierarchy example

Tek bir veritabanı tablosundan varlık devralma yapısı oluşturma deseni, hiyerarşi başına tablo (TPH) devralma olarak adlandırılır.

Alternatif olarak veritabanının devralma yapısı gibi görünmesini sağlayabilirsiniz. Örneğin, tabloda yalnızca ad alanları ve tarih alanlarıyla Person ayrı Instructor ve Student tablolar olabilir.

Uyarı

Tür Başına Tablo (TPT) 3.x tarafından EF Core desteklenmez, ancak 5.0'da EF Coreuygulanmıştır.

Table-per-type inheritance

Her varlık sınıfı için veritabanı tablosu oluşturma deseni, tür başına tablo (TPT) devralma olarak adlandırılır.

Ancak diğer bir seçenek de soyut olmayan tüm türleri tek tek tablolara eşlemektir. Devralınan özellikler de dahil olmak üzere bir sınıfın tüm özellikleri, ilgili tablonun sütunlarıyla eşler. Bu desen, Beton Başına Tablo Sınıfı (TPC) devralma olarak adlandırılır. Daha önce gösterildiği gibi , Studentve sınıfları için PersonTPC devralmayı uyguladıysanız, Student devralma uygulandıktan sonra ve Instructor tabloları öncekinden farklı Instructor görünmeyecektir.

TPT desenleri karmaşık birleştirme sorgularının neden olabileceğinden, TPC ve TPH devralma desenleri genellikle TPT devralma desenlerinden daha iyi performans sağlar.

Bu öğreticide TPH devralmayı uygulama gösterilmektedir. TPH, Entity Framework Core'un desteklediği tek devralma desenidir. Yapmanız gereken bir Person sınıf oluşturmak, ve Student sınıflarını öğesinden Persontüretecek şekilde değiştirmekInstructor, yeni sınıfı öğesine DbContexteklemek ve bir geçiş oluşturmaktır.

Bahşiş

Aşağıdaki değişiklikleri yapmadan önce projenin bir kopyasını kaydetmeyi göz önünde bulundurun. Daha sonra sorunlarla karşılaşırsanız ve yeniden başlamanız gerekirse, bu öğretici için yapılan adımları geri almak veya tüm serinin başına dönmek yerine kaydedilen projeden başlamak daha kolay olacaktır.

Person sınıfını oluşturma

Modeller klasöründe Person.cs dosyasını oluşturun ve şablon kodunu aşağıdaki kodla değiştirin:

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;
            }
        }
    }
}

Eğitmeni ve Öğrenciyi Güncelleştirme

içinde Instructor.cs, Person sınıfından Instructor sınıfını türetip anahtar ve ad alanlarını kaldırın. Kod aşağıdaki örneğe benzer olacaktır:

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 ICollection<CourseAssignment> CourseAssignments { get; set; }
        public OfficeAssignment OfficeAssignment { get; set; }
    }
}

içinde de aynı değişiklikleri Student.csyapın.

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 ICollection<Enrollment> Enrollments { get; set; }
    }
}

Modele Kişi Ekleme

Kişi varlık türünü öğesine SchoolContext.csekleyin. Yeni satırlar vurgulanır.

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; }
        public DbSet<Person> People { 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<Person>().ToTable("Person");

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

Hiyerarşi başına tablo devralmayı yapılandırmak için Entity Framework'ün ihtiyaç duyduğu tek şey budur. Gördüğünüz gibi, veritabanı güncelleştirildiğinde Öğrenci ve Eğitmen tablolarının yerine bir Kişi tablosu olur.

Geçişleri oluşturma ve güncelleştirme

Değişikliklerinizi kaydedin ve projeyi oluşturun. Ardından proje klasöründeki komut penceresini açın ve aşağıdaki komutu girin:

dotnet ef migrations add Inheritance

Komutu henüz çalıştırmayın database update . Bu komut, Eğitmen tablosunu bırakması ve Öğrenci tablosunu Kişi olarak yeniden adlandırması nedeniyle verilerin kaybolmasına neden olur. Mevcut verileri korumak için özel kod sağlamanız gerekir.

yöntemini açın Migrations/<timestamp>_Inheritance.cs ve aşağıdaki kodla değiştirin Up :

protected override void Up(MigrationBuilder migrationBuilder)
{
    migrationBuilder.DropForeignKey(
        name: "FK_Enrollment_Student_StudentID",
        table: "Enrollment");

    migrationBuilder.DropIndex(name: "IX_Enrollment_StudentID", table: "Enrollment");

    migrationBuilder.RenameTable(name: "Instructor", newName: "Person");
    migrationBuilder.AddColumn<DateTime>(name: "EnrollmentDate", table: "Person", nullable: true);
    migrationBuilder.AddColumn<string>(name: "Discriminator", table: "Person", nullable: false, maxLength: 128, defaultValue: "Instructor");
    migrationBuilder.AlterColumn<DateTime>(name: "HireDate", table: "Person", nullable: true);
    migrationBuilder.AddColumn<int>(name: "OldId", table: "Person", nullable: true);

    // Copy existing Student data into new Person table.
    migrationBuilder.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.
    migrationBuilder.Sql("UPDATE dbo.Enrollment SET StudentId = (SELECT ID FROM dbo.Person WHERE OldId = Enrollment.StudentId AND Discriminator = 'Student')");

    // Remove temporary key
    migrationBuilder.DropColumn(name: "OldID", table: "Person");

    migrationBuilder.DropTable(
        name: "Student");

    migrationBuilder.CreateIndex(
         name: "IX_Enrollment_StudentID",
         table: "Enrollment",
         column: "StudentID");

    migrationBuilder.AddForeignKey(
        name: "FK_Enrollment_Person_StudentID",
        table: "Enrollment",
        column: "StudentID",
        principalTable: "Person",
        principalColumn: "ID",
        onDelete: ReferentialAction.Cascade);
}

Bu kod aşağıdaki veritabanı güncelleştirme görevlerini üstlenir:

  • Student tablosuna işaret eden yabancı anahtar kısıtlamalarını ve dizinlerini kaldırır.

  • Eğitmen tablosunu Kişi olarak yeniden adlandırır ve Öğrenci verilerini depolamak için gerekli değişiklikleri yapar:

  • Öğrenciler için null atanabilir EnrollmentDate ekler.

  • Bir satırın öğrenciye mi yoksa eğitmene mi yönelik olduğunu belirtmek için Ayrımcı sütunu ekler.

  • Öğrenci satırlarının işe alma tarihleri olmayacağından HireDate'ı boş değer atanabilir yapar.

  • Öğrencilere işaret eden yabancı anahtarları güncelleştirmek için kullanılacak geçici bir alan ekler. Öğrencileri Kişi tablosuna kopyaladığınızda, yeni birincil anahtar değerleri alır.

  • Öğrenci tablosundaki verileri Kişi tablosuna kopyalar. Bu, öğrencilere yeni birincil anahtar değerleri atanmalarına neden olur.

  • Öğrencilere işaret eden yabancı anahtar değerlerini düzeltir.

  • Yabancı anahtar kısıtlamalarını ve dizinlerini yeniden oluşturarak bunları Kişi tablosuna yönlendirir.

(Birincil anahtar türü olarak tamsayı yerine GUID kullandıysanız, öğrencinin birincil anahtar değerlerinin değişmesi gerekmez ve bu adımlardan bazıları atlanmış olabilir.)

database update Komutunu çalıştırın:

dotnet ef database update

(Bir üretim sisteminde, önceki veritabanı sürümüne geri dönmek için Down bunu kullanmak zorunda kaldıysanız yöntemine karşılık gelen değişiklikler yaparsınız. Bu öğreticide yöntemini kullanmayacaksınız Down .)

Dekont

Mevcut verileri olan bir veritabanında şema değişiklikleri yaparken başka hatalar almak mümkündür. Çözemediğiniz geçiş hataları alırsanız, bağlantı dizesi veritabanı adını değiştirebilir veya veritabanını silebilirsiniz. Yeni bir veritabanıyla geçirecek veri yoktur ve update-database komutunun hatasız tamamlanma olasılığı daha yüksektir. Veritabanını silmek için SSOX kullanın veya CLI komutunu çalıştırın database drop .

Uygulamayı test edin

Uygulamayı çalıştırın ve çeşitli sayfaları deneyin. Her şey eskisi gibi çalışıyor.

SQL Server Nesne Gezgini Veri Bağlan ions/SchoolContext'i ve ardından Tablolar'ı genişletin; Öğrenci ve Eğitmen tablolarının yerini bir Kişi tablosu olarak görürsünüz. Kişi tablo tasarımcısını açtığınızda, öğrenci ve eğitmen tablolarında kullanılan tüm sütunların bulunduğunu görürsünüz.

Person table in SSOX

Kişi tablosuna sağ tıklayın ve ardından Ayırıcı sütununu görmek için Tablo Verilerini Göster'e tıklayın.

Person table in SSOX - table data

Kodu alma

Tamamlanan uygulamayı indirin veya görüntüleyin.

Ek kaynaklar

Entity Framework Core'da devralma hakkında daha fazla bilgi için bkz . Devralma.

Sonraki adımlar

Bu öğreticide şunları yaptınız:

  • Veritabanına eşlenmiş devralma
  • Person sınıfı oluşturuldu
  • Güncelleştirilmiş Eğitmen ve Öğrenci
  • Modele Kişi eklendi
  • Geçişler oluşturuldu ve güncelleştirildi
  • Uygulamayı test etti

Çeşitli görece gelişmiş Entity Framework senaryolarını işlemeyi öğrenmek için sonraki öğreticiye ilerleyin.