Aracılığıyla paylaş


Öğretici: ASP.NET MVC uygulaması için daha karmaşık bir veri modeli oluşturma

Önceki öğreticilerde üç varlık içeren basit bir veri modeliyle çalıştınız. Bu öğreticide daha fazla varlık ve ilişki ekleyecek ve biçimlendirme, doğrulama ve veritabanı eşleme kurallarını belirterek veri modelini özelleştirebilirsiniz. Bu makalede veri modelini özelleştirmenin iki yolu gösterilmektedir: varlık sınıflarına öznitelikler ekleyerek ve veritabanı bağlam sınıfına kod ekleyerek.

İşiniz bittiğinde varlık sınıfları, aşağıdaki çizimde gösterilen tamamlanmış veri modelini oluşturur:

School_class_diagram

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

  • Veri modelini özelleştirme
  • Öğrenci varlığını güncelleştirme
  • Eğitmen varlığı oluşturma
  • OfficeAssignment varlığı oluşturma
  • Course varlığını değiştirme
  • Departman varlığını oluşturma
  • Kayıt varlığını değiştirme
  • Veritabanı bağlamı için kod ekleme
  • Test verileriyle tohum veritabanı
  • Geçiş ekleme
  • Veritabanını güncelleştirme

Önkoşullar

Veri modelini özelleştirme

Bu bölümde biçimlendirme, doğrulama ve veritabanı eşleme kurallarını belirten öznitelikleri kullanarak veri modelini özelleştirmeyi öğreneceksiniz. Ardından aşağıdaki bölümlerde, oluşturduğunuz sınıflara öznitelikler ekleyerek ve modeldeki kalan varlık türleri için yeni sınıflar oluşturarak tam School veri modelini oluşturacaksınız.

DataType Özniteliği

Öğrenci kayıt tarihleri için, tüm web sayfaları şu anda tarihle birlikte saati görüntüler, ancak bu alan için tek ilgilendiğiniz tarihtir. Veri ek açıklaması özniteliklerini kullanarak, verileri gösteren her görünümde görüntüleme biçimini düzeltecek bir kod değişikliği yapabilirsiniz. Bunun nasıl yapıldığını gösteren bir örnek görmek için sınıfındaki Student özelliğine EnrollmentDate bir öznitelik ekleyeceksiniz.

Models\Student.cs bölümünde, ad alanı için System.ComponentModel.DataAnnotations bir using deyim ekleyin ve aşağıdaki örnekte gösterildiği gibi özelliğine EnrollmentDate ve DisplayFormat öznitelikleri ekleyinDataType:

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

DataType özniteliği, veritabanı iç türünden daha özel bir veri türü belirtmek için kullanılır. Bu durumda, tarih ve saati değil yalnızca tarihi izlemek istiyoruz. DataType Numaralandırması Date, Time, PhoneNumber, Currency, EmailAddress ve daha fazlası 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, DataType.EmailAddress için bir mailto: bağlantı oluşturulabilir ve HTML5'i destekleyen tarayıcılarda DataType.Date için bir tarih seçici sağlanabilir. DataType öznitelikleri, HTML 5 tarayıcılarının anlayabileceği HTML 5 veri- (belirgin veri tiresi) öznitelikleri yayar. DataType öznitelikleri herhangi bir doğrulama sağlamaz.

DataType.Date görüntülenen tarihin biçimini belirtmez. Varsayılan olarak, veri 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 değer düzenleme için bir metin kutusunda görüntülendiğinde belirtilen biçimlendirmenin de uygulanması gerektiğini belirtir. (Bazı alanlarda bunu istemeyebilirsiniz; örneğin para birimi değerleri için, metin kutusunda para birimi simgesinin düzenlenmesini istemeyebilirsiniz.)

DisplayFormat özniteliğini tek başına kullanabilirsiniz, ancak DataType özniteliğini de kullanmak genellikle iyi bir fikirdir. DataType özniteliği, verilerin ekranda nasıl işlendiğinin aksine semantiğini iletir ve ile DisplayFormatelde etmediğiniz 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österebilir.
  • Varsayılan olarak, tarayıcı yerel ayarınıza göre doğru biçimi kullanarak verileri işler.
  • DataType özniteliği, MVC'nin verileri işlemek için doğru alan şablonunu seçmesini sağlayabilir (DisplayFormat dize şablonunu kullanır). Daha fazla bilgi için bkz. Brad Wilson'ın ASP.NET MVC 2 Şablonları. (MVC 2 için yazılmış olsa da, bu makale ASP.NET MVC'nin geçerli sürümü için hala geçerlidir.)

özniteliğini DataType bir tarih alanıyla kullanıyorsanız, alanın Chrome tarayıcılarında doğru şekilde işlenmesini sağlamak için özniteliğini de belirtmeniz DisplayFormat gerekir. Daha fazla bilgi için bu StackOverflow iş parçacığına bakın.

MVC'de diğer tarih biçimlerini işleme hakkında daha fazla bilgi için MVC 5 Giriş: Düzenleme Yöntemlerini ve Düzenleme Görünümünü İnceleme bölümüne gidin ve sayfada "uluslararasılaştırma" araması yapın.

Öğrenci Dizini sayfasını yeniden çalıştırın ve kayıt tarihleri için artık saatlerin görüntülenmediğini fark edin. Modeli kullanan Student tüm görünümler için de aynı şey geçerli olacaktır.

Students_index_page_with_formatted_date

The StringLengthAttribute

Ayrıca öznitelikleri kullanarak veri doğrulama kuralları ve doğrulama hata iletileri belirtebilirsiniz. StringLength özniteliği veritabanındaki uzunluk üst sınırını ayarlar ve ASP.NET MVC için istemci tarafı ve sunucu tarafı doğrulaması sağlar. Bu öznitelikte en düşük dize uzunluğunu da belirtebilirsiniz, ancak en düşük değerin veritabanı şeması üzerinde hiçbir etkisi yoktur.

Kullanıcıların bir ad için 50'den fazla karakter girmediğinden emin olmak istediğinizi varsayalım. Bu sınırlamayı eklemek için, aşağıdaki örnekte gösterildiği gibi ve FirstMidName özelliklerine LastName StringLength öznitelikleri ekleyin:

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

StringLength özniteliği, kullanıcının bir ad için boşluk girmesini engellemez. Girişe kısıtlamalar uygulamak için RegularExpression özniteliğini kullanabilirsiniz. Ö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""'\s-]*$")]

MaxLength özniteliği StringLength özniteliğine benzer işlevler sağlar ancak istemci tarafı doğrulaması sağlamaz.

Uygulamayı çalıştırın ve Öğrenciler sekmesine tıklayın. Aşağıdaki hatayı alıyorsunuz:

Veritabanı oluşturulduktan sonra 'SchoolContext' bağlamını destekleme modeli değişti. Veritabanını (https://go.microsoft.com/fwlink/?LinkId=238269) güncelleştirmek için Code First Migrations kullanmayı göz önünde bulundurun.

Veritabanı modeli, veritabanı şemasında değişiklik gerektirecek şekilde değişmiştir ve Entity Framework bunu algılamıştır. Kullanıcı arabirimini kullanarak veritabanına eklediğiniz verileri kaybetmeden şemayı güncelleştirmek için geçişleri kullanacaksınız. yöntemi tarafından oluşturulan verileri değiştirdiyseniz, yönteminde Seed kullandığınız Seed AddOrUpdate yöntemi nedeniyle bu durum özgün durumuna geri döndürülecektir. (AddOrUpdate , veritabanı terminolojisinden "upsert" işlemine eşdeğerdir.)

Paket Yöneticisi Konsolu'na (PMC) aşağıdaki komutları girin:

add-migration MaxLengthOnNames
update-database

komutu timeStampadd-migration>_MaxLengthOnNames.cs adlı <bir dosya oluşturur. Bu dosya yönteminde Up veritabanını geçerli veri modeliyle eşleşecek şekilde güncelleştirecek kod içerir. Komut update-database bu kodu çalıştırmıştı.

Geçişler dosya adına eklenen zaman damgası, Entity Framework tarafından geçişleri sıralamak için kullanılır. Komutu çalıştırmadan update-database önce birden çok geçiş oluşturabilirsiniz ve ardından tüm geçişler oluşturuldukları sırayla uygulanır.

Oluştur sayfasını çalıştırın ve 50 karakterden uzun bir ad girin. Oluştur'a tıkladığınızda istemci tarafı doğrulaması bir hata iletisi gösterir: LastName alanı en fazla 50 uzunluğunda bir dize olmalıdır.

Sütun Özniteliği

Sınıflarınızın ve özelliklerinizin veritabanına nasıl eşlenmiş olduğunu denetlemek için öznitelikleri de kullanabilirsiniz. Alan ikinci ad da içerebileceğinden, ad alanı için adı kullandığınızı FirstMidName varsayalım. Ancak, veritabanına geçici sorgular yazacak kullanıcılar bu ada alışkın olduğundan veritabanı sütununun olarak adlandırılmasını FirstNameistiyorsunuz. Bu eşlemeyi yapmak için özniteliğini Column kullanabilirsiniz.

Column özniteliği, veritabanı oluşturulduğunda, özelliğine eşleyen tablonun sütununun Student FirstMidName olarak adlandırılacağını FirstNamebelirtir. Başka bir deyişle, kodunuz öğesine başvurduğunda Student.FirstMidNameveriler tablosundan FirstName gelir veya tablonun sütununda Student güncelleştirilir. Sütun adlarını belirtmezseniz, bunlara özellik adıyla aynı ad verilir.

Student.cs dosyasında System.ComponentModel.DataAnnotations.Schema için bir using deyim ekleyin ve aşağıdaki vurgulanan kodda gösterildiği gibi sütun adı özniteliğini FirstMidName özelliğine ekleyin:

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

Column özniteliğinin eklenmesi SchoolContext'i destekleme modelini değiştirir, bu nedenle veritabanıyla eşleşmez. Başka bir geçiş oluşturmak için PMC'ye aşağıdaki komutları girin:

add-migration ColumnFirstName
update-database

Sunucu Gezgini'nde, Öğrenci tablosuna çift tıklayarak Öğrenci tablo tasarımcısını açın.

Aşağıdaki görüntüde, ilk iki geçişi uygulamadan önceki özgün sütun adı gösterilmektedir. olarak değişen FirstMidName FirstNamesütun adına ek olarak, iki ad sütunu uzunluğu 50 karaktere değiştirildi MAX .

İki Öğrenci tablosunun Ad ve Veri Türü arasındaki farkları gösteren iki ekran görüntüsü.

Bu öğreticinin ilerleyen bölümlerinde göreceğiniz gibi Fluent API'sini kullanarak veritabanı eşleme değişiklikleri de yapabilirsiniz.

Not

Aşağıdaki bölümlerde tüm varlık sınıflarını oluşturmayı tamamlamadan önce derlemeyi denerseniz, derleyici hataları alabilirsiniz.

Öğrenci varlığını güncelleştirme

Models\Student.cs bölümünde, daha önce eklediğiniz kodu aşağıdaki kodla değiştirin. Değişiklikler vurgulanır.

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

Gerekli Öznitelik

Gerekli özniteliği, ad özelliklerini gerekli alanlara getirir. Required attribute DateTime, int, double ve float gibi değer türleri için gerekli değildir. Değer türlerine null değer atanamaz, bu nedenle doğal olarak gerekli alanlar olarak kabul edilirler.

ö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.

Görüntüleme Özniteliği

özniteliği, Display metin kutularının resim yazısının her örnekte özellik adı yerine "Ad", "Soyadı", "Tam Ad" ve "Kayıt Tarihi" olması gerektiğini belirtir (sözcükleri bölen bir alanı yoktur).

FullName Hesaplanan Özelliği

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

Eğitmen varlığı oluşturma

Models\Instructor.cs oluşturun ve şablon kodunu aşağıdaki kodla değiştirin:

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

namespace ContosoUniversity.Models
{
    public class 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 virtual ICollection<Course> Courses { get; set; }
        public virtual OfficeAssignment OfficeAssignment { get; set; }
    }
}

ve Instructor varlıklarında birkaç özelliğin Student aynı olduğuna dikkat edin. Bu serinin devamında yer alan Devralma Uygulama öğreticisinde, yedekliliği ortadan kaldırmak için bu kodu yeniden düzenleyeceksiniz.

Bir satıra birden çok öznitelik koyarak eğitmen sınıfını da aşağıdaki gibi yazabilirsiniz:

public class Instructor
{
   public int ID { get; set; }

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

   [Column("FirstName"),Display(Name = "First Name"),StringLength(50, MinimumLength=1)]
   public string FirstMidName { get; set; }

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

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

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

Kurslar ve OfficeAssignment Gezinti Özellikleri

Courses ve OfficeAssignment özellikleri gezinti özellikleridir. Daha önce açıklandığı gibi, genellikle yavaş yükleme adı verilen bir Entity Framework özelliğinden yararlanabilmeleri için sanal olarak tanımlanırlar. Ayrıca, bir gezinti özelliği birden çok varlığı barındırabiliyorsa, türünün ICollection<T> Arabirimini uygulaması gerekir. Örneğin, IList<T> nitelenir ancak Ekle uygulanmadığından IEnumerable<T'yi> IEnumerable<T> nitelemez.

Eğitmen herhangi bir sayıda ders verebilir, bu nedenle Courses varlık koleksiyonu Course olarak tanımlanır.

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

İş kurallarımız, eğitmenin yalnızca en fazla bir ofise sahip olabileceğini belirtir, bu nedenle OfficeAssignment tek OfficeAssignment bir varlık olarak tanımlanır (herhangi bir ofis atanmamış olabilir null ).

public virtual OfficeAssignment OfficeAssignment { get; set; }

OfficeAssignment varlığı oluşturma

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

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

namespace ContosoUniversity.Models
{
    public class OfficeAssignment
    {
        [Key]
        [ForeignKey("Instructor")]
        public int InstructorID { get; set; }
        [StringLength(50)]
        [Display(Name = "Office Location")]
        public string Location { get; set; }

        public virtual Instructor Instructor { get; set; }
    }
}

Değişikliklerinizi kaydeden ve derleyicinin yakalayabileceği kopyalama ve yapıştırma hataları yapmadığınızı doğrulayan projeyi oluşturun.

Anahtar Özniteliği

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 ve bu nedenle birincil anahtarı aynı zamanda varlığın Instructor yabancı anahtarıdır. Ancak adı veya sınıf adı ID adlandırma kuralına uymadığından Entity Framework bu varlığın ID birincil anahtarı olarak otomatik olarak tanıyamazInstructorID. Bu nedenle, Key özniteliği anahtar olarak tanımlamak için kullanılır:

[Key]
[ForeignKey("Instructor")]
public int InstructorID { get; set; }

Varlığın Key kendi birincil anahtarı varsa ancak özelliğine veya IDdeğerinden classnameID farklı bir ad vermek istiyorsanız özniteliğini de kullanabilirsiniz. Varsayılan olarak, sütun tanımlayıcı bir ilişki için olduğundan EF anahtarı veritabanı oluşturulmamış olarak ele alır.

ForeignKey Özniteliği

İki varlık arasında (ve gibi OfficeAssignment Instructor) bire sıfıra veya bire bir ilişki olduğunda, EF ilişkinin hangi sonunun sorumlu ve hangi ucun bağımlı olduğunu çözemez. Bire bir ilişkiler, her sınıfta diğer sınıfa başvuru gezinti özelliğine sahiptir. Yabancı Anahtar Özniteliği , ilişkiyi kurmak için bağımlı sınıfa uygulanabilir. ForeignKey Özniteliğini atlarsanız, geçişi oluşturmaya çalıştığınızda aşağıdaki hatayı alırsınız:

'ContosoUniversity.Models.OfficeAssignment' ve 'ContosoUniversity.Models.Instructor' türleri arasındaki ilişkilendirmenin asıl sonu belirlenemiyor. Bu ilişkilendirmenin asıl ucu, ilişki akıcı API'si veya veri ek açıklamaları kullanılarak açıkça yapılandırılmalıdır.

Öğreticinin ilerleyen bölümlerinde bu ilişkinin akıcı API ile nasıl yapılandırabileceğinizi göreceksiniz.

Eğitmen Gezinti Özelliği

Varlığın Instructor null atanabilir OfficeAssignment bir gezinti özelliği vardır (bir eğitmenin office ataması olmayabilir) ve varlığın OfficeAssignment null atanamaz Instructor bir gezinti özelliği vardır (bir office ataması eğitmen olmadan mevcut olmadığından) InstructorID null atanamaz. Bir Instructor varlığın ilgili OfficeAssignment bir varlığı olduğunda, her varlığın gezinti özelliğinde diğerine bir başvurusu olur.

İlgili bir eğitmen olması gerektiğini belirtmek için Eğitmen gezinti özelliğine bir [Required] öznitelik koyabilirsiniz, ancak InstructorID yabancı anahtarı (aynı zamanda bu tablonun anahtarıdır) null atanamaz olduğundan bunu yapmanız gerekmez.

Course varlığını değiştirme

Models\Course.cs içinde, daha önce eklediğiniz kodu aşağıdaki kodla değiştirin:

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 virtual Department Department { get; set; }
      public virtual ICollection<Enrollment> Enrollments { get; set; }
      public virtual ICollection<Instructor> Instructors { get; set; }
   }
}

Kurs varlığının ilgili Department varlığa işaret eden bir yabancı anahtar özelliği DepartmentID vardır ve bir Department gezinti özelliği vardır. Entity Framework, ilgili bir varlık için gezinti özelliğine sahip olduğunuzda veri modelinize yabancı anahtar özelliği eklemenizi gerektirmez. EF, gerektiğinde veritabanında otomatik olarak yabancı anahtarlar oluşturur. Ancak veri modelinde yabancı anahtarın olması güncelleştirmeleri daha basit ve daha verimli hale getirebilir. Örneğin, düzenlemek üzere bir kurs varlığını getirdiğinizde, Department yüklemezseniz varlık null olur, bu nedenle kurs varlığını güncelleştirdiğinizde önce varlığı getirmeniz Department gerekir. Yabancı anahtar özelliği DepartmentID veri modeline dahil edildiğinde, güncelleştirmeden önce varlığı getirmeniz Department gerekmez.

DatabaseGenerated Özniteliği

özelliğinde CourseID None parametresine sahip DatabaseGenerated özniteliği, birincil anahtar değerlerinin veritabanı tarafından oluşturulmak yerine kullanıcı tarafından sağlandığını belirtir.

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

Varsayılan olarak, Entity Framework birincil anahtar değerlerinin veritabanı tarafından oluşturulduğunu varsayar. Çoğu senaryoda istediğiniz budur. Ancak varlıklar için, bir bölüm için Course 1000 serisi, başka bir bölüm için 2000 serisi gibi kullanıcı tarafından belirtilen bir kurs numarası kullanırsınız.

Yabancı Anahtar ve Gezinti Özellikleri

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

  • Kurs bir bölüme atandığından, yukarıda belirtilen nedenlerle bir DepartmentID yabancı anahtar ve Department gezinti özelliği vardır.

    public int DepartmentID { get; set; }
    public virtual Department Department { get; set; }
    
  • Bir kursta kayıtlı herhangi bir sayıda öğrenci olabilir, bu nedenle Enrollments gezinti özelliği bir koleksiyondur:

    public virtual ICollection<Enrollment> Enrollments { get; set; }
    
  • Bir kurs birden çok eğitmen tarafından öğretilebilir, bu nedenle Instructors gezinti özelliği bir koleksiyondur:

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

Departman varlığını oluşturma

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

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 virtual Instructor Administrator { get; set; }
      public virtual ICollection<Course> Courses { get; set; }
   }
}

Sütun Özniteliği

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

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

Varlık Çerçevesi genellikle özellik için tanımladığınız CLR türüne göre uygun SQL Server veri türünü seçtiğinden sütun eşlemesi genellikle gerekli değildir. CLR decimal türü bir SQL Server decimal türüyle eşler. Ancak bu durumda, sütunun para birimi tutarlarını tutacağını ve para veri türünün bunun için daha uygun olduğunu biliyorsunuz. CLR veri türleri ve BUNLARıN SQL Server veri türleriyle eşleşmesi hakkında daha fazla bilgi için bkz . Entity FrameworkTypes için SqlClient.

Yabancı Anahtar ve Gezinti Özellikleri

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

  • Bir bölümün yöneticisi olabilir veya olmayabilir ve yönetici her zaman eğitmendir. Bu nedenle özellik, varlığın InstructorID yabancı anahtarı Instructor olarak eklenir ve özelliği null atanabilir olarak işaretlemek için tür gösteriminden sonra int bir soru işareti eklenir. Gezinti özelliği adlandırılmıştır Administrator ancak bir Instructor varlığı barındırmaktadır:

    public int? InstructorID { get; set; }
    public virtual Instructor Administrator { get; set; }
    
  • Bir bölümün birçok kursu olabilir, bu nedenle bir Courses gezinti özelliği vardır:

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

    Not

    Kural gereği, Entity Framework null atanamayan yabancı anahtarlar ve çoka çok ilişkiler için art arda silmeyi etkinleştirir. Bu, döngüsel art arda silme kurallarına neden olabilir ve bu da geçiş eklemeye çalıştığınızda özel duruma neden olur. Örneğin, özelliğini null atanabilir olarak tanımlamadıysanız Department.InstructorID şu özel durum iletisini alırsınız: "Bilgi ilişkisi izin verilmeyen döngüsel başvuruya neden olur." İş kurallarınızda özelliğin null atanamaz olması gerekiyorsa InstructorID , ilişkide art arda silmeyi devre dışı bırakmak için aşağıdaki fluent API deyimini kullanmanız gerekir:

modelBuilder.Entity().HasRequired(d => d.Administrator).WithMany().WillCascadeOnDelete(false);

Kayıt varlığını değiştirme

Models\Enrollment.cs içinde, daha önce eklediğiniz kodu aşağıdaki kodla değiştirin

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 virtual Course Course { get; set; }
        public virtual Student Student { get; set; }
    }
}

Yabancı Anahtar ve Gezinti Özellikleri

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

  • Kayıt kaydı tek bir kurs içindir, bu nedenle yabancı anahtar özelliği ve Course gezinti özelliği vardırCourseID:

    public int CourseID { get; set; }
    public virtual Course Course { get; set; }
    
  • Kayıt kaydı tek bir öğrenciye yöneliktir, bu nedenle yabancı anahtar özelliği ve Student gezinti özelliği vardırStudentID:

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

Çoka Çok İlişkiler

ve varlıkları arasında Student çoka çok ilişkisi vardır ve Enrollment varlık, veritabanında yükü olan çoka çok birleştirme tablosu işlevi Course görür. Bu, Enrollment tablonun birleştirilen tablolar için yabancı anahtarların (bu örnekte birincil anahtar ve Grade özellik) yanı sıra ek veriler içerdiği anlamına gelir.

Aşağıdaki çizimde bu ilişkilerin bir varlık diyagramında nasıl göründüğü gösterilmektedir. (Bu diyagram, Entity Framework Power Tools; diyagramı oluşturmak öğreticinin bir parçası değildir, yalnızca burada çizim olarak kullanılır.)

Öğrenci Course_many many_relationship

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

Enrollment Tabloda not bilgileri yoksa, yalnızca ve iki yabancı anahtarı CourseID StudentIDiçermesi gerekir. Bu durumda, veritabanında yükü (veya saf birleştirme tablosu) olmayan çoka çok birleştirme tablosuna karşılık gelir ve bunun için bir model sınıfı oluşturmanız gerekmez. Instructor ve Course varlıkları bu tür çoka çok ilişkisine sahiptir ve gördüğünüz gibi aralarında varlık sınıfı yoktur:

Eğitmenden Course_many many_relationship

Ancak, aşağıdaki veritabanı diyagramında gösterildiği gibi veritabanında bir birleştirme tablosu gereklidir:

Eğitmenden Course_many many_relationship_tables

Entity Framework tabloyu otomatik olarak oluşturur CourseInstructor ve ve gezinti özelliklerini okuyup güncelleştirerek tabloyu dolaylı olarak okur ve güncelleştirirsiniz Instructor.Courses Course.Instructors .

Varlık ilişkisi diyagramı

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

School_data_model_diagram

Çoka çok ilişki çizgilerinin (* - *) ve bire çok ilişki çizgilerinin (1 - *) yanı sıra, burada ve OfficeAssignment varlıkları arasındaki bire sıfır veya bir ilişki çizgisini (1 - 0..1) ve Eğitmen ile Departman varlıkları arasındaki Instructor sıfır veya bire çok ilişki çizgisini (0..1 - *) görebilirsiniz.

Veritabanı bağlamı için kod ekleme

Ardından yeni varlıkları sınıfına SchoolContext ekleyecek ve akıcı API çağrılarını kullanarak eşlemenin bazılarını özelleştireceksiniz. Aşağıdaki örnekte olduğu gibi genellikle bir dizi yöntem çağrısını tek bir deyimde dizeleyerek kullanıldığından API "akıcıdır":

modelBuilder.Entity<Course>()
     .HasMany(c => c.Instructors).WithMany(i => i.Courses)
     .Map(t => t.MapLeftKey("CourseID")
         .MapRightKey("InstructorID")
         .ToTable("CourseInstructor"));

Bu öğreticide, akıcı API'yi yalnızca özniteliklerle gerçekleştiremezseniz veritabanı eşlemesi için kullanacaksınız. Ancak, öznitelikleri kullanarak yapabileceğiniz biçimlendirme, doğrulama ve eşleme kurallarının çoğunu belirtmek için akıcı API'yi de kullanabilirsiniz. gibi MinimumLength bazı öznitelikler akıcı API ile uygulanamaz. Daha önce belirtildiği gibi şemayı MinimumLength değiştirmez, yalnızca istemci ve sunucu tarafı 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. İsterseniz öznitelikleri ve akıcı API'yi karıştırabilirsiniz ve yalnızca akıcı API kullanılarak yapılabilecek birkaç özelleştirme vardır, ancak genel olarak önerilen yöntem bu iki yaklaşımdan birini seçmek ve bunu mümkün olduğunca tutarlı bir şekilde kullanmaktır.

Yeni varlıkları veri modeline eklemek ve öznitelikleri kullanarak yapmadığınız veritabanı eşlemesini gerçekleştirmek için DAL\SchoolContext.cs içindeki kodu aşağıdaki kodla değiştirin:

using ContosoUniversity.Models;
using System.Data.Entity;
using System.Data.Entity.ModelConfiguration.Conventions;

namespace ContosoUniversity.DAL
{
   public class SchoolContext : DbContext
   {
      public DbSet<Course> Courses { get; set; }
      public DbSet<Department> Departments { get; set; }
      public DbSet<Enrollment> Enrollments { get; set; }
      public DbSet<Instructor> Instructors { get; set; }
      public DbSet<Student> Students { get; set; }
      public DbSet<OfficeAssignment> OfficeAssignments { get; set; }

      protected override void OnModelCreating(DbModelBuilder modelBuilder)
      {
         modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();

         modelBuilder.Entity<Course>()
             .HasMany(c => c.Instructors).WithMany(i => i.Courses)
             .Map(t => t.MapLeftKey("CourseID")
                 .MapRightKey("InstructorID")
                 .ToTable("CourseInstructor"));
      }
   }
}

OnModelCreating yöntemindeki yeni deyim, çoka çok birleştirme tablosunu yapılandırır:

  • ve Course varlıkları arasındaki Instructor çoka çok ilişkisi için kod birleştirme tablosunun tablo ve sütun adlarını belirtir. Code First, bu kod olmadan çoka çok ilişkisini sizin için yapılandırabilir, ancak çağırmıyorsanız sütun için InstructorID gibi InstructorInstructorID varsayılan adları alırsınız.

    modelBuilder.Entity<Course>()
        .HasMany(c => c.Instructors).WithMany(i => i.Courses)
        .Map(t => t.MapLeftKey("CourseID")
            .MapRightKey("InstructorID")
            .ToTable("CourseInstructor"));
    

Aşağıdaki kod, ve OfficeAssignment varlıkları arasındaki Instructor ilişkiyi belirtmek için öznitelikler yerine akıcı API'yi nasıl kullanabileceğinize ilişkin bir örnek sağlar:

modelBuilder.Entity<Instructor>()
    .HasOptional(p => p.OfficeAssignment).WithRequired(p => p.Instructor);

"Akıcı API" deyimlerinin arka planda ne yaptığı hakkında bilgi için Fluent API blog gönderisine bakın.

Test verileriyle tohum veritabanı

Oluşturduğunuz yeni varlıklar için tohum verileri sağlamak için Migrations\Configuration.cs dosyasındaki kodu aşağıdaki kodla değiştirin.

namespace ContosoUniversity.Migrations
{
    using ContosoUniversity.Models;
    using ContosoUniversity.DAL;
    using System;
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;
    
    internal sealed class Configuration : DbMigrationsConfiguration<SchoolContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(SchoolContext context)
        {
            var students = new List<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") }
            };

            students.ForEach(s => context.Students.AddOrUpdate(p => p.LastName, s));
            context.SaveChanges();

            var instructors = new List<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") }
            };
            instructors.ForEach(s => context.Instructors.AddOrUpdate(p => p.LastName, s));
            context.SaveChanges();

            var departments = new List<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 }
            };
            departments.ForEach(s => context.Departments.AddOrUpdate(p => p.Name, s));
            context.SaveChanges();

            var courses = new List<Course>
            {
                new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3,
                  DepartmentID = departments.Single( s => s.Name == "Engineering").DepartmentID,
                  Instructors = new List<Instructor>() 
                },
                new Course {CourseID = 4022, Title = "Microeconomics", Credits = 3,
                  DepartmentID = departments.Single( s => s.Name == "Economics").DepartmentID,
                  Instructors = new List<Instructor>() 
                },
                new Course {CourseID = 4041, Title = "Macroeconomics", Credits = 3,
                  DepartmentID = departments.Single( s => s.Name == "Economics").DepartmentID,
                  Instructors = new List<Instructor>() 
                },
                new Course {CourseID = 1045, Title = "Calculus",       Credits = 4,
                  DepartmentID = departments.Single( s => s.Name == "Mathematics").DepartmentID,
                  Instructors = new List<Instructor>() 
                },
                new Course {CourseID = 3141, Title = "Trigonometry",   Credits = 4,
                  DepartmentID = departments.Single( s => s.Name == "Mathematics").DepartmentID,
                  Instructors = new List<Instructor>() 
                },
                new Course {CourseID = 2021, Title = "Composition",    Credits = 3,
                  DepartmentID = departments.Single( s => s.Name == "English").DepartmentID,
                  Instructors = new List<Instructor>() 
                },
                new Course {CourseID = 2042, Title = "Literature",     Credits = 4,
                  DepartmentID = departments.Single( s => s.Name == "English").DepartmentID,
                  Instructors = new List<Instructor>() 
                },
            };
            courses.ForEach(s => context.Courses.AddOrUpdate(p => p.CourseID, s));
            context.SaveChanges();

            var officeAssignments = new List<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" },
            };
            officeAssignments.ForEach(s => context.OfficeAssignments.AddOrUpdate(p => p.InstructorID, s));
            context.SaveChanges();

            AddOrUpdateInstructor(context, "Chemistry", "Kapoor");
            AddOrUpdateInstructor(context, "Chemistry", "Harui");
            AddOrUpdateInstructor(context, "Microeconomics", "Zheng");
            AddOrUpdateInstructor(context, "Macroeconomics", "Zheng");

            AddOrUpdateInstructor(context, "Calculus", "Fakhouri");
            AddOrUpdateInstructor(context, "Trigonometry", "Harui");
            AddOrUpdateInstructor(context, "Composition", "Abercrombie");
            AddOrUpdateInstructor(context, "Literature", "Abercrombie");

            context.SaveChanges();

            var enrollments = new List<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();
        }

        void AddOrUpdateInstructor(SchoolContext context, string courseTitle, string instructorName)
        {
            var crs = context.Courses.SingleOrDefault(c => c.Title == courseTitle);
            var inst = crs.Instructors.SingleOrDefault(i => i.LastName == instructorName);
            if (inst == null)
                crs.Instructors.Add(context.Instructors.Single(i => i.LastName == instructorName));
        }
    }
}

İlk öğreticide gördüğünüz gibi, bu kodun çoğu yalnızca yeni varlık nesnelerini güncelleştirir veya oluşturur ve test için gereken örnek verileri özelliklere yükler. Ancak varlıkla çoka çok ilişkisi olan varlığın nasıl Course işlendiğine Instructor dikkat edin:

var courses = new List<Course>
{
    new Course {CourseID = 1050, Title = "Chemistry",      Credits = 3,
      DepartmentID = departments.Single( s => s.Name == "Engineering").DepartmentID,
      Instructors = new List<Instructor>() 
    },
    ...
};
courses.ForEach(s => context.Courses.AddOrUpdate(p => p.CourseID, s));
context.SaveChanges();

Bir Course nesne oluşturduğunuzda, gezinti özelliğini kodunu Instructors = new List<Instructor>()kullanarak boş bir koleksiyon olarak başlatırsınızInstructors. Bu, yöntemini kullanarak bununla Course ilgili varlıkların eklenmesini Instructor Instructors.Add mümkün kılar. Boş bir liste oluşturmadıysanız, özelliği null olacağından ve bir Add yöntemi olmayacağından Instructors bu ilişkileri ekleyemezsiniz. Liste başlatmayı oluşturucuya da ekleyebilirsiniz.

Geçiş ekleme

PMC'den komutunu girin add-migration (komutu henüz yapmayın update-database ):

add-Migration ComplexDataModel

Komutu bu noktada çalıştırmaya update-database çalıştıysanız (henüz uygulamayın), aşağıdaki hatayı alırsınız:

ALTER TABLE deyimi FOREIGN KEY kısıtlaması "FK_dbo. Course_dbo. Department_DepartmentID". Çakışma "ContosoUniversity" veritabanında, "dbo" tablosunda oluştu. Department", 'DepartmentID' sütunu.

Bazen geçişleri mevcut verilerle yürütürken, yabancı anahtar kısıtlamalarını karşılamak için veritabanına saplama verileri eklemeniz gerekir ve şimdi yapmanız gereken budur. ComplexDataModel Up yönteminde oluşturulan kod, tabloya Course null atanamaz DepartmentID bir yabancı anahtar ekler. Kod çalıştırıldığında tabloda zaten satırlar Course bulunduğundan, AddColumn SQL Server sütuna null olmayan hangi değeri koyacağını bilmediğinden işlem başarısız olur. Bu nedenle, kodu yeni sütuna varsayılan bir değer verecek şekilde değiştirmeniz ve varsayılan departman görevi görmesi için "Temp" adlı bir saplama departmanı oluşturmanız gerekir. Sonuç olarak, Course mevcut satırların tümü yöntem çalıştırıldıktan sonra "Geçici" bölümle Up ilişkilendirilecektir. Bunları yöntemindeki doğru departmanlarla Seed ilişkilendirebilirsiniz.

Zaman damgasını<>_ComplexDataModel.cs dosyasını düzenleyin, DepartmentID sütununu Course tablosuna ekleyen kod satırını açıklama satırı yapın ve aşağıdaki vurgulanmış kodu ekleyin (açıklama satırı da vurgulanır):

CreateTable(
        "dbo.CourseInstructor",
        c => new
            {
                CourseID = c.Int(nullable: false),
                InstructorID = c.Int(nullable: false),
            })
        .PrimaryKey(t => new { t.CourseID, t.InstructorID })
        .ForeignKey("dbo.Course", t => t.CourseID, cascadeDelete: true)
        .ForeignKey("dbo.Instructor", t => t.InstructorID, cascadeDelete: true)
        .Index(t => t.CourseID)
        .Index(t => t.InstructorID);

    // Create  a department for course to point to.
    Sql("INSERT INTO dbo.Department (Name, Budget, StartDate) VALUES ('Temp', 0.00, GETDATE())");
    //  default value for FK points to department created above.
    AddColumn("dbo.Course", "DepartmentID", c => c.Int(nullable: false, defaultValue: 1)); 
    //AddColumn("dbo.Course", "DepartmentID", c => c.Int(nullable: false));

    AlterColumn("dbo.Course", "Title", c => c.String(maxLength: 50));

Seed Yöntemi çalıştırıldığında tabloya Department satır ekler ve var olan Course satırları bu yeni Department satırlarla ilişkilendirir. Kullanıcı arabirimine hiç kurs eklemediyseniz artık "Geçici" bölüme veya sütundaki varsayılan değere Course.DepartmentID ihtiyacınız kalmaz. Birinin uygulamayı kullanarak kurs eklemiş olma olasılığına izin vermek için, varsayılan değeri sütundan kaldırıp "Temp" bölümünü silmeden önce tüm Course satırların (yalnızca yöntemin önceki çalıştırmaları Seed tarafından eklenenler değil) geçerli DepartmentID değerlere sahip olduğundan emin olmak için yöntem kodunu da güncelleştirmek Seed istersiniz.

Veritabanını güncelleştirme

Zaman damgası>_ComplexDataModel.cs dosyasını düzenlemeyi <bitirdikten sonra, geçişi yürütmek için PMC'ye komutunu girinupdate-database.

update-database

Not

Verileri geçirirken ve şema değişiklikleri yaparken başka hatalar almak mümkündür. Çözemediğiniz geçiş hataları alırsanız, bağlantı dizesi veritabanı adını değiştirebilir veya veritabanını silebilirsiniz. En basit yaklaşım, Web.config dosyasında veritabanını yeniden adlandırmaktır . Aşağıdaki örnekte adın CU_Test olarak değiştirildiği gösterilmektedir:

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

Yeni bir veritabanıyla, geçirecek veri yoktur ve komutun update-database hatasız tamamlanma olasılığı çok daha yüksektir. Veritabanını silme yönergeleri için bkz . Visual Studio 2012'den Veritabanı Bırakma.

Bu başarısız olursa, deneyebileceğiniz başka bir şey de PMC'ye aşağıdaki komutu girerek veritabanını yeniden başlatmaktır:

update-database -TargetMigration:0

Daha önce yaptığınız gibi veritabanını Sunucu Gezgini'nde açın ve tüm tabloların oluşturulduğunu görmek için Tablolar düğümünü genişletin. (Hala Sunucu Gezgini daha önceki bir zamanda açıldığında Yenile düğmesine tıklayın.)

Sunucu Gezgini penceresini gösteren ekran görüntüsü. Okul Bağlamı altındaki Tablolar klasörü açık.

Tablo için CourseInstructor model sınıfı oluşturmadınız. Daha önce açıklandığı gibi, bu ve Course varlıkları arasındaki Instructor çoka çok ilişkisi için bir birleştirme tablosudur.

Tabloya sağ tıklayın ve gezinti özelliğine CourseInstructor eklediğiniz varlıkların Instructor bir sonucu olarak içinde veri olduğunu doğrulamak için Course.Instructors Tablo Verilerini Göster'i seçin.

Table_data_in_CourseInstructor_table

Kodu alma

Tamamlanan Projeyi İndir

Ek kaynaklar

Diğer Entity Framework kaynaklarına bağlantılar ASP.NET Veri Erişimi - Önerilen Kaynaklar'da bulunabilir.

Sonraki adımlar

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

  • Veri modelini özelleştirme
  • Güncelleştirilmiş Öğrenci varlığı
  • Eğitmen varlığı oluşturuldu
  • Oluşturulan OfficeAssignment varlığı
  • Kurs varlığı değiştirildi
  • Departman varlığı oluşturuldu
  • Kayıt varlığı değiştirildi
  • Veritabanı bağlamı için kod eklendi
  • Test verileriyle dağıtılmış veritabanı
  • Geçiş eklendi
  • Veritabanı güncelleştirildi

Entity Framework'ün gezinti özelliklerine yüklediğini ilgili verileri okumayı ve görüntülemeyi öğrenmek için sonraki makaleye ilerleyin.