Aracılığıyla paylaş


Bölüm 5, Razor ASP.NET Core'da bulunan EF Core sayfalar - Veri Modeli

Tom Dykstra, Jeremy Likness ve Jon P Smith tarafından

Contoso University web uygulaması, ve Visual Studio kullanarak EF Core Sayfalar web uygulamalarının nasıl oluşturulacağını Razor gösterir. Öğretici serisi hakkında bilgi için ilk öğreticiye bakın.

Çözemediğiniz sorunlarla karşılaşırsanız, tamamlanmış uygulamayı indirin ve öğreticiyi izleyerek bu kodu oluşturduğunuz kodla karşılaştırın.

Önceki öğreticiler üç varlıklardan oluşan temel bir veri modeliyle çalışıyordu. Bu öğreticide:

  • Daha fazla varlık ve ilişki eklenir.
  • Veri modeli biçimlendirme, doğrulama ve veritabanı eşleme kuralları belirtilerek özelleştirilir.

Tamamlanan veri modeli aşağıdaki çizimde gösterilmiştir:

Entity diagram

Dataedo ile aşağıdaki veritabanı diyagramı yapılmıştır:

Dataedo diagram

Dataedo ile veritabanı diyagramı oluşturmak için:

Önceki Dataedo diyagramında CourseInstructor , Entity Framework tarafından oluşturulan bir birleştirme tablosudur. Daha fazla bilgi için bkz . Çoka çok

Student varlığı

içindeki Models/Student.cs kodu aşağıdaki kodla değiştirin:

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, ErrorMessage = "First name cannot be longer than 50 characters.")]
        [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; }
    }
}

Yukarıdaki kod bir FullName özellik ekler ve mevcut özelliklere aşağıdaki öznitelikleri ekler:

FullName hesaplanan özelliği

FullName , diğer iki özelliğin birleştirilmesiyle oluşturulan bir değer döndüren hesaplanmış bir özelliktir. FullName ayarlanamaz, bu nedenle yalnızca bir get erişimciye sahiptir. FullName Veritabanında sütun oluşturulmaz.

DataType özniteliği

[DataType(DataType.Date)]

Öğrenci kayıt tarihleri için, tüm sayfalar şu anda tarihle birlikte günün saatini görüntüler, ancak yalnızca tarih geçerlidir. Veri ek açıklaması özniteliklerini kullanarak, verileri gösteren her sayfada görüntüleme biçimini düzeltecek bir kod değişikliği yapabilirsiniz.

DataType özniteliği, veritabanı iç türünden daha özel bir veri türü belirtir. Bu durumda, tarih ve saat değil yalnızca tarih görüntülenmelidir. DataType Numaralandırması Date, Time, Telefon Number, Currency, EmailAddress gibi birçok veri türü sağlar. Özniteliği, DataType uygulamanın türe özgü özellikleri otomatik olarak sağlamasına da olanak sağlayabilir. Örnek:

  • Bağlantı mailto: için DataType.EmailAddressotomatik olarak oluşturulur.
  • Tarih seçici çoğu tarayıcıda sağlanır DataType.Date .

DataType özniteliği HTML 5 data- (belirgin veri tiresi) öznitelikleri yayar. DataType Öznitelikler doğrulama sağlamaz.

DisplayFormat özniteliği

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

DataType.Date görüntülenen tarihin biçimini belirtmez. Varsayılan olarak, tarih alanı sunucunun CultureInfo'sunu temel alan varsayılan biçimlere göre görüntülenir.

DisplayFormat özniteliği, tarih biçimini açıkça belirtmek için kullanılır. ayarı, ApplyFormatInEditMode biçimlendirmenin düzenleme kullanıcı arabirimine de uygulanması gerektiğini belirtir. Bazı alanlar kullanmamalıdır ApplyFormatInEditMode. Örneğin, para birimi simgesi genellikle düzenleme metin kutusunda görüntülenmemelidir.

DisplayFormat özniteliği tek başına kullanılabilir. özniteliğini özniteliğiyle DisplayFormat kullanmak DataType genellikle iyi bir fikirdir. özniteliği, DataType verilerin ekranda nasıl işlendiğinin aksine semantiğini iletir. DataType özniteliği, içinde DisplayFormatbulunmayan aşağıdaki avantajları sağlar:

  • Tarayıcı HTML5 özelliklerini etkinleştirebilir. Örneğin, bir takvim denetimi, yerel ayara uygun para birimi simgesi, e-posta bağlantıları ve istemci tarafı giriş doğrulamasını gösterin.
  • Varsayılan olarak, tarayıcı verileri yerel ayara göre doğru biçimi kullanarak işler.

Daha fazla bilgi için giriş Etiketi Yardımcısı belgelerine bakın<.>

StringLength özniteliği

[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]

Veri doğrulama kuralları ve doğrulama hata iletileri özniteliklerle belirtilebilir. StringLength özniteliği, bir veri alanında izin verilen en düşük ve en uzun karakter uzunluğunu belirtir. Gösterilen kod adları en fazla 50 karakterle sınırlar. En düşük dize uzunluğunu ayarlayan bir örnek daha sonra gösterilir.

StringLength özniteliği istemci tarafı ve sunucu tarafı doğrulama da sağlar. En düşük değerin veritabanı şeması üzerinde hiçbir etkisi yoktur.

StringLength özniteliği, kullanıcının bir ad için boşluk girmesini engellemez. RegularExpression özniteliği girişe kısıtlamalar uygulamak için kullanılabilir. Örneğin, aşağıdaki kod ilk karakterin büyük harf olmasını ve kalan karakterlerin alfabetik olmasını gerektirir:

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

SQL Server Nesne Gezgini'de (SSOX), Student tablosuna çift tıklayarak Student tablo tasarımcısını açın.

Students table in SSOX before migrations

Yukarıdaki görüntüde tablonun şeması Student gösterilir. Ad alanlarının türü nvarchar(MAX)vardır. Bu öğreticinin devamında bir geçiş oluşturulduğunda ve uygulandığında, ad alanları dize uzunluğu özniteliklerinin bir sonucu olarak olur nvarchar(50) .

Column özniteliği

[Column("FirstName")]
public string FirstMidName { get; set; }

Öznitelikler, sınıfların ve özelliklerin veritabanına nasıl eşlenebileceğini denetleyebilir. Modelde Student özniteliği, özelliğin Column adını veritabanındaki FirstMidName "FirstName" ile eşlemek için kullanılır.

Veritabanı oluşturulduğunda, modeldeki özellik adları sütun adları için kullanılır (özniteliğin Column kullanılması dışında). Alan Student ikinci ad da içerebileceğinden model ad alanı için kullanır FirstMidName .

özniteliğiyle [Column] , Student.FirstMidName veri modelinde tablonun sütununa eşler FirstNameStudent . özniteliğinin Column eklenmesi, modelinin desteklenmesinde SchoolContextdeğişiklik gösterir. öğesinin yedeklenmesi SchoolContext artık veritabanıyla eşleşir. Bu tutarsızlık, bu öğreticinin ilerleyen bölümlerinde bir geçiş eklenerek çözülecektir.

Gerekli özniteliği

[Required]

özniteliği, Required ad özelliklerini gerekli alanlara getirir. Required Öznitelik, değer türleri (örneğin, DateTime, intve double) gibi null atanamayan türler için gerekli değildir. Null yapılamaz türler otomatik olarak gerekli alanlar olarak kabul edilir.

özniteliğinin Required uygulanabilmesi için MinimumLength ile MinimumLength kullanılması gerekir.

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

MinimumLength ve Required boşluğun doğrulamayı karşılamasına izin verin. RegularExpression Dize üzerinde tam denetim için özniteliğini kullanın.

Display özniteliği

[Display(Name = "Last Name")]

özniteliği, Display metin kutuları için başlık "Ad", "Soyadı", "Tam Ad" ve "Kayıt Tarihi" olması gerektiğini belirtir. Varsayılan başlık sözcükleri bölen boşluk yoktu, örneğin "Soyadı."

Geçiş oluşturma

Uygulamayı çalıştırın ve Öğrenciler sayfasına gidin. Bir özel durum oluşturulur. özniteliği EF'in [Column] adlı FirstNamebir sütunu bulmayı beklemesine neden olur, ancak veritabanındaki sütun adı hala FirstMidNameolur.

Hata iletisi aşağıdaki örneğe benzer:

SqlException: Invalid column name 'FirstName'.
There are pending model changes
Pending model changes are detected in the following:

SchoolContext
  • PMC'de, yeni bir geçiş oluşturmak ve veritabanını güncelleştirmek için aşağıdaki komutları girin:

    Add-Migration ColumnFirstName
    Update-Database
    
    

    Bu komutlardan ilki aşağıdaki uyarı iletisini oluşturur:

    An operation was scaffolded that may result in the loss of data.
    Please review the migration for accuracy.
    

    Ad alanları artık 50 karakterle sınırlı olduğundan uyarı oluşturulur. Veritabanındaki bir ad 50'den fazla karaktere sahipse, 51-son karakter kaybolur.

  • SSOX'ta Student tablosunu açın:

    Students table in SSOX after migrations

    Geçiş uygulanmadan önce ad sütunları nvarchar(MAX) türündeydi. Ad sütunları artık nvarchar(50)şeklindedir. Sütun adı olarak değiştirildi FirstMidNameFirstName.

  • Uygulamayı çalıştırın ve Öğrenciler sayfasına gidin.
  • Saatlerin giriş yapılmadığını veya tarihlerle birlikte görüntülenmediğini fark edin.
  • Yeni Oluştur'u seçin ve 50 karakterden uzun bir ad girmeyi deneyin.

Dekont

Aşağıdaki bölümlerde, uygulamanın bazı aşamalarda oluşturulması derleyici hataları oluşturur. Yönergeler, uygulamanın ne zaman derleneceğini belirtir.

Eğitmen Varlığı

Aşağıdaki kodla oluşturun Models/Instructor.cs :

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<Course> Courses { get; set; }
        public OfficeAssignment OfficeAssignment { get; set; }
    }
}

Birden çok öznitelik tek satırda olabilir. HireDate Öznitelikler aşağıdaki gibi yazılabilir:

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

Courses ve OfficeAssignment özellikleri gezinti özellikleridir.

Eğitmen herhangi bir sayıda ders verebilir, bu nedenle Courses koleksiyon olarak tanımlanır.

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

Eğitmenin en fazla bir ofisi olabilir, bu nedenle özelliğin OfficeAssignment tek OfficeAssignment bir varlığı vardır. OfficeAssignment hiçbir office atanmamışsa null olur.

public OfficeAssignment OfficeAssignment { get; set; }

OfficeAssignment varlığı

OfficeAssignment entity

Aşağıdaki kodla oluşturun Models/OfficeAssignment.cs :

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

Key özniteliği

[Key] özniteliği, özellik adı veya IDdışında classnameID bir şey olduğunda bir özelliği birincil anahtar (PK) olarak tanımlamak için kullanılır.

ve OfficeAssignment varlıkları arasında Instructor bire sıfır veya bir ilişkisi vardır. Bir ofis ataması yalnızca atandığı eğitmenle ilişkili olarak bulunur. OfficeAssignment PK aynı zamanda varlığın yabancı anahtarıdır (FKInstructor). Bir tablodaki PK hem PK hem de başka bir tablodaki FK olduğunda bire sıfır veya bir ilişkisi oluşur.

EF CoreID veya classnameID adlandırma kuralına uymadığından otomatik olarak PK OfficeAssignmentInstructorID olarak tanınamıyorInstructorID. Bu nedenle, Key özniteliği PK olarak tanımlamak InstructorID için kullanılır:

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

Varsayılan olarak, EF Core sütun tanımlayıcı bir ilişki için olduğundan anahtarı veritabanı oluşturulmamış olarak ele alır. Daha fazla bilgi için bkz . EF Anahtarları.

Eğitmen gezinti özelliği

Belirli Instructor.OfficeAssignment bir eğitmen için satır OfficeAssignment olmadığından gezinti özelliği null olabilir. Eğitmenin ofis ödevi olmayabilir.

OfficeAssignment.Instructor Yabancı anahtar InstructorID türü null atanamayan bir değer türü olduğundan intgezinti özelliğinin her zaman bir eğitmen varlığı olacaktır. Bir ofis ödevi, eğitmen olmadan mevcut olamaz.

Bir Instructor varlığın ilgili OfficeAssignment bir varlığı olduğunda, her varlığın gezinti özelliğinde diğerine bir başvurusu olur.

Kurs Varlığı

Aşağıdaki kodla güncelleştirin Models/Course.cs :

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<Instructor> Instructors { get; set; }
    }
}

Varlığın Course yabancı anahtar (FK) özelliği DepartmentIDvardır. DepartmentID ilgili Department varlığa işaret eder. Varlığın Course bir Department gezinti özelliği vardır.

EF Core modelin ilgili varlık için gezinti özelliği olduğunda veri modeli için yabancı anahtar özelliği gerektirmez. EF Core gerektiğinde otomatik olarak veritabanında FK'ler oluşturur. EF Coreotomatik olarak oluşturulan FK'ler için gölge özellikler oluşturur. Ancak, FK'yi veri modeline açıkça dahil ederek güncelleştirmeleri daha basit ve daha verimli hale getirebilirsiniz. Örneğin, FK özelliğinin DepartmentIDdahil edilmediği bir model düşünün. Düzenlemek üzere bir kurs varlığı getirildiğinde:

  • Department özelliği, null açıkça yüklenmemişse olur.
  • Kurs varlığını güncelleştirmek için önce varlığın Department getirilmesi gerekir.

FK özelliği DepartmentID veri modeline dahil edildiğinde, bir güncelleştirmeden önce varlığı getirmeye Department gerek yoktur.

DatabaseGenerated özniteliği

özniteliği, [DatabaseGenerated(DatabaseGeneratedOption.None)] PK'nin veritabanı tarafından oluşturulmak yerine uygulama tarafından sağlandığını belirtir.

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

Varsayılan olarak, EF Core PK değerlerinin veritabanı tarafından oluşturulduğunu varsayar. Veritabanı tarafından oluşturulan genellikle en iyi yaklaşımdır. Varlıklar için Course kullanıcı PK'yı belirtir. Örneğin, matematik bölümü için 1000 serisi, İngilizce bölümü için 2000 serisi gibi bir ders numarası.

Özniteliği, DatabaseGenerated varsayılan değerleri oluşturmak için de kullanılabilir. Örneğin, veritabanı otomatik olarak bir satırın oluşturulduğu veya güncelleştirilildiği tarihi kaydetmek için bir tarih alanı oluşturabilir. Daha fazla bilgi için bkz . Oluşturulan Özellikler.

Yabancı anahtar ve gezinti özellikleri

Varlıktaki Course yabancı anahtar (FK) özellikleri ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

Kurs bir bölüme atandığından FK ve Department gezinti özelliği vardırDepartmentID.

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

Bir kursta kayıtlı herhangi bir sayıda öğrenci olabilir, bu nedenle Enrollments gezinti özelliği bir koleksiyondur:

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

Bir kurs birden çok eğitmen tarafından öğretilebilir, bu nedenle Instructors gezinti özelliği bir koleksiyondur:

public ICollection<Instructor> Instructors { get; set; }

Departman varlığı

Aşağıdaki kodla oluşturun Models/Department.cs :

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

Column özniteliği

Column Daha önce sütun adı eşlemesini değiştirmek için özniteliği kullanılıyordu. Varlığın kodunda Department , Column SQL veri türü eşlemesini değiştirmek için özniteliği kullanılır. Budget Sütun, veritabanındaki SQL Server para türü kullanılarak tanımlanır:

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

Sütun eşlemesi genellikle gerekli değildir. EF Core özelliği için CLR türüne göre uygun SQL Server veri türünü seçer. CLR decimal türü bir SQL Server decimal türüyle eşler. Budget para birimi içindir ve para birimi veri türü para birimi için daha uygundur.

Yabancı anahtar ve gezinti özellikleri

FK ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

  • Bir bölümün yöneticisi olabilir veya olmayabilir.
  • Yönetici her zaman eğitmendir. Bu nedenle InstructorID özelliği, varlığa FK Instructor olarak eklenir.

Gezinti özelliği adlandırılmıştır Administrator ancak bir Instructor varlığı barındırmaktadır:

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

? Yukarıdaki kodda özelliğin null atanabilir olduğunu belirtir.

Bir bölümün birçok kursu olabileceği için Kurslar gezinti özelliği vardır:

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

Kural gereği, EF Core null değer atanamayan FK'ler ve çoka çok ilişkiler için art arda silmeyi etkinleştirir. Bu varsayılan davranış döngüsel art arda silme kurallarına neden olabilir. Döngüsel art arda silme kuralları, geçiş eklendiğinde özel duruma neden olur.

Örneğin, özellik null atanamaz olarak tanımlandıysa Department.InstructorID , EF Core art arda silme kuralı yapılandırılır. Bu durumda, yönetici olarak atanan eğitmen silindiğinde bölüm silinir. Bu senaryoda kısıtlama kuralı daha mantıklı olacaktır. Aşağıdaki akıcı API bir kısıtlama kuralı ayarlar ve art arda silmeyi devre dışı bırakır.

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

Kayıt yabancı anahtarı ve gezinti özellikleri

Kayıt kaydı, bir öğrencinin aldığı bir kursa yöneliktir.

Enrollment entity

Aşağıdaki kodla güncelleştirin Models/Enrollment.cs :

using System.ComponentModel.DataAnnotations;

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

FK özellikleri ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

Kayıt kaydı bir kurs içindir, bu nedenle bir CourseID FK özelliği ve bir Course gezinti özelliği vardır:

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

Kayıt kaydı bir öğrenci içindir, bu nedenle bir StudentID FK özelliği ve bir Student gezinti özelliği vardır:

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

Çoka Çok İlişkiler

ve Course varlıkları arasında Student çoka çok ilişkisi vardır. Varlık, Enrollment veritabanında yükü olan çoka çok birleştirme tablosu olarak çalışır. YükünEnrollment olması, tablonun birleştirilen tablolar için FK'lerin yanı sıra ek veriler içerdiği anlamına gelir. Varlığında Enrollment , FK'ler dışında ek veriler PK ve Grade'tir.

Aşağıdaki çizimde bu ilişkilerin bir varlık diyagramında nasıl göründüğü gösterilmektedir. (Bu diyagram kullanılarak oluşturulmuşturEF 6.x için EF Power Tools . Diyagramı oluşturmak öğreticinin bir parçası değildir.)

Student-Course many to many relationship

Her ilişki çizgisinin bir ucunda 1, diğer ucunda ise bire çok ilişkisini gösteren bir yıldız işareti (*) vardır.

Enrollment Tabloda not bilgileri yoksa, yalnızca iki FK ve içermesi CourseIDStudentIDgerekir. Yükü olmayan çoka çok birleştirme tablosu bazen saf birleştirme tablosu (PJT) olarak adlandırılır.

ve Course varlıklarının Instructor PJT kullanan çoka çok ilişkisi vardır.

Veritabanı bağlamını güncelleştirme

Aşağıdaki kodla güncelleştirin Data/SchoolContext.cs :

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

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Course>().ToTable(nameof(Course))
                .HasMany(c => c.Instructors)
                .WithMany(i => i.Courses);
            modelBuilder.Entity<Student>().ToTable(nameof(Student));
            modelBuilder.Entity<Instructor>().ToTable(nameof(Instructor));
        }
    }
}

Yukarıdaki kod yeni varlıkları ekler ve ve Course varlıkları arasındaki Instructor çoka çok ilişkisini yapılandırılır.

Özniteliklere alternatif fluent API

Yukarıdaki OnModelCreating koddaki yöntem, davranışı yapılandırmak EF Core için akıcı API'yi kullanır. API'ye "fluent" adı verilir çünkü genellikle bir dizi yöntem çağrısını tek bir deyimde dizeleyerek kullanılır. Aşağıdaki kod , akıcı API örneğidir:

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

Bu öğreticide, akıcı API yalnızca özniteliklerle yapılamaz veritabanı eşlemesi için kullanılır. Ancak, akıcı API özniteliklerle yapılabilecek biçimlendirme, doğrulama ve eşleme kurallarının çoğunu belirtebilir.

gibi MinimumLength bazı öznitelikler akıcı API ile uygulanamaz. MinimumLength şemayı değiştirmez, yalnızca minimum uzunluk doğrulama kuralı uygular.

Bazı geliştiriciler varlık sınıflarını temiz tutabilmek için yalnızca akıcı API'yi kullanmayı tercih eder. Öznitelikler ve akıcı API karıştırılabilir. Bileşik PK belirtme gibi yalnızca akıcı API ile yapılabilecek bazı yapılandırmalar vardır. Yalnızca özniteliklerle (MinimumLength) yapilebilen bazı yapılandırmalar vardır. Akıcı API veya öznitelikleri kullanmak için önerilen uygulama:

  • Bu iki yaklaşımdan birini seçin.
  • Seçilen yaklaşımı mümkün olduğunca tutarlı bir şekilde kullanın.

Bu öğreticide kullanılan özniteliklerden bazıları şunlar için kullanılır:

  • Yalnızca doğrulama (örneğin, MinimumLength).
  • EF Core yalnızca yapılandırma (örneğin, HasKey).
  • Doğrulama ve EF Core yapılandırma (örneğin, [StringLength(50)]).

Öznitelikler ve akıcı API hakkında daha fazla bilgi için bkz . Yapılandırma yöntemleri.

Veritabanının tohumunu oluşturma

içindeki Data/DbInitializer.cskodu güncelleştirin:

using ContosoUniversity.Models;
using System;
using System.Collections.Generic;
using System.Linq;

namespace ContosoUniversity.Data
{
    public static class DbInitializer
    {
        public static void Initialize(SchoolContext context)
        {
            // Look for any students.
            if (context.Students.Any())
            {
                return;   // DB has been seeded
            }

            var alexander = new Student
            {
                FirstMidName = "Carson",
                LastName = "Alexander",
                EnrollmentDate = DateTime.Parse("2016-09-01")
            };

            var alonso = new Student
            {
                FirstMidName = "Meredith",
                LastName = "Alonso",
                EnrollmentDate = DateTime.Parse("2018-09-01")
            };

            var anand = new Student
            {
                FirstMidName = "Arturo",
                LastName = "Anand",
                EnrollmentDate = DateTime.Parse("2019-09-01")
            };

            var barzdukas = new Student
            {
                FirstMidName = "Gytis",
                LastName = "Barzdukas",
                EnrollmentDate = DateTime.Parse("2018-09-01")
            };

            var li = new Student
            {
                FirstMidName = "Yan",
                LastName = "Li",
                EnrollmentDate = DateTime.Parse("2018-09-01")
            };

            var justice = new Student
            {
                FirstMidName = "Peggy",
                LastName = "Justice",
                EnrollmentDate = DateTime.Parse("2017-09-01")
            };

            var norman = new Student
            {
                FirstMidName = "Laura",
                LastName = "Norman",
                EnrollmentDate = DateTime.Parse("2019-09-01")
            };

            var olivetto = new Student
            {
                FirstMidName = "Nino",
                LastName = "Olivetto",
                EnrollmentDate = DateTime.Parse("2011-09-01")
            };

            var students = new Student[]
            {
                alexander,
                alonso,
                anand,
                barzdukas,
                li,
                justice,
                norman,
                olivetto
            };

            context.AddRange(students);

            var abercrombie = new Instructor
            {
                FirstMidName = "Kim",
                LastName = "Abercrombie",
                HireDate = DateTime.Parse("1995-03-11")
            };

            var fakhouri = new Instructor
            {
                FirstMidName = "Fadi",
                LastName = "Fakhouri",
                HireDate = DateTime.Parse("2002-07-06")
            };

            var harui = new Instructor
            {
                FirstMidName = "Roger",
                LastName = "Harui",
                HireDate = DateTime.Parse("1998-07-01")
            };

            var kapoor = new Instructor
            {
                FirstMidName = "Candace",
                LastName = "Kapoor",
                HireDate = DateTime.Parse("2001-01-15")
            };

            var zheng = new Instructor
            {
                FirstMidName = "Roger",
                LastName = "Zheng",
                HireDate = DateTime.Parse("2004-02-12")
            };

            var instructors = new Instructor[]
            {
                abercrombie,
                fakhouri,
                harui,
                kapoor,
                zheng
            };

            context.AddRange(instructors);

            var officeAssignments = new OfficeAssignment[]
            {
                new OfficeAssignment {
                    Instructor = fakhouri,
                    Location = "Smith 17" },
                new OfficeAssignment {
                    Instructor = harui,
                    Location = "Gowan 27" },
                new OfficeAssignment {
                    Instructor = kapoor,
                    Location = "Thompson 304" }
            };

            context.AddRange(officeAssignments);

            var english = new Department
            {
                Name = "English",
                Budget = 350000,
                StartDate = DateTime.Parse("2007-09-01"),
                Administrator = abercrombie
            };

            var mathematics = new Department
            {
                Name = "Mathematics",
                Budget = 100000,
                StartDate = DateTime.Parse("2007-09-01"),
                Administrator = fakhouri
            };

            var engineering = new Department
            {
                Name = "Engineering",
                Budget = 350000,
                StartDate = DateTime.Parse("2007-09-01"),
                Administrator = harui
            };

            var economics = new Department
            {
                Name = "Economics",
                Budget = 100000,
                StartDate = DateTime.Parse("2007-09-01"),
                Administrator = kapoor
            };

            var departments = new Department[]
            {
                english,
                mathematics,
                engineering,
                economics
            };

            context.AddRange(departments);

            var chemistry = new Course
            {
                CourseID = 1050,
                Title = "Chemistry",
                Credits = 3,
                Department = engineering,
                Instructors = new List<Instructor> { kapoor, harui }
            };

            var microeconomics = new Course
            {
                CourseID = 4022,
                Title = "Microeconomics",
                Credits = 3,
                Department = economics,
                Instructors = new List<Instructor> { zheng }
            };

            var macroeconmics = new Course
            {
                CourseID = 4041,
                Title = "Macroeconomics",
                Credits = 3,
                Department = economics,
                Instructors = new List<Instructor> { zheng }
            };

            var calculus = new Course
            {
                CourseID = 1045,
                Title = "Calculus",
                Credits = 4,
                Department = mathematics,
                Instructors = new List<Instructor> { fakhouri }
            };

            var trigonometry = new Course
            {
                CourseID = 3141,
                Title = "Trigonometry",
                Credits = 4,
                Department = mathematics,
                Instructors = new List<Instructor> { harui }
            };

            var composition = new Course
            {
                CourseID = 2021,
                Title = "Composition",
                Credits = 3,
                Department = english,
                Instructors = new List<Instructor> { abercrombie }
            };

            var literature = new Course
            {
                CourseID = 2042,
                Title = "Literature",
                Credits = 4,
                Department = english,
                Instructors = new List<Instructor> { abercrombie }
            };

            var courses = new Course[]
            {
                chemistry,
                microeconomics,
                macroeconmics,
                calculus,
                trigonometry,
                composition,
                literature
            };

            context.AddRange(courses);

            var enrollments = new Enrollment[]
            {
                new Enrollment {
                    Student = alexander,
                    Course = chemistry,
                    Grade = Grade.A
                },
                new Enrollment {
                    Student = alexander,
                    Course = microeconomics,
                    Grade = Grade.C
                },
                new Enrollment {
                    Student = alexander,
                    Course = macroeconmics,
                    Grade = Grade.B
                },
                new Enrollment {
                    Student = alonso,
                    Course = calculus,
                    Grade = Grade.B
                },
                new Enrollment {
                    Student = alonso,
                    Course = trigonometry,
                    Grade = Grade.B
                },
                new Enrollment {
                    Student = alonso,
                    Course = composition,
                    Grade = Grade.B
                },
                new Enrollment {
                    Student = anand,
                    Course = chemistry
                },
                new Enrollment {
                    Student = anand,
                    Course = microeconomics,
                    Grade = Grade.B
                },
                new Enrollment {
                    Student = barzdukas,
                    Course = chemistry,
                    Grade = Grade.B
                },
                new Enrollment {
                    Student = li,
                    Course = composition,
                    Grade = Grade.B
                },
                new Enrollment {
                    Student = justice,
                    Course = literature,
                    Grade = Grade.B
                }
            };

            context.AddRange(enrollments);
            context.SaveChanges();
        }
    }
}

Yukarıdaki kod, yeni varlıklar için tohum verileri sağlar. Bu kodun çoğu yeni varlık nesneleri oluşturur ve örnek verileri yükler. Örnek veriler test için kullanılır.

Geçişi uygulama veya bırakma ve yeniden oluşturma

Mevcut veritabanıyla, veritabanını değiştirmeye yönelik iki yaklaşım vardır:

İki seçenek de SQL Server için çalışır. Apply-migration yöntemi daha karmaşık ve zaman alıcı olsa da, gerçek dünya, üretim ortamları için tercih edilen yaklaşımdır.

Veritabanını bırakma ve yeniden oluşturma

Yeni veritabanı oluşturmaya zorlamak EF Core için veritabanını bırakın ve güncelleştirin:

  • Migrations klasörünü silin.
  • Paket Yöneticisi Konsolu'nda (PMC) aşağıdaki komutları çalıştırın:
Drop-Database
Add-Migration InitialCreate
Update-Database

Uygulamayı çalıştırma. Uygulamayı çalıştırmak yöntemini çalıştırır DbInitializer.Initialize . yeni DbInitializer.Initialize veritabanını doldurur.

Veritabanını SSOX'ta açın:

  • SSOX daha önce açıldıysa Yenile düğmesine tıklayın.
  • Tablolar düğümünü genişletin. Oluşturulan tablolar görüntülenir.

Sonraki adımlar

Sonraki iki öğretici, ilgili verilerin nasıl okunup güncelleştirileceğini gösterir.

Önceki öğreticiler üç varlıklardan oluşan temel bir veri modeliyle çalışıyordu. Bu öğreticide:

  • Daha fazla varlık ve ilişki eklenir.
  • Veri modeli biçimlendirme, doğrulama ve veritabanı eşleme kuralları belirtilerek özelleştirilir.

Tamamlanan veri modeli aşağıdaki çizimde gösterilmiştir:

Entity diagram

Student varlığı

Student entity

içindeki Models/Student.cs kodu aşağıdaki kodla değiştirin:

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, ErrorMessage = "First name cannot be longer than 50 characters.")]
        [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; }
    }
}

Yukarıdaki kod bir FullName özellik ekler ve mevcut özelliklere aşağıdaki öznitelikleri ekler:

  • [DataType]
  • [DisplayFormat]
  • [StringLength]
  • [Column]
  • [Required]
  • [Display]

FullName hesaplanan özelliği

FullName , diğer iki özelliğin birleştirilmesiyle oluşturulan bir değer döndüren hesaplanmış bir özelliktir. FullName ayarlanamaz, bu nedenle yalnızca bir get erişimciye sahiptir. FullName Veritabanında sütun oluşturulmaz.

DataType özniteliği

[DataType(DataType.Date)]

Öğrenci kayıt tarihleri için, tüm sayfalar şu anda tarihle birlikte günün saatini görüntüler, ancak yalnızca tarih geçerlidir. Veri ek açıklaması özniteliklerini kullanarak, verileri gösteren her sayfada görüntüleme biçimini düzeltecek bir kod değişikliği yapabilirsiniz.

DataType özniteliği, veritabanı iç türünden daha özel bir veri türü belirtir. Bu durumda, tarih ve saat değil yalnızca tarih görüntülenmelidir. DataType Numaralandırması Date, Time, Telefon Number, Currency, EmailAddress gibi birçok veri türü sağlar. Özniteliği, DataType uygulamanın türe özgü özellikleri otomatik olarak sağlamasına da olanak sağlayabilir. Örnek:

  • Bağlantı mailto: için DataType.EmailAddressotomatik olarak oluşturulur.
  • Tarih seçici çoğu tarayıcıda sağlanır DataType.Date .

DataType özniteliği HTML 5 data- (belirgin veri tiresi) öznitelikleri yayar. DataType Öznitelikler doğrulama sağlamaz.

DisplayFormat özniteliği

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

DataType.Date görüntülenen tarihin biçimini belirtmez. Varsayılan olarak, tarih alanı sunucunun CultureInfo'sunu temel alan varsayılan biçimlere göre görüntülenir.

DisplayFormat özniteliği, tarih biçimini açıkça belirtmek için kullanılır. ayarı, ApplyFormatInEditMode biçimlendirmenin düzenleme kullanıcı arabirimine de uygulanması gerektiğini belirtir. Bazı alanlar kullanmamalıdır ApplyFormatInEditMode. Örneğin, para birimi simgesi genellikle düzenleme metin kutusunda görüntülenmemelidir.

DisplayFormat özniteliği tek başına kullanılabilir. özniteliğini özniteliğiyle DisplayFormat kullanmak DataType genellikle iyi bir fikirdir. özniteliği, DataType verilerin ekranda nasıl işlendiğinin aksine semantiğini iletir. DataType özniteliği, içinde DisplayFormatbulunmayan aşağıdaki avantajları sağlar:

  • Tarayıcı HTML5 özelliklerini etkinleştirebilir. Örneğin, bir takvim denetimi, yerel ayara uygun para birimi simgesi, e-posta bağlantıları ve istemci tarafı giriş doğrulamasını gösterin.
  • Varsayılan olarak, tarayıcı verileri yerel ayara göre doğru biçimi kullanarak işler.

Daha fazla bilgi için giriş Etiketi Yardımcısı belgelerine bakın<.>

StringLength özniteliği

[StringLength(50, ErrorMessage = "First name cannot be longer than 50 characters.")]

Veri doğrulama kuralları ve doğrulama hata iletileri özniteliklerle belirtilebilir. StringLength özniteliği, bir veri alanında izin verilen en düşük ve en uzun karakter uzunluğunu belirtir. Gösterilen kod adları en fazla 50 karakterle sınırlar. En düşük dize uzunluğunu ayarlayan bir örnek daha sonra gösterilir.

StringLength özniteliği istemci tarafı ve sunucu tarafı doğrulama da sağlar. En düşük değerin veritabanı şeması üzerinde hiçbir etkisi yoktur.

StringLength özniteliği, kullanıcının bir ad için boşluk girmesini engellemez. RegularExpression özniteliği girişe kısıtlamalar uygulamak için kullanılabilir. Örneğin, aşağıdaki kod ilk karakterin büyük harf olmasını ve kalan karakterlerin alfabetik olmasını gerektirir:

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

SQL Server Nesne Gezgini'de (SSOX), Student tablosuna çift tıklayarak Student tablo tasarımcısını açın.

Students table in SSOX before migrations

Yukarıdaki görüntüde tablonun şeması Student gösterilir. Ad alanlarının türü nvarchar(MAX)vardır. Bu öğreticinin devamında bir geçiş oluşturulduğunda ve uygulandığında, ad alanları dize uzunluğu özniteliklerinin bir sonucu olarak olur nvarchar(50) .

Column özniteliği

[Column("FirstName")]
public string FirstMidName { get; set; }

Öznitelikler, sınıfların ve özelliklerin veritabanına nasıl eşlenebileceğini denetleyebilir. Modelde Student özniteliği, özelliğin Column adını veritabanındaki FirstMidName "FirstName" ile eşlemek için kullanılır.

Veritabanı oluşturulduğunda, modeldeki özellik adları sütun adları için kullanılır (özniteliğin Column kullanılması dışında). Alan Student ikinci ad da içerebileceğinden model ad alanı için kullanır FirstMidName .

özniteliğiyle [Column] , Student.FirstMidName veri modelinde tablonun sütununa eşler FirstNameStudent . özniteliğinin Column eklenmesi, modelinin desteklenmesinde SchoolContextdeğişiklik gösterir. öğesinin yedeklenmesi SchoolContext artık veritabanıyla eşleşir. Bu tutarsızlık, bu öğreticinin ilerleyen bölümlerinde bir geçiş eklenerek çözülecektir.

Gerekli özniteliği

[Required]

özniteliği, Required ad özelliklerini gerekli alanlara getirir. Required Öznitelik, değer türleri (örneğin, DateTime, intve double) gibi null atanamayan türler için gerekli değildir. Null yapılamaz türler otomatik olarak gerekli alanlar olarak kabul edilir.

özniteliğinin Required uygulanabilmesi için MinimumLength ile MinimumLength kullanılması gerekir.

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

MinimumLength ve Required boşluğun doğrulamayı karşılamasına izin verin. RegularExpression Dize üzerinde tam denetim için özniteliğini kullanın.

Display özniteliği

[Display(Name = "Last Name")]

özniteliği, Display metin kutuları için başlık "Ad", "Soyadı", "Tam Ad" ve "Kayıt Tarihi" olması gerektiğini belirtir. Varsayılan başlık sözcükleri bölen boşluk yoktu, örneğin "Soyadı."

Geçiş oluşturma

Uygulamayı çalıştırın ve Öğrenciler sayfasına gidin. Bir özel durum oluşturulur. özniteliği EF'in [Column] adlı FirstNamebir sütunu bulmayı beklemesine neden olur, ancak veritabanındaki sütun adı hala FirstMidNameolur.

Hata iletisi aşağıdaki örneğe benzer:

SqlException: Invalid column name 'FirstName'.
  • PMC'de, yeni bir geçiş oluşturmak ve veritabanını güncelleştirmek için aşağıdaki komutları girin:

    Add-Migration ColumnFirstName
    Update-Database
    

    Bu komutlardan ilki aşağıdaki uyarı iletisini oluşturur:

    An operation was scaffolded that may result in the loss of data.
    Please review the migration for accuracy.
    

    Ad alanları artık 50 karakterle sınırlı olduğundan uyarı oluşturulur. Veritabanındaki bir ad 50'den fazla karaktere sahipse, 51-son karakter kaybolur.

  • SSOX'ta Student tablosunu açın:

    Students table in SSOX after migrations

    Geçiş uygulanmadan önce ad sütunları nvarchar(MAX) türündeydi. Ad sütunları artık nvarchar(50)şeklindedir. Sütun adı olarak değiştirildi FirstMidNameFirstName.

  • Uygulamayı çalıştırın ve Öğrenciler sayfasına gidin.
  • Saatlerin giriş yapılmadığını veya tarihlerle birlikte görüntülenmediğini fark edin.
  • Yeni Oluştur'u seçin ve 50 karakterden uzun bir ad girmeyi deneyin.

Dekont

Aşağıdaki bölümlerde, uygulamanın bazı aşamalarda oluşturulması derleyici hataları oluşturur. Yönergeler, uygulamanın ne zaman derleneceğini belirtir.

Eğitmen Varlığı

Instructor entity

Aşağıdaki kodla oluşturun Models/Instructor.cs :

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

Birden çok öznitelik tek satırda olabilir. HireDate Öznitelikler aşağıdaki gibi yazılabilir:

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

CourseAssignments ve OfficeAssignment özellikleri gezinti özellikleridir.

Eğitmen herhangi bir sayıda ders verebilir, bu nedenle CourseAssignments koleksiyon olarak tanımlanır.

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

Eğitmenin en fazla bir ofisi olabilir, bu nedenle özelliğin OfficeAssignment tek OfficeAssignment bir varlığı vardır. OfficeAssignment hiçbir office atanmamışsa null olur.

public OfficeAssignment OfficeAssignment { get; set; }

OfficeAssignment varlığı

OfficeAssignment entity

Aşağıdaki kodla oluşturun Models/OfficeAssignment.cs :

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

Key özniteliği

[Key] Özniteliği, özellik adı classnameID veya ID dışında bir şey olduğunda bir özelliği birincil anahtar (PK) olarak tanımlamak için kullanılır.

ve OfficeAssignment varlıkları arasında Instructor bire sıfır veya bir ilişkisi vardır. Bir ofis ataması yalnızca atandığı eğitmenle ilişkili olarak bulunur. OfficeAssignment PK aynı zamanda varlığın yabancı anahtarıdır (FKInstructor).

EF CoreID veya classnameID adlandırma kuralına uymadığından otomatik olarak PK OfficeAssignmentInstructorID olarak tanınamıyorInstructorID. Bu nedenle, Key özniteliği PK olarak tanımlamak InstructorID için kullanılır:

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

Varsayılan olarak, EF Core sütun tanımlayıcı bir ilişki için olduğundan anahtarı veritabanı oluşturulmamış olarak ele alır.

Eğitmen gezinti özelliği

Belirli Instructor.OfficeAssignment bir eğitmen için satır OfficeAssignment olmadığından gezinti özelliği null olabilir. Eğitmenin ofis ödevi olmayabilir.

OfficeAssignment.Instructor Yabancı anahtar InstructorID türü null atanamayan bir değer türü olduğundan intgezinti özelliğinin her zaman bir eğitmen varlığı olacaktır. Bir ofis ödevi, eğitmen olmadan mevcut olamaz.

Bir Instructor varlığın ilgili OfficeAssignment bir varlığı olduğunda, her varlığın gezinti özelliğinde diğerine bir başvurusu olur.

Kurs Varlığı

Course entity

Aşağıdaki kodla güncelleştirin Models/Course.cs :

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

Varlığın Course yabancı anahtar (FK) özelliği DepartmentIDvardır. DepartmentID ilgili Department varlığa işaret eder. Varlığın Course bir Department gezinti özelliği vardır.

EF Core modelin ilgili varlık için gezinti özelliği olduğunda veri modeli için yabancı anahtar özelliği gerektirmez. EF Core gerektiğinde otomatik olarak veritabanında FK'ler oluşturur. EF Coreotomatik olarak oluşturulan FK'ler için gölge özellikler oluşturur. Ancak, FK'yi veri modeline açıkça dahil ederek güncelleştirmeleri daha basit ve daha verimli hale getirebilirsiniz. Örneğin, FK özelliğinin DepartmentIDdahil edilmediği bir model düşünün. Düzenlemek üzere bir kurs varlığı getirildiğinde:

  • Özellik Department açıkça yüklenmediyse null olur.
  • Kurs varlığını güncelleştirmek için önce varlığın Department getirilmesi gerekir.

FK özelliği DepartmentID veri modeline dahil edildiğinde, bir güncelleştirmeden önce varlığı getirmeye Department gerek yoktur.

DatabaseGenerated özniteliği

özniteliği, [DatabaseGenerated(DatabaseGeneratedOption.None)] PK'nin veritabanı tarafından oluşturulmak yerine uygulama tarafından sağlandığını belirtir.

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

Varsayılan olarak, EF Core PK değerlerinin veritabanı tarafından oluşturulduğunu varsayar. Veritabanı tarafından oluşturulan genellikle en iyi yaklaşımdır. Varlıklar için Course kullanıcı PK'yı belirtir. Örneğin, matematik bölümü için 1000 serisi, İngilizce bölümü için 2000 serisi gibi bir ders numarası.

Özniteliği, DatabaseGenerated varsayılan değerleri oluşturmak için de kullanılabilir. Örneğin, veritabanı otomatik olarak bir satırın oluşturulduğu veya güncelleştirilildiği tarihi kaydetmek için bir tarih alanı oluşturabilir. Daha fazla bilgi için bkz . Oluşturulan Özellikler.

Yabancı anahtar ve gezinti özellikleri

Varlıktaki Course yabancı anahtar (FK) özellikleri ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

Kurs bir bölüme atandığından FK ve Department gezinti özelliği vardırDepartmentID.

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

Bir kursta kayıtlı herhangi bir sayıda öğrenci olabilir, bu nedenle Enrollments gezinti özelliği bir koleksiyondur:

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

Bir kurs birden çok eğitmen tarafından öğretilebilir, bu nedenle CourseAssignments gezinti özelliği bir koleksiyondur:

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

CourseAssignmentdaha sonra açıklanacaktır.

Departman varlığı

Department entity

Aşağıdaki kodla oluşturun Models/Department.cs :

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

Column özniteliği

Column Daha önce sütun adı eşlemesini değiştirmek için özniteliği kullanılıyordu. Varlığın kodunda Department , Column SQL veri türü eşlemesini değiştirmek için özniteliği kullanılır. Budget Sütun, veritabanındaki SQL Server para türü kullanılarak tanımlanır:

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

Sütun eşlemesi genellikle gerekli değildir. EF Core özelliği için CLR türüne göre uygun SQL Server veri türünü seçer. CLR decimal türü bir SQL Server decimal türüyle eşler. Budget para birimi içindir ve para birimi veri türü para birimi için daha uygundur.

Yabancı anahtar ve gezinti özellikleri

FK ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

  • Bir bölümün yöneticisi olabilir veya olmayabilir.
  • Yönetici her zaman eğitmendir. Bu nedenle InstructorID özelliği, varlığa FK Instructor olarak eklenir.

Gezinti özelliği adlandırılmıştır Administrator ancak bir Instructor varlığı barındırmaktadır:

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

Yukarıdaki koddaki soru işareti (?) özelliğin null atanabilir olduğunu belirtir.

Bir bölümün birçok kursu olabileceği için Kurslar gezinti özelliği vardır:

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

Kural gereği, EF Core null değer atanamayan FK'ler ve çoka çok ilişkiler için art arda silmeyi etkinleştirir. Bu varsayılan davranış döngüsel art arda silme kurallarına neden olabilir. Döngüsel art arda silme kuralları, geçiş eklendiğinde özel duruma neden olur.

Örneğin, özellik null atanamaz olarak tanımlandıysa Department.InstructorID , EF Core art arda silme kuralı yapılandırılır. Bu durumda, yönetici olarak atanan eğitmen silindiğinde bölüm silinir. Bu senaryoda kısıtlama kuralı daha mantıklı olacaktır. Aşağıdaki akıcı API bir kısıtlama kuralı ayarlar ve art arda silmeyi devre dışı bırakır.

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

Kayıt varlığı

Kayıt kaydı, bir öğrencinin aldığı bir kursa yöneliktir.

Enrollment entity

Aşağıdaki kodla güncelleştirin Models/Enrollment.cs :

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

Yabancı anahtar ve gezinti özellikleri

FK özellikleri ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

Kayıt kaydı bir kurs içindir, bu nedenle bir CourseID FK özelliği ve bir Course gezinti özelliği vardır:

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

Kayıt kaydı bir öğrenci içindir, bu nedenle bir StudentID FK özelliği ve bir Student gezinti özelliği vardır:

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

Çoka Çok İlişkiler

ve Course varlıkları arasında Student çoka çok ilişkisi vardır. Varlık, Enrollment veritabanında yükü olan çoka çok birleştirme tablosu olarak çalışır. "Yük ile", tablonun birleştirilen tablolar için FK'ler dışında ek veriler içerdiği anlamına gelir Enrollment (bu örnekte PK ve Grade).

Aşağıdaki çizimde bu ilişkilerin bir varlık diyagramında nasıl göründüğü gösterilmektedir. (Bu diyagram kullanılarak oluşturulmuşturEF 6.x için EF Power Tools . Diyagramı oluşturmak öğreticinin bir parçası değildir.)

Student-Course many to many relationship

Her ilişki çizgisinin bir ucunda 1, diğer ucunda ise bire çok ilişkisini gösteren bir yıldız işareti (*) vardır.

Enrollment Tabloda not bilgileri yoksa, yalnızca iki FK 'yi (CourseID ve StudentID) içermesi gerekir. Yükü olmayan çoka çok birleştirme tablosu bazen saf birleştirme tablosu (PJT) olarak adlandırılır.

ve Course varlıkları, Instructor saf birleştirme tablosu kullanan çoka çok ilişkisine sahiptir.

Not: EF 6.x, çoka çok ilişkiler için örtük birleştirme tablolarını destekler, ancak EF Core desteklemez. Daha fazla bilgi için bkz. 2.0'da EF CoreÇoka çok ilişkiler.

CourseAssignment varlığı

CourseAssignment entity

Aşağıdaki kodla oluşturun Models/CourseAssignment.cs :

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

Eğitmenden Kurslara çoka çok ilişkisi bir birleştirme tablosu gerektirir ve bu birleştirme tablosunun varlığı CourseAssignment'tır.

Instructor-to-Courses m:M

Birleştirme varlığını adlandırmak yaygın bir durumdır EntityName1EntityName2. Örneğin, Bu deseni kullanarak Eğitmenden Kurslara birleştirme tablosu olacaktır CourseInstructor. Ancak, ilişkiyi açıklayan bir ad kullanmanızı öneririz.

Veri modelleri basit bir şekilde başlar ve büyür. Yüksüz tabloları birleştirme (PJT) genellikle yükü içerecek şekilde gelişir. Açıklayıcı bir varlık adıyla başlayarak, birleştirme tablosu değiştiğinde adın değişmesi gerekmez. İdeal olarak, birleştirme varlığının iş etki alanında kendi doğal (muhtemelen tek sözcük) adı olabilir. Örneğin, Kitaplar ve Müşteriler Derecelendirmeler adlı bir katılma varlığıyla ilişkilendirilebilir. Eğitmenden Kurslara çoka çok ilişkisi için yerine CourseAssignment tercih CourseInstructoredilir.

Bileşik anahtar

(InstructorID ve CourseID) içindeki CourseAssignment iki FK, tablonun her satırını CourseAssignment benzersiz olarak tanımlar. CourseAssignment özel bir PK gerektirmez. InstructorID ve CourseID özellikleri bileşik PK işlevi görür. için bileşik PK'leri EF Core belirtmenin tek yolu akıcı API'yi kullanmaktır. Sonraki bölümde bileşik PK'nin nasıl yapılandırılır gösterilmektedir.

Bileşik anahtar aşağıdakileri sağlar:

  • Bir kurs için birden çok satıra izin verilir.
  • Bir eğitmen için birden çok satıra izin verilir.
  • Aynı eğitmen ve kurs için birden çok satıra izin verilmez.

Enrollment Birleştirme varlığı kendi PK'sini tanımlar, bu nedenle bu tür yinelemeler mümkündür. Bu tür yinelemeleri önlemek için:

  • FK alanlarına benzersiz bir dizin ekleyin veya
  • gibi CourseAssignmentbir birincil bileşik anahtarla yapılandırınEnrollment. Daha fazla bilgi için bkz . Dizinler.

Veritabanı bağlamını güncelleştirme

Aşağıdaki kodla güncelleştirin Data/SchoolContext.cs :

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

Yukarıdaki kod yeni varlıkları ekler ve varlığın bileşik PK'sini CourseAssignment yapılandırılır.

Özniteliklere alternatif fluent API

Yukarıdaki OnModelCreating koddaki yöntem, davranışı yapılandırmak EF Core için akıcı API'yi kullanır. API'ye "fluent" adı verilir çünkü genellikle bir dizi yöntem çağrısını tek bir deyimde dizeleyerek kullanılır. Aşağıdaki kod , akıcı API örneğidir:

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

Bu öğreticide, akıcı API yalnızca özniteliklerle yapılamaz veritabanı eşlemesi için kullanılır. Ancak, akıcı API özniteliklerle yapılabilecek biçimlendirme, doğrulama ve eşleme kurallarının çoğunu belirtebilir.

gibi MinimumLength bazı öznitelikler akıcı API ile uygulanamaz. MinimumLength şemayı değiştirmez, yalnızca minimum uzunluk doğrulama kuralı uygular.

Bazı geliştiriciler, varlık sınıflarını "temiz" tutabilmek için yalnızca akıcı API'yi kullanmayı tercih eder. Öznitelikler ve akıcı API karıştırılabilir. Yalnızca akıcı API ile (bileşik PK belirterek) gerçekleştirilebilecek bazı yapılandırmalar vardır. Yalnızca özniteliklerle (MinimumLength) yapilebilen bazı yapılandırmalar vardır. Akıcı API veya öznitelikleri kullanmak için önerilen uygulama:

  • Bu iki yaklaşımdan birini seçin.
  • Seçilen yaklaşımı mümkün olduğunca tutarlı bir şekilde kullanın.

Bu öğreticide kullanılan özniteliklerden bazıları şunlar için kullanılır:

  • Yalnızca doğrulama (örneğin, MinimumLength).
  • EF Core yalnızca yapılandırma (örneğin, HasKey).
  • Doğrulama ve EF Core yapılandırma (örneğin, [StringLength(50)]).

Öznitelikler ve akıcı API hakkında daha fazla bilgi için bkz . Yapılandırma yöntemleri.

Varlık diyagramı

Aşağıdaki çizimde, TAMAMLANMıŞ Okul modeli için EF Power Tools'un oluşturduğu diyagram gösterilmektedir.

Entity diagram

Yukarıdaki diyagramda aşağıdakiler gösterilir:

  • Birkaç bire çok ilişki çizgisi (1 - *).
  • ve OfficeAssignment varlıkları arasındaki Instructor bire sıfır veya bir ilişki çizgisi (1 -0,.1).
  • ve Department varlıkları arasındaki Instructor sıfır veya bire çok ilişki çizgisi (0..1 - *).

Veritabanının tohumunu oluşturma

içindeki Data/DbInitializer.cskodu güncelleştirin:

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("2016-09-01") },
                new Student { FirstMidName = "Meredith", LastName = "Alonso",
                    EnrollmentDate = DateTime.Parse("2018-09-01") },
                new Student { FirstMidName = "Arturo",   LastName = "Anand",
                    EnrollmentDate = DateTime.Parse("2019-09-01") },
                new Student { FirstMidName = "Gytis",    LastName = "Barzdukas",
                    EnrollmentDate = DateTime.Parse("2018-09-01") },
                new Student { FirstMidName = "Yan",      LastName = "Li",
                    EnrollmentDate = DateTime.Parse("2018-09-01") },
                new Student { FirstMidName = "Peggy",    LastName = "Justice",
                    EnrollmentDate = DateTime.Parse("2017-09-01") },
                new Student { FirstMidName = "Laura",    LastName = "Norman",
                    EnrollmentDate = DateTime.Parse("2019-09-01") },
                new Student { FirstMidName = "Nino",     LastName = "Olivetto",
                    EnrollmentDate = DateTime.Parse("2011-09-01") }
            };

            context.Students.AddRange(students);
            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") }
            };

            context.Instructors.AddRange(instructors);
            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 }
            };

            context.Departments.AddRange(departments);
            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
                },
            };

            context.Courses.AddRange(courses);
            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" },
            };

            context.OfficeAssignments.AddRange(officeAssignments);
            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
                    },
            };

            context.CourseAssignments.AddRange(courseInstructors);
            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();
        }
    }
}

Yukarıdaki kod, yeni varlıklar için tohum verileri sağlar. Bu kodun çoğu yeni varlık nesneleri oluşturur ve örnek verileri yükler. Örnek veriler test için kullanılır. Bkz Enrollments . ve CourseAssignments kaça çok birleştirme tablolarının dağıtılabildiğine ilişkin örnekler için.

Geçiş ekleme

Projeyi derleyin.

PMC'de aşağıdaki komutu çalıştırın.

Add-Migration ComplexDataModel

Yukarıdaki komut, olası veri kaybıyla ilgili bir uyarı görüntüler.

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

database update Komut çalıştırılırsa aşağıdaki hata oluşturulur:

The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Course_dbo.Department_DepartmentID". The conflict occurred in
database "ContosoUniversity", table "dbo.Department", column 'DepartmentID'.

Sonraki bölümde, bu hatayla ilgili yapmanız gerekenleri göreceksiniz.

Geçişi uygulama veya bırakma ve yeniden oluşturma

Artık var olan bir veritabanınız olduğuna göre, bu veritabanına değişiklikleri nasıl uygulayabileceğinizi düşünmeniz gerekir. Bu öğreticide iki alternatif gösterilmektedir:

  • Veritabanını bırakın ve yeniden oluşturun. SQLite kullanıyorsanız bu bölümü seçin.
  • Geçişi var olan veritabanına uygulayın. Bu bölümdeki yönergeler SQLite için değil yalnızca SQL Server için çalışır.

İki seçenek de SQL Server için çalışır. Apply-migration yöntemi daha karmaşık ve zaman alıcı olsa da, gerçek dünya, üretim ortamları için tercih edilen yaklaşımdır.

Veritabanını bırakma ve yeniden oluşturma

SQL Server kullanıyorsanız ve aşağıdaki bölümdeki apply-migration yaklaşımını uygulamak istiyorsanız bu bölümü atlayın.

Yeni veritabanı oluşturmaya zorlamak EF Core için veritabanını bırakın ve güncelleştirin:

  • Paket Yöneticisi Konsolu'nda (PMC) aşağıdaki komutu çalıştırın:

    Drop-Database
    
  • Migrations klasörünü silin ve aşağıdaki komutu çalıştırın:

    Add-Migration InitialCreate
    Update-Database
    

Uygulamayı çalıştırma. Uygulamayı çalıştırmak yöntemini çalıştırır DbInitializer.Initialize . yeni DbInitializer.Initialize veritabanını doldurur.

Veritabanını SSOX'ta açın:

  • SSOX daha önce açıldıysa Yenile düğmesine tıklayın.

  • Tablolar düğümünü genişletin. Oluşturulan tablolar görüntülenir.

    Tables in SSOX

  • CourseAssignment tablosunu inceleyin:

    • CourseAssignment tablosuna sağ tıklayın ve Verileri Görüntüle'yi seçin.
    • CourseAssignment tablosunun veri içerdiğini doğrulayın.

    CourseAssignment data in SSOX

Geçişi uygulama

Bu bölüm isteğe bağlıdır. Bu adımlar yalnızca SQL Server LocalDB için çalışır ve yalnızca önceki Drop ve re-create veritabanını atladıysanız.

Geçişler mevcut verilerle çalıştırıldığında, mevcut verilerden memnun olmayan FK kısıtlamaları olabilir. Üretim verileriyle, mevcut verileri geçirmek için adımlar atılmalıdır. Bu bölümde FK kısıtlama ihlallerini düzeltmeye yönelik bir örnek verilmiştir. Yedek olmadan bu kod değişikliklerini yapmayın. Önceki Drop ve re-create the database bölümünü tamamladıysanız bu kod değişikliklerini yapmayın.

Dosya {timestamp}_ComplexDataModel.cs aşağıdaki kodu içerir:

migrationBuilder.AddColumn<int>(
    name: "DepartmentID",
    table: "Course",
    type: "int",
    nullable: false,
    defaultValue: 0);

Yukarıdaki kod tabloya Course null atanamaz DepartmentID bir FK ekler. Önceki öğreticideki veritabanı içinde Coursesatırlar içerir, böylece tablo geçişler tarafından güncelleştirilemez.

Geçişin ComplexDataModel mevcut verilerle çalışmasını sağlamak için:

  • Yeni sütuna (DepartmentID) varsayılan değer verecek şekilde kodu değiştirin.
  • Varsayılan bölüm olarak hareket etmek için "Temp" adlı sahte bir departman oluşturun.

Yabancı anahtar kısıtlamalarını düzeltme

ComplexDataModel Geçiş sınıfında yöntemini güncelleştirinUp:

  • {timestamp}_ComplexDataModel.cs dosyasını açın.
  • Sütunu tabloya ekleyen DepartmentID kod satırını açıklama satırı olarak açıklama satırına ekleyin Course .
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);

Aşağıdaki vurgulanmış kodu ekleyin. Yeni kod bloğun arkasına .CreateTable( name: "Department" geçer:

migrationBuilder.CreateTable(
    name: "Department",
    columns: table => new
    {
        DepartmentID = table.Column<int>(type: "int", nullable: false)
            .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
        Budget = table.Column<decimal>(type: "money", nullable: false),
        InstructorID = table.Column<int>(type: "int", nullable: true),
        Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
        StartDate = table.Column<DateTime>(type: "datetime2", 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);

Önceki değişikliklerle, yöntem çalıştırıldıktan sonra var olan Course satırlar "Geçici" bölümle ComplexDataModel.Up ilişkilendirilecektir.

Burada gösterilen durumu işleme yöntemi bu öğretici için basitleştirilmiştir. Bir üretim uygulaması şu şekilde olur:

  • Yeni Department satırlara satırlar ve ilgili Course satırlar eklemek Department için kod veya betikler ekleyin.
  • için "Temp" bölümünü veya varsayılan değerini Course.DepartmentIDkullanmayın.
  • Paket Yöneticisi Konsolu'nda (PMC) aşağıdaki komutu çalıştırın:

    Update-Database
    

DbInitializer.Initialize yöntemi yalnızca boş bir veritabanıyla çalışacak şekilde tasarlandığından, Öğrenci ve Kurs tablolarındaki tüm satırları silmek için SSOX kullanın. (Art arda silme işlemi Kayıt tablosuyla ilgilenir.)

Uygulamayı çalıştırma. Uygulamayı çalıştırmak yöntemini çalıştırır DbInitializer.Initialize . yeni DbInitializer.Initialize veritabanını doldurur.

Sonraki adımlar

Sonraki iki öğretici, ilgili verilerin nasıl okunup güncelleştirileceğini gösterir.

Önceki öğreticiler üç varlıklardan oluşan temel bir veri modeliyle çalışıyordu. Bu öğreticide:

  • Daha fazla varlık ve ilişki eklenir.
  • Veri modeli biçimlendirme, doğrulama ve veritabanı eşleme kuralları belirtilerek özelleştirilir.

Tamamlanan veri modelinin varlık sınıfları aşağıdaki çizimde gösterilmiştir:

Entity diagram

Çözemediğiniz sorunlarla karşılaşırsanız tamamlanmış uygulamayı indirin.

Veri modelini özniteliklerle özelleştirme

Bu bölümde, veri modeli öznitelikler kullanılarak özelleştirilir.

DataType özniteliği

Öğrenci sayfalarında şu anda kayıt tarihinin saati görüntülenir. Genellikle, tarih alanları saati değil yalnızca tarihi gösterir.

Aşağıdaki vurgulanmış kodla güncelleştirin Models/Student.cs :

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

DataType özniteliği, veritabanı iç türünden daha özel bir veri türü belirtir. Bu durumda, tarih ve saat değil yalnızca tarih görüntülenmelidir. DataType Numaralandırması Date, Time, Telefon Number, Currency, EmailAddress gibi birçok veri türü sağlar. Özniteliği, DataType uygulamanın türe özgü özellikleri otomatik olarak sağlamasına da olanak sağlayabilir. Örnek:

  • Bağlantı mailto: için DataType.EmailAddressotomatik olarak oluşturulur.
  • Tarih seçici çoğu tarayıcıda sağlanır DataType.Date .

özniteliği, DataType HTML 5 data- tarayıcılarının tükettiği HTML 5 (belirgin veri tiresi) öznitelikleri yayar. DataType Öznitelikler doğrulama sağlamaz.

DataType.Date görüntülenen tarihin biçimini belirtmez. Varsayılan olarak, tarih alanı sunucunun CultureInfo'sunu temel alan varsayılan biçimlere göre görüntülenir.

DisplayFormat özniteliği, tarih biçimini açıkça belirtmek için kullanılır:

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

ayarı, ApplyFormatInEditMode biçimlendirmenin düzenleme kullanıcı arabirimine de uygulanması gerektiğini belirtir. Bazı alanlar kullanmamalıdır ApplyFormatInEditMode. Örneğin, para birimi simgesi genellikle düzenleme metin kutusunda görüntülenmemelidir.

DisplayFormat özniteliği tek başına kullanılabilir. özniteliğini özniteliğiyle DisplayFormat kullanmak DataType genellikle iyi bir fikirdir. özniteliği, DataType verilerin ekranda nasıl işlendiğinin aksine semantiğini iletir. DataType özniteliği, içinde DisplayFormatbulunmayan aşağıdaki avantajları sağlar:

  • Tarayıcı HTML5 özelliklerini etkinleştirebilir. Örneğin, bir takvim denetimi, yerel ayara uygun para birimi simgesi, e-posta bağlantıları, istemci tarafı giriş doğrulaması vb. gösterin.
  • Varsayılan olarak, tarayıcı verileri yerel ayara göre doğru biçimi kullanarak işler.

Daha fazla bilgi için giriş Etiketi Yardımcısı belgelerine bakın<.>

Uygulamayı çalıştırma. Öğrenci Dizini sayfasına gidin. Süreler artık görüntülenmez. Modeli kullanan Student her görünümde tarih saat olmadan görüntülenir.

Students index page showing dates without times

StringLength özniteliği

Veri doğrulama kuralları ve doğrulama hata iletileri özniteliklerle belirtilebilir. StringLength özniteliği, bir veri alanında izin verilen en düşük ve en uzun karakter uzunluğunu belirtir. StringLength özniteliği istemci tarafı ve sunucu tarafı doğrulama da sağlar. En düşük değerin veritabanı şeması üzerinde hiçbir etkisi yoktur.

Student Modeli aşağıdaki kodla güncelleştirin:

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, ErrorMessage = "First name cannot be longer than 50 characters.")]
        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; }
    }
}

Yukarıdaki kod adları en fazla 50 karakterle sınırlar. StringLength özniteliği, kullanıcının bir ad için boşluk girmesini engellemez. RegularExpression özniteliği girişe kısıtlamalar uygulamak için kullanılır. Örneğin, aşağıdaki kod ilk karakterin büyük harf olmasını ve kalan karakterlerin alfabetik olmasını gerektirir:

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

Uygulamayı çalıştırın:

  • Öğrenciler sayfasına gidin.
  • Yeni Oluştur'u seçin ve 50 karakterden uzun bir ad girin.
  • Oluştur'u seçtiğinizde istemci tarafı doğrulama bir hata iletisi gösterir.

Students index page showing string length errors

SQL Server Nesne Gezgini'de (SSOX), Student tablosuna çift tıklayarak Student tablo tasarımcısını açın.

Students table in SSOX before migrations

Yukarıdaki görüntüde tablonun şeması Student gösterilir. Ad alanlarının türü nvarchar(MAX) vardır çünkü geçişler db üzerinde çalıştırılmamıştır. Geçişler bu öğreticinin ilerleyen bölümlerinde çalıştırıldığında ad alanları olur nvarchar(50).

Column özniteliği

Öznitelikler, sınıfların ve özelliklerin veritabanına nasıl eşlenebileceğini denetleyebilir. Bu bölümde özniteliği, özelliğin Column adını FirstMidName DB'deki "FirstName" ile eşlemek için kullanılır.

Veritabanı oluşturulduğunda, modeldeki özellik adları sütun adları için kullanılır (özniteliğin Column kullanılması dışında).

Alan Student ikinci ad da içerebileceğinden model ad alanı için kullanır FirstMidName .

Student.cs Dosyayı aşağıdaki vurgulanmış kodla güncelleştirin:

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, ErrorMessage = "First name cannot be longer than 50 characters.")]
        [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; }
    }
}

Önceki değişiklikle birlikte, Student.FirstMidName uygulamada tablonun sütununa FirstName eşler Student .

özniteliğinin Column eklenmesi, modelinin desteklenmesinde SchoolContextdeğişiklik gösterir. öğesinin yedeklenmesi SchoolContext artık veritabanıyla eşleşir. Uygulama geçişleri uygulamadan önce çalıştırılırsa aşağıdaki özel durum oluşturulur:

SqlException: Invalid column name 'FirstName'.

Db'yi güncelleştirmek için:

  • Projeyi derleyin.
  • Proje klasöründe bir komut penceresi açın. Yeni bir geçiş oluşturmak ve db'yi güncelleştirmek için aşağıdaki komutları girin:
Add-Migration ColumnFirstName
Update-Database

Komut migrations add ColumnFirstName aşağıdaki uyarı iletisini oluşturur:

An operation was scaffolded that may result in the loss of data.
Please review the migration for accuracy.

Ad alanları artık 50 karakterle sınırlı olduğundan uyarı oluşturulur. DB'deki bir ad 50'den fazla karaktere sahipse, 51-son karakter kaybolur.

  • Uygulamayı test etme.

SSOX'ta Student tablosunu açın:

Students table in SSOX after migrations

Geçiş uygulanmadan önce ad sütunları nvarchar(MAX) türündeydi. Ad sütunları artık nvarchar(50)şeklindedir. Sütun adı olarak değiştirildi FirstMidNameFirstName.

Dekont

Aşağıdaki bölümde, uygulamayı bazı aşamalarda derlemek derleyici hataları oluşturur. Yönergeler, uygulamanın ne zaman derleneceğini belirtir.

Öğrenci varlık güncelleştirmesi

Student entity

Aşağıdaki kodla güncelleştirin Models/Student.cs :

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, ErrorMessage = "First name cannot be longer than 50 characters.")]
        [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; }
    }
}

Gerekli özniteliği

özniteliği, Required ad özelliklerini gerekli alanlara getirir. Required Öznitelik, değer türleri (DateTime, int, doublevb.) gibi null atanamayan türler için gerekli değildir. Null yapılamaz türler otomatik olarak gerekli alanlar olarak kabul edilir.

özniteliği, Required özniteliğinde StringLength en düşük uzunluk parametresiyle değiştirilebilir:

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

Display özniteliği

özniteliği, Display metin kutuları için başlık "Ad", "Soyadı", "Tam Ad" ve "Kayıt Tarihi" olması gerektiğini belirtir. Varsayılan başlık sözcükleri bölen boşluk yoktu, örneğin "Soyadı."

FullName hesaplanan özelliği

FullName , diğer iki özelliğin birleştirilmesiyle oluşturulan bir değer döndüren hesaplanmış bir özelliktir. FullName ayarlanamaz, yalnızca bir get erişimciye sahiptir. FullName Veritabanında sütun oluşturulmaz.

Eğitmen Varlığı Oluşturma

Instructor entity

Aşağıdaki kodla oluşturun Models/Instructor.cs :

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

Birden çok öznitelik tek satırda olabilir. HireDate Öznitelikler aşağıdaki gibi yazılabilir:

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

CourseAssignments ve OfficeAssignment gezinti özellikleri

CourseAssignments ve OfficeAssignment özellikleri gezinti özellikleridir.

Eğitmen herhangi bir sayıda ders verebilir, bu nedenle CourseAssignments koleksiyon olarak tanımlanır.

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

Gezinti özelliği birden çok varlık barındırıyorsa:

  • Girdilerin eklenebileceği, silinebileceği ve güncelleştirilebileceği bir liste türü olmalıdır.

Gezinti özelliği türleri şunlardır:

  • ICollection<T>
  • List<T>
  • HashSet<T>

belirtilirse ICollection<T> , EF Core varsayılan olarak bir HashSet<T> koleksiyon oluşturur.

Varlık CourseAssignment , çoka çok ilişkileri bölümünde açıklanmıştır.

Contoso Üniversitesi iş kuralları, bir eğitmenin en fazla bir ofise sahip olabileceğini belirtir. OfficeAssignment özelliği tek OfficeAssignment bir varlığı barındırıyor. OfficeAssignment hiçbir office atanmamışsa null olur.

public OfficeAssignment OfficeAssignment { get; set; }

OfficeAssignment varlığını oluşturma

OfficeAssignment entity

Aşağıdaki kodla oluşturun Models/OfficeAssignment.cs :

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

Key özniteliği

[Key] Özniteliği, özellik adı classnameID veya ID dışında bir şey olduğunda bir özelliği birincil anahtar (PK) olarak tanımlamak için kullanılır.

ve OfficeAssignment varlıkları arasında Instructor bire sıfır veya bir ilişkisi vardır. Bir ofis ataması yalnızca atandığı eğitmenle ilişkili olarak bulunur. OfficeAssignment PK aynı zamanda varlığın yabancı anahtarıdır (FKInstructor). EF Core şu nedenlerden dolayı PK olarak otomatik olarak tanınamıyor InstructorIDOfficeAssignment :

  • InstructorID ID veya classnameID adlandırma kuralına uymaz.

Bu nedenle, Key özniteliği PK olarak tanımlamak InstructorID için kullanılır:

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

Varsayılan olarak, EF Core sütun tanımlayıcı bir ilişki için olduğundan anahtarı veritabanı oluşturulmamış olarak ele alır.

Eğitmen gezinti özelliği

Varlığın OfficeAssignmentInstructor gezinti özelliği null atanabilir çünkü:

  • Başvuru türleri (sınıflar gibi null atanabilir).
  • Eğitmenin ofis ödevi olmayabilir.

Varlığın OfficeAssignment null atanamaz Instructor bir gezinti özelliği vardır çünkü:

  • InstructorID null atanamaz.
  • Bir ofis ödevi, eğitmen olmadan mevcut olamaz.

Bir Instructor varlığın ilgili OfficeAssignment bir varlığı olduğunda, her varlığın gezinti özelliğinde diğerine bir başvurusu olur.

[Required] özniteliği gezinti özelliğine Instructor uygulanabilir:

[Required]
public Instructor Instructor { get; set; }

Yukarıdaki kod, ilgili bir eğitmen olması gerektiğini belirtir. Yabancı anahtar (aynı zamanda PK) null atanamaz olduğundan InstructorID yukarıdaki kod gereksizdir.

Kurs Varlığını Değiştirme

Course entity

Aşağıdaki kodla güncelleştirin Models/Course.cs :

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

Varlığın Course yabancı anahtar (FK) özelliği DepartmentIDvardır. DepartmentID ilgili Department varlığa işaret eder. Varlığın Course bir Department gezinti özelliği vardır.

EF Core modelin ilgili varlık için gezinti özelliği olduğunda veri modeli için FK özelliği gerektirmez.

EF Core gerektiğinde otomatik olarak veritabanında FK'ler oluşturur. EF Coreotomatik olarak oluşturulan FK'ler için gölge özellikler oluşturur. Veri modelinde FK'nin olması güncelleştirmeleri daha basit ve daha verimli hale getirebilir. Örneğin, FK özelliğinin DepartmentIDdahil edilmediği bir model düşünün. Düzenlemek üzere bir kurs varlığı getirildiğinde:

  • Varlık Department açıkça yüklenmediyse null olur.
  • Kurs varlığını güncelleştirmek için önce varlığın Department getirilmesi gerekir.

FK özelliği DepartmentID veri modeline dahil edildiğinde, bir güncelleştirmeden önce varlığı getirmeye Department gerek yoktur.

DatabaseGenerated özniteliği

özniteliği, [DatabaseGenerated(DatabaseGeneratedOption.None)] PK'nin veritabanı tarafından oluşturulmak yerine uygulama tarafından sağlandığını belirtir.

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

Varsayılan olarak, EF Core PK değerlerinin VERITABANı tarafından oluşturulduğunu varsayar. Veritabanı tarafından oluşturulan PK değerleri genellikle en iyi yaklaşımdır. Varlıklar için Course kullanıcı PK'yı belirtir. Örneğin, matematik bölümü için 1000 serisi, İngilizce bölümü için 2000 serisi gibi bir ders numarası.

Özniteliği, DatabaseGenerated varsayılan değerleri oluşturmak için de kullanılabilir. Örneğin, veritabanı bir satırın oluşturulduğu veya güncelleştirilildiği tarihi kaydetmek için otomatik olarak bir tarih alanı oluşturabilir. Daha fazla bilgi için bkz . Oluşturulan Özellikler.

Yabancı anahtar ve gezinti özellikleri

Varlıktaki Course yabancı anahtar (FK) özellikleri ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

Kurs bir bölüme atandığından FK ve Department gezinti özelliği vardırDepartmentID.

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

Bir kursta kayıtlı herhangi bir sayıda öğrenci olabilir, bu nedenle Enrollments gezinti özelliği bir koleksiyondur:

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

Bir kurs birden çok eğitmen tarafından öğretilebilir, bu nedenle CourseAssignments gezinti özelliği bir koleksiyondur:

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

CourseAssignmentdaha sonra açıklanacaktır.

Departman varlığını oluşturma

Department entity

Aşağıdaki kodla oluşturun Models/Department.cs :

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

Column özniteliği

Column Daha önce sütun adı eşlemesini değiştirmek için özniteliği kullanılıyordu. Varlığın kodunda Department , Column SQL veri türü eşlemesini değiştirmek için özniteliği kullanılır. Budget Sütun, veritabanındaki SQL Server para türü kullanılarak tanımlanır:

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

Sütun eşlemesi genellikle gerekli değildir. EF Core genellikle özelliği için CLR türüne göre uygun SQL Server veri türünü seçer. CLR decimal türü bir SQL Server decimal türüyle eşler. Budget para birimi içindir ve para birimi veri türü para birimi için daha uygundur.

Yabancı anahtar ve gezinti özellikleri

FK ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

  • Bir bölümün yöneticisi olabilir veya olmayabilir.
  • Yönetici her zaman eğitmendir. Bu nedenle InstructorID özelliği, varlığa FK Instructor olarak eklenir.

Gezinti özelliği adlandırılmıştır Administrator ancak bir Instructor varlığı barındırmaktadır:

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

Yukarıdaki koddaki soru işareti (?) özelliğin null atanabilir olduğunu belirtir.

Bir bölümün birçok kursu olabileceği için Kurslar gezinti özelliği vardır:

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

Not: Kurala göre, EF Core null atanamayan FK'ler ve çoka çok ilişkiler için art arda silmeyi etkinleştirir. Art arda silme işlemi döngüsel art arda silme kurallarına neden olabilir. Döngüsel art arda silme kuralları, geçiş eklendiğinde bir özel duruma neden olur.

Örneğin, özelliği null atanamaz olarak tanımlandıysa Department.InstructorID :

  • EF Core , eğitmen silindiğinde bölümü silmek için art arda silme kuralı yapılandırıyor.

  • Eğitmen silindiğinde bölümü silmek istenen davranış değildir.

  • Aşağıdaki akıcı API , art arda yerine bir kısıtlama kuralı ayarlar.

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

Yukarıdaki kod, bölüm eğitmeni ilişkisinde art arda silmeyi devre dışı bırakır.

Kayıt varlığını güncelleştirme

Kayıt kaydı, bir öğrencinin aldığı bir kursa yöneliktir.

Enrollment entity

Aşağıdaki kodla güncelleştirin Models/Enrollment.cs :

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

Yabancı anahtar ve gezinti özellikleri

FK özellikleri ve gezinti özellikleri aşağıdaki ilişkileri yansıtır:

Kayıt kaydı bir kurs içindir, bu nedenle bir CourseID FK özelliği ve bir Course gezinti özelliği vardır:

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

Kayıt kaydı bir öğrenci içindir, bu nedenle bir StudentID FK özelliği ve bir Student gezinti özelliği vardır:

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

Çoka Çok İlişkiler

ve Course varlıkları arasında Student çoka çok ilişkisi vardır. Varlık, Enrollment veritabanında yükü olan çoka çok birleştirme tablosu olarak çalışır. "Yük ile", tablonun birleştirilen tablolar için FK'ler dışında ek veriler içerdiği anlamına gelir Enrollment (bu örnekte PK ve Grade).

Aşağıdaki çizimde bu ilişkilerin bir varlık diyagramında nasıl göründüğü gösterilmektedir. (Bu diyagram kullanılarak oluşturulmuşturEF 6.x için EF Power Tools . Diyagramı oluşturmak öğreticinin bir parçası değildir.)

Student-Course many to many relationship

Her ilişki çizgisinin bir ucunda 1, diğer ucunda ise bire çok ilişkisini gösteren bir yıldız işareti (*) vardır.

Enrollment Tabloda not bilgileri yoksa, yalnızca iki FK 'yi (CourseID ve StudentID) içermesi gerekir. Yükü olmayan çoka çok birleştirme tablosu bazen saf birleştirme tablosu (PJT) olarak adlandırılır.

ve Course varlıkları, Instructor saf birleştirme tablosu kullanan çoka çok ilişkisine sahiptir.

Not: EF 6.x, çoka çok ilişkiler için örtük birleştirme tablolarını destekler, ancak EF Core desteklemez. Daha fazla bilgi için bkz. 2.0'da EF CoreÇoka çok ilişkiler.

CourseAssignment varlığı

CourseAssignment entity

Aşağıdaki kodla oluşturun Models/CourseAssignment.cs :

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

Eğitmenden Kurslara

Instructor-to-Courses m:M

Eğitmenden Kurslara çoka çok ilişkisi:

  • Varlık kümesi tarafından temsil edilmesi gereken bir birleştirme tablosu gerektirir.
  • Saf birleştirme tablosudur (yüksüz tablo).

Birleştirme varlığını adlandırmak yaygın bir durumdır EntityName1EntityName2. Örneğin, Bu deseni kullanarak Eğitmenden Kurslara birleştirme tablosu şeklindedir CourseInstructor. Ancak, ilişkiyi açıklayan bir ad kullanmanızı öneririz.

Veri modelleri basit bir şekilde başlar ve büyür. Yük olmayan birleştirmeler (PJT) genellikle yükü içerecek şekilde gelişir. Açıklayıcı bir varlık adıyla başlayarak, birleştirme tablosu değiştiğinde adın değişmesi gerekmez. İdeal olarak, birleştirme varlığının iş etki alanında kendi doğal (muhtemelen tek sözcük) adı olabilir. Örneğin, Kitaplar ve Müşteriler Derecelendirmeler adlı bir katılma varlığıyla ilişkilendirilebilir. Eğitmenden Kurslara çoka çok ilişkisi için yerine CourseAssignment tercih CourseInstructoredilir.

Bileşik anahtar

FK'ler null değer atanamaz. (InstructorID ve CourseID) içindeki CourseAssignment iki FK, tablonun her satırını CourseAssignment benzersiz olarak tanımlar. CourseAssignment özel bir PK gerektirmez. InstructorID ve CourseID özellikleri bileşik PK işlevi görür. için bileşik PK'leri EF Core belirtmenin tek yolu akıcı API'yi kullanmaktır. Sonraki bölümde bileşik PK'nin nasıl yapılandırılır gösterilmektedir.

Bileşik anahtar aşağıdakileri sağlar:

  • Bir kurs için birden çok satıra izin verilir.
  • Bir eğitmen için birden çok satıra izin verilir.
  • Aynı eğitmen ve kurs için birden çok satıra izin verilmez.

Enrollment Birleştirme varlığı kendi PK'sini tanımlar, bu nedenle bu tür yinelemeler mümkündür. Bu tür yinelemeleri önlemek için:

  • FK alanlarına benzersiz bir dizin ekleyin veya
  • gibi CourseAssignmentbir birincil bileşik anahtarla yapılandırınEnrollment. Daha fazla bilgi için bkz . Dizinler.

VERITABANı bağlamını güncelleştirme

aşağıdaki vurgulanmış kodu içine Data/SchoolContext.csekleyin:

using ContosoUniversity.Models;
using Microsoft.EntityFrameworkCore;

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

        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollment { get; set; }
        public DbSet<Student> Student { 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 });
        }
    }
}

Yukarıdaki kod yeni varlıkları ekler ve varlığın bileşik PK'sini CourseAssignment yapılandırılır.

Özniteliklere alternatif fluent API

Yukarıdaki OnModelCreating koddaki yöntem, davranışı yapılandırmak EF Core için akıcı API'yi kullanır. API'ye "fluent" adı verilir çünkü genellikle bir dizi yöntem çağrısını tek bir deyimde dizeleyerek kullanılır. Aşağıdaki kod , akıcı API örneğidir:

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

Bu öğreticide, akıcı API yalnızca özniteliklerle yapılamaz veritabanı eşlemesi için kullanılır. Ancak, akıcı API özniteliklerle yapılabilecek biçimlendirme, doğrulama ve eşleme kurallarının çoğunu belirtebilir.

gibi MinimumLength bazı öznitelikler akıcı API ile uygulanamaz. MinimumLength şemayı değiştirmez, yalnızca minimum uzunluk doğrulama kuralı uygular.

Bazı geliştiriciler, varlık sınıflarını "temiz" tutabilmek için yalnızca akıcı API'yi kullanmayı tercih eder. Öznitelikler ve akıcı API karıştırılabilir. Yalnızca akıcı API ile (bileşik PK belirterek) gerçekleştirilebilecek bazı yapılandırmalar vardır. Yalnızca özniteliklerle (MinimumLength) yapilebilen bazı yapılandırmalar vardır. Akıcı API veya öznitelikleri kullanmak için önerilen uygulama:

  • Bu iki yaklaşımdan birini seçin.
  • Seçilen yaklaşımı mümkün olduğunca tutarlı bir şekilde kullanın.

Bu öğreticide kullanılan özniteliklerden bazıları şunlar için kullanılır:

  • Yalnızca doğrulama (örneğin, MinimumLength).
  • EF Core yalnızca yapılandırma (örneğin, HasKey).
  • Doğrulama ve EF Core yapılandırma (örneğin, [StringLength(50)]).

Öznitelikler ve akıcı API hakkında daha fazla bilgi için bkz . Yapılandırma yöntemleri.

İlişkileri Gösteren Varlık Diyagramı

Aşağıdaki çizimde, TAMAMLANMıŞ Okul modeli için EF Power Tools'un oluşturduğu diyagram gösterilmektedir.

Entity diagram

Yukarıdaki diyagramda aşağıdakiler gösterilir:

  • Birkaç bire çok ilişki çizgisi (1 - *).
  • ve OfficeAssignment varlıkları arasındaki Instructor bire sıfır veya bir ilişki çizgisi (1 -0,.1).
  • ve Department varlıkları arasındaki Instructor sıfır veya bire çok ilişki çizgisi (0..1 - *).

Test Verileri ile veritabanı tohumu oluşturma

içindeki Data/DbInitializer.cskodu güncelleştirin:

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.Student.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.Student.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.Enrollment.Where(
                    s =>
                            s.Student.ID == e.StudentID &&
                            s.Course.CourseID == e.CourseID).SingleOrDefault();
                if (enrollmentInDataBase == null)
                {
                    context.Enrollment.Add(e);
                }
            }
            context.SaveChanges();
        }
    }
}

Yukarıdaki kod, yeni varlıklar için tohum verileri sağlar. Bu kodun çoğu yeni varlık nesneleri oluşturur ve örnek verileri yükler. Örnek veriler test için kullanılır. Bkz Enrollments . ve CourseAssignments kaça çok birleştirme tablolarının dağıtılabildiğine ilişkin örnekler için.

Geçiş ekleme

Projeyi derleyin.

Add-Migration ComplexDataModel

Yukarıdaki komut, olası veri kaybıyla ilgili bir uyarı görüntüler.

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'

database update Komut çalıştırılırsa aşağıdaki hata oluşturulur:

The ALTER TABLE statement conflicted with the FOREIGN KEY constraint "FK_dbo.Course_dbo.Department_DepartmentID". The conflict occurred in
database "ContosoUniversity", table "dbo.Department", column 'DepartmentID'.

Geçişi uygulama

Artık var olan bir veritabanınız olduğuna göre, gelecekteki değişiklikleri nasıl uygulayabileceğinizi düşünmeniz gerekir. Bu öğreticide iki yaklaşım gösterilmektedir:

  • Veritabanını bırakma ve yeniden oluşturma
  • Geçişi var olan veritabanına uygulayın. Bu yöntem daha karmaşık ve zaman alıcı olsa da, gerçek dünyadaki üretim ortamları için tercih edilen yaklaşımdır. Not: Bu, öğreticinin isteğe bağlı bir bölümüdür. Bırakma ve yeniden oluşturma adımlarını gerçekleştirebilir ve bu bölümü atlayabilirsiniz. Bu bölümdeki adımları izlemek istiyorsanız bırakma ve yeniden oluşturma adımlarını gerçekleştirmeyin.

Veritabanını bırakma ve yeniden oluşturma

Güncelleştirilmiş DbInitializer içindeki kod, yeni varlıklar için tohum verileri ekler. Yeni bir veritabanı oluşturmaya zorlamak EF Core için, db'yi bırakın ve güncelleştirin:

Paket Yöneticisi Konsolu'nda (PMC) aşağıdaki komutu çalıştırın:

Drop-Database
Update-Database

Yardım bilgilerini almak için PMC'den komutunu çalıştırın Get-Help about_EntityFrameworkCore .

Uygulamayı çalıştırma. Uygulamayı çalıştırmak yöntemini çalıştırır DbInitializer.Initialize . yeni DbInitializer.Initialize veritabanını doldurur.

SSOX'ta db'yi açın:

  • SSOX daha önce açıldıysa Yenile düğmesine tıklayın.
  • Tablolar düğümünü genişletin. Oluşturulan tablolar görüntülenir.

Tables in SSOX

CourseAssignment tablosunu inceleyin:

  • CourseAssignment tablosuna sağ tıklayın ve Verileri Görüntüle'yi seçin.
  • CourseAssignment tablosunun veri içerdiğini doğrulayın.

CourseAssignment data in SSOX

Geçişi var olan veritabanına uygulama

Bu bölüm isteğe bağlıdır. Bu adımlar yalnızca önceki Drop bölümünü atlayıp veritabanı bölümünü yeniden oluşturduysanız çalışır.

Geçişler mevcut verilerle çalıştırıldığında, mevcut verilerden memnun olmayan FK kısıtlamaları olabilir. Üretim verileriyle, mevcut verileri geçirmek için adımlar atılmalıdır. Bu bölümde FK kısıtlama ihlallerini düzeltmeye yönelik bir örnek verilmiştir. Yedek olmadan bu kod değişikliklerini yapmayın. Önceki bölümü tamamlayıp veritabanını güncelleştirdiyseniz bu kod değişikliklerini yapmayın.

Dosya {timestamp}_ComplexDataModel.cs aşağıdaki kodu içerir:

migrationBuilder.AddColumn<int>(
    name: "DepartmentID",
    table: "Course",
    type: "int",
    nullable: false,
    defaultValue: 0);

Yukarıdaki kod tabloya Course null atanamaz DepartmentID bir FK ekler. Önceki öğreticideki veritabanı içinde Coursesatırlar içerir, böylece tablo geçişler tarafından güncelleştirilemez.

Geçişin ComplexDataModel mevcut verilerle çalışmasını sağlamak için:

  • Yeni sütuna (DepartmentID) varsayılan değer verecek şekilde kodu değiştirin.
  • Varsayılan bölüm olarak hareket etmek için "Temp" adlı sahte bir departman oluşturun.

Yabancı anahtar kısıtlamalarını düzeltme

Sınıflar Up yöntemini güncelleştirinComplexDataModel:

  • {timestamp}_ComplexDataModel.cs dosyasını açın.
  • Sütunu tabloya ekleyen DepartmentID kod satırını açıklama satırı olarak açıklama satırına ekleyin Course .
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);

Aşağıdaki vurgulanmış kodu ekleyin. Yeni kod bloğun arkasına .CreateTable( name: "Department" geçer:

migrationBuilder.CreateTable(
    name: "Department",
    columns: table => new
    {
        DepartmentID = table.Column<int>(type: "int", nullable: false)
            .Annotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn),
        Budget = table.Column<decimal>(type: "money", nullable: false),
        InstructorID = table.Column<int>(type: "int", nullable: true),
        Name = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: true),
        StartDate = table.Column<DateTime>(type: "datetime2", 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);

Önceki değişikliklerle, yöntem çalıştırıldıktan sonra var olan Course satırlar "Geçici" bölümle ComplexDataModelUp ilişkilendirilecektir.

Bir üretim uygulaması şu şekilde olur:

  • Yeni Department satırlara satırlar ve ilgili Course satırlar eklemek Department için kod veya betikler ekleyin.
  • için "Temp" bölümünü veya varsayılan değerini Course.DepartmentIDkullanmayın.

Sonraki öğreticide ilgili veriler yer alır.

Ek kaynaklar