Öğ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:
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 Instructor
Student
:
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.
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.
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 , Student
ve sınıfları için Person
TPC 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 Person
türetecek şekilde değiştirmekInstructor
, yeni sınıfı öğesine DbContext
eklemek 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.cs
yapı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.cs
ekleyin. 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.
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.
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.
ASP.NET Core