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:
Dataedo ile aşağıdaki veritabanı diyagramı yapılmıştır:
Dataedo ile veritabanı diyagramı oluşturmak için:
- Uygulamayı Azure'a dağıtma
- Dataedo'yu bilgisayarınıza indirin ve yükleyin.
- 5 dakika içinde Azure SQL Veritabanı için belge oluşturma yönergelerini izleyin
Ö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ığı
Models/Student.cs
kodunu şu 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, PhoneNumber, 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. Örneğin:
- Bağlantı
mailto:
içinDataType.EmailAddress
otomatik 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 DisplayFormat
bulunmayan 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.
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 FirstName
Student
. özniteliğinin Column
eklenmesi, modelinin desteklenmesinde SchoolContext
değ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
, int
ve 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 resim yazısının "Ad", "Soyadı", "Tam Ad" ve "Kayıt Tarihi" olması gerektiğini belirtir. Varsayılan açıklamalı alt yazılarda 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ı FirstName
bir sütunu bulmayı beklemesine neden olur, ancak veritabanındaki sütun adı hala FirstMidName
olur.
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:
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ştirildiFirstMidName
FirstName
.
- 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.
Not
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)]
Gezinti özellikleri
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ığı
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 ID
dışı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 OfficeAssignment
InstructorID
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 int
gezinti ö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 DepartmentID
vardı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 DepartmentID
dahil 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 FKInstructor
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.
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ün Enrollment
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.)
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 CourseID
StudentID
gerekir. 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.cs
kodu 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:
- Veritabanını bırakın ve yeniden oluşturun. SQLite kullanırken 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
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:
Student varlığı
Models/Student.cs
kodunu şu 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, PhoneNumber, 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. Örneğin:
- Bağlantı
mailto:
içinDataType.EmailAddress
otomatik 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 DisplayFormat
bulunmayan 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.
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 FirstName
Student
. özniteliğinin Column
eklenmesi, modelinin desteklenmesinde SchoolContext
değ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
, int
ve 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 resim yazısının "Ad", "Soyadı", "Tam Ad" ve "Kayıt Tarihi" olması gerektiğini belirtir. Varsayılan açıklamalı alt yazılarda 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ı FirstName
bir sütunu bulmayı beklemesine neden olur, ancak veritabanındaki sütun adı hala FirstMidName
olur.
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:
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ştirildiFirstMidName
FirstName
.
- 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.
Not
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<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)]
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; }
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ığı
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 OfficeAssignment
InstructorID
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 int
gezinti ö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<CourseAssignment> CourseAssignments { get; set; }
}
}
Varlığın Course
yabancı anahtar (FK) özelliği DepartmentID
vardı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 DepartmentID
dahil 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; }
CourseAssignment
daha sonra açıklanacaktır.
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 FKInstructor
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.
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.)
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ığı
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.
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 CourseInstructor
edilir.
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
CourseAssignment
bir 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.
Yukarıdaki diyagramda aşağıdakiler gösterilir:
- Birkaç bire çok ilişki çizgisi (1 - *).
- ve
OfficeAssignment
varlıkları arasındakiInstructor
bire sıfır veya bir ilişki çizgisi (1 -0,.1). - ve
Department
varlıkları arasındakiInstructor
sıfır veya bire çok ilişki çizgisi (0..1 - *).
Veritabanının tohumunu oluşturma
içindeki Data/DbInitializer.cs
kodu 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.
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.
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 Course
satı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 ekleyinCourse
.
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 ilgiliCourse
satırlar eklemekDepartment
için kod veya betikler ekleyin. - için "Temp" bölümünü veya varsayılan değerini
Course.DepartmentID
kullanmayı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:
Çö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, PhoneNumber, 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. Örneğin:
- Bağlantı
mailto:
içinDataType.EmailAddress
otomatik 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 DisplayFormat
bulunmayan 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.
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.
SQL Server Nesne Gezgini'de (SSOX), Student tablosuna çift tıklayarak Student tablo tasarımcısını açın.
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 SchoolContext
değ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:
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 FirstMidName
FirstName
.
Not
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
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
, double
vb.) 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 resim yazısının "Ad", "Soyadı", "Tam Ad" ve "Kayıt Tarihi" olması gerektiğini belirtir. Varsayılan açıklamalı alt yazılarda 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
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
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 InstructorID
OfficeAssignment
:
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 OfficeAssignment
Instructor
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
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 DepartmentID
vardı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 DepartmentID
dahil 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; }
CourseAssignment
daha sonra açıklanacaktır.
Departman varlığını oluşturma
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 FKInstructor
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.
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.)
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ığı
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
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 CourseInstructor
edilir.
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
CourseAssignment
bir 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.cs
ekleyin:
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.
Yukarıdaki diyagramda aşağıdakiler gösterilir:
- Birkaç bire çok ilişki çizgisi (1 - *).
- ve
OfficeAssignment
varlıkları arasındakiInstructor
bire sıfır veya bir ilişki çizgisi (1 -0,.1). - ve
Department
varlıkları arasındakiInstructor
sıfır veya bire çok ilişki çizgisi (0..1 - *).
Test Verileri ile veritabanı tohumu oluşturma
içindeki Data/DbInitializer.cs
kodu 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.
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.
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 Course
satı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 ekleyinCourse
.
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.
Bir üretim uygulaması şu şekilde olur:
- Yeni
Department
satırlara satırlar ve ilgiliCourse
satırlar eklemekDepartment
için kod veya betikler ekleyin. - için "Temp" bölümünü veya varsayılan değerini
Course.DepartmentID
kullanmayın.
Sonraki öğreticide ilgili veriler yer alır.
Ek kaynaklar
ASP.NET Core