Aracılığıyla paylaş


Kod İlk Veri Ek Açıklamaları

Dekont

EF4.1 Yalnızca Devamı - Bu sayfada ele alınan özellikler, API'ler vb. Entity Framework 4.1'de sunulmuştur. Önceki bir sürümü kullanıyorsanız, bu bilgilerin bazıları veya tümü geçerli değildir.

Bu sayfadaki içerik, Julie Lerman (<http://thedatafarm.com> ) tarafından yazılan bir makaleden uyarlanmıştır.

Entity Framework Code First, EF'in sorgulama, değişiklik izleme ve güncelleştirme işlevlerini gerçekleştirmek için kullandığı modeli temsil etmek için kendi etki alanı sınıflarınızı kullanmanıza olanak tanır. Code First, 'yapılandırma üzerinde kural' olarak adlandırılan bir programlama düzeninden yararlanır. Code First, sınıflarınızın Entity Framework kurallarına uygun olduğunu varsayar ve bu durumda işinin nasıl gerçekleştirileceğine otomatik olarak çalışır. Ancak, sınıflarınız bu kurallara uymuyorsa, EF'ye gerekli bilgileri sağlamak için sınıflarınıza yapılandırmalar ekleyebilirsiniz.

Code First, bu yapılandırmaları sınıflarınıza eklemek için size iki yol sağlar. Bunlardan biri DataAnnotations adlı basit öznitelikleri, ikincisi ise kodda yapılandırmaları kesin olarak açıklamanızı sağlayan Code First Fluent API'sini kullanmaktır.

Bu makale, sınıflarınızı yapılandırmak için DataAnnotations (System.ComponentModel.DataAnnotations ad alanında) kullanımına odaklanacak ve en sık gereken yapılandırmaları vurgulayacaktır. DataAnnotations, bu uygulamaların istemci tarafı doğrulamaları için aynı ek açıklamalardan yararlanmasını sağlayan ASP.NET MVC gibi bir dizi .NET uygulaması tarafından da anlaşılır.

Model

Basit bir sınıf çifti ile Code First DataAnnotations'ı göstereceğim: Blog ve Gönderi.

    public class Blog
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string BloggerName { get; set;}
        public virtual ICollection<Post> Posts { get; set; }
    }

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public DateTime DateCreated { get; set; }
        public string Content { get; set; }
        public int BlogId { get; set; }
        public ICollection<Comment> Comments { get; set; }
    }

Oldukları gibi, Blog ve Post sınıfları kod ilk kuralını rahatça izler ve EF uyumluluğu sağlamak için herhangi bir ayarlama gerektirmez. Ancak ek açıklamaları kullanarak EF'e sınıflar ve bunların eşlendiği veritabanı hakkında daha fazla bilgi sağlayabilirsiniz.

 

Tuş

Entity Framework, her varlığın varlık izleme için kullanılan bir anahtar değerine sahip olmasına dayanır. Code First kuralından biri örtük anahtar özellikleridir; Code First, "Id" adlı bir özelliği veya "BlogId" gibi sınıf adı ve "Kimlik" birleşimini arar. Bu özellik veritabanındaki birincil anahtar sütununa eşlenir.

Blog ve Post sınıflarının her ikisi de bu kuralı izler. Ya yapmasalardı? Blog bunun yerine PrimaryTrackingKey veya hatta foo adını kullandıysa ne olur? Kod önce bu kuralla eşleşen bir özellik bulamazsa, Entity Framework'ün bir anahtar özelliğine sahip olmanız gerektiği gereksinimi nedeniyle bir özel durum oluşturur. EntityKey olarak hangi özelliğin kullanılacağını belirtmek için anahtar ek açıklamasını kullanabilirsiniz.

    public class Blog
    {
        [Key]
        public int PrimaryTrackingKey { get; set; }
        public string Title { get; set; }
        public string BloggerName { get; set;}
        public virtual ICollection<Post> Posts { get; set; }
    }

Kod öncesinin veritabanı oluşturma özelliğini kullanıyorsanız, Blog tablosunda primaryTrackingKey adlı birincil anahtar sütunu bulunur ve bu sütun varsayılan olarak Kimlik olarak da tanımlanır.

Blog table with primary key

Bileşik anahtarlar

Entity Framework, birden fazla özellikten oluşan birincil anahtarlar olan bileşik anahtarları destekler. Örneğin, birincil anahtarı PassportNumber ve IssuingCountry'nin birleşimi olan bir Passport sınıfınız olabilir.

    public class Passport
    {
        [Key]
        public int PassportNumber { get; set; }
        [Key]
        public string IssuingCountry { get; set; }
        public DateTime Issued { get; set; }
        public DateTime Expires { get; set; }
    }

EF modelinizde yukarıdaki sınıfı kullanmayı denemeniz bir InvalidOperationExceptionile sonuçlanır:

'Passport' türü için bileşik birincil anahtar sıralaması belirlenemiyor. Bileşik birincil anahtarlar için bir sıra belirtmek üzere ColumnAttribute veya HasKey yöntemini kullanın.

Bileşik anahtarları kullanmak için Entity Framework, anahtar özellikleri için bir sıra tanımlamanızı gerektirir. Bir sıra belirtmek için Sütun ek açıklamasını kullanarak bunu yapabilirsiniz.

Dekont

Sıra değeri görelidir (dizin tabanlı değil). Bu nedenle tüm değerler kullanılabilir. Örneğin, 1 ve 2 yerine 100 ve 200 kabul edilebilir.

    public class Passport
    {
        [Key]
        [Column(Order=1)]
        public int PassportNumber { get; set; }
        [Key]
        [Column(Order = 2)]
        public string IssuingCountry { get; set; }
        public DateTime Issued { get; set; }
        public DateTime Expires { get; set; }
    }

Bileşik yabancı anahtarlara sahip varlıklarınız varsa, ilgili birincil anahtar özellikleri için kullandığınız sütun sıralamasını belirtmeniz gerekir.

Yalnızca yabancı anahtar özelliklerindeki göreli sıralamanın aynı olması gerekir; Order'a atanan değerlerin tam olarak eşleşmesi gerekmez. Örneğin, aşağıdaki sınıfta 1 ve 2 yerine 3 ve 4 kullanılabilir.

    public class PassportStamp
    {
        [Key]
        public int StampId { get; set; }
        public DateTime Stamped { get; set; }
        public string StampingCountry { get; set; }

        [ForeignKey("Passport")]
        [Column(Order = 1)]
        public int PassportNumber { get; set; }

        [ForeignKey("Passport")]
        [Column(Order = 2)]
        public string IssuingCountry { get; set; }

        public Passport Passport { get; set; }
    }

Zorunlu

Ek açıklama EF'ye Required belirli bir özelliğin gerekli olduğunu bildirir.

Title özelliğine Gerekli eklenmesi, özelliğin içinde veri olduğundan emin olmak için EF'yi (ve MVC'yi) zorlar.

    [Required]
    public string Title { get; set; }

Uygulamada ek kod veya işaretleme değişikliği olmadığında, MVC uygulaması özellik ve ek açıklama adlarını kullanarak dinamik olarak bir ileti oluşturarak bile istemci tarafı doğrulaması gerçekleştirir.

Create page with Title is required error

Gerekli özniteliği, eşlenen özelliği null atanamaz hale getirerek oluşturulan veritabanını da etkiler. Başlık alanının "null değil" olarak değiştiğine dikkat edin.

Dekont

Bazı durumlarda, özellik gerekli olsa bile veritabanındaki sütunun null atanamaz olması mümkün olmayabilir. Örneğin, birden çok tür için TPH devralma stratejisi verileri kullanılırken tek bir tabloda depolanır. Türetilmiş bir tür gerekli bir özellik içeriyorsa, hiyerarşideki tüm türler bu özelliğe sahip olmadığından sütun null atanamaz hale getirilemez.

 

Blogs table

 

MaxLength ve MinLength

MaxLength ve MinLength öznitelikleri, aynı ile Requiredyaptığınız gibi ek özellik doğrulamaları belirtmenize olanak sağlar.

Burada, uzunluk gereksinimleri olan BloggerName yer alır. Örnekte özniteliklerin nasıl birleştirildiği de gösterilmektedir.

    [MaxLength(10),MinLength(5)]
    public string BloggerName { get; set; }

MaxLength ek açıklaması, özelliğin uzunluğunu 10 olarak ayarlayarak veritabanını etkiler.

Blogs table showing max length on BloggerName column

MVC istemci tarafı ek açıklaması ve EF 4.1 sunucu tarafı ek açıklaması, yine dinamik olarak bir hata iletisi oluşturarak bu doğrulamayı kabul edecektir: "BloggerName alanı en fazla '10' uzunluğunda bir dize veya dizi türü olmalıdır." Bu mesaj biraz uzun. Birçok ek açıklama, ErrorMessage özniteliğiyle bir hata iletisi belirtmenize olanak sağlar.

    [MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
    public string BloggerName { get; set; }

ErrorMessage'i Gerekli ek açıklamasında da belirtebilirsiniz.

Create page with custom error message

 

Eşlenmemiş

Kod ilk kuralı, desteklenen bir veri türündeki her özelliğin veritabanında temsil edilir. Ancak uygulamalarınızda her zaman böyle bir durum söz konusu değildir. Örneğin, Blog sınıfında Title ve BloggerName alanlarını temel alan bir kod oluşturan bir özelliğiniz olabilir. Bu özellik dinamik olarak oluşturulabilir ve depolanması gerekmez. Bu BlogCode özelliği gibi, veritabanına eşlenmeyen tüm özellikleri NotMapped ek açıklamasıyla işaretleyebilirsiniz.

    [NotMapped]
    public string BlogCode
    {
        get
        {
            return Title.Substring(0, 1) + ":" + BloggerName.Substring(0, 1);
        }
    }

 

ComplexType

Bir sınıf kümesinde etki alanı varlıklarınızı açıklamak ve ardından tam bir varlığı açıklamak için bu sınıfları katmana almak sık karşılaşılan bir durum değildir. Örneğin, modelinize BlogDetails adlı bir sınıf ekleyebilirsiniz.

    public class BlogDetails
    {
        public DateTime? DateCreated { get; set; }

        [MaxLength(250)]
        public string Description { get; set; }
    }

BlogDetails Herhangi bir anahtar özelliği türüne sahip olmadığını fark edin. Etki alanı temelli tasarımda değer BlogDetails nesnesi olarak adlandırılır. Entity Framework, değer nesnelerini karmaşık türler olarak ifade eder.  Karmaşık türler kendi başına izlenemez.

Ancak sınıfında bir özellik Blog olarak, BlogDetails bir Blog nesnenin parçası olarak izlenir. Kodun önce bunu tanıması için sınıfını BlogDetails olarak ComplexTypeişaretlemeniz gerekir.

    [ComplexType]
    public class BlogDetails
    {
        public DateTime? DateCreated { get; set; }

        [MaxLength(250)]
        public string Description { get; set; }
    }

Artık bu blog için Blog öğesini temsil etmek üzere sınıfına BlogDetails bir özellik ekleyebilirsiniz.

        public BlogDetails BlogDetail { get; set; }

Veritabanında tablo, Blog özelliğinde yer BlogDetail alan özellikler de dahil olmak üzere blogun tüm özelliklerini içerir. Varsayılan olarak, her birinin başında "BlogDetail" karmaşık türünün adı yer alır.

Blog table with complex type

ConcurrencyCheck

Ek ConcurrencyCheck açıklama, kullanıcı bir varlığı düzenlediğinde veya sildiğinde veritabanında eşzamanlılık denetimi için kullanılacak bir veya daha fazla özelliğe bayrak eklemenizi sağlar. EF Tasarım Aracı ile çalışıyorsanız, bu özellik olarak ayarlanır ConcurrencyModeFixed.

Özelliğine BloggerName ekleyerek nasıl ConcurrencyCheck çalıştığını görelim.

    [ConcurrencyCheck, MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
    public string BloggerName { get; set; }

ÇağrıldığındaSaveChanges, alandaki ek açıklama BloggerName nedeniyle ConcurrencyCheck bu özelliğin özgün değeri güncelleştirmede kullanılır. Komut, yalnızca anahtar değerini değil özgün değerini BloggerNamede filtreleyerek doğru satırı bulmayı dener.  Veritabanına gönderilen UPDATE komutunun kritik bölümleri aşağıdadır. Burada komutun, blog veritabanından alındığında özgün değer olan 1 ve BloggerName "Julie" değerini içeren satırı PrimaryTrackingKey güncelleştireceğini görebilirsiniz.

    where (([PrimaryTrackingKey] = @4) and ([BloggerName] = @5))
    @4=1,@5=N'Julie'

Bu sırada birisi blogun blogcu adını değiştirdiyse, bu güncelleştirme başarısız olur ve işlemeniz gereken bir DbUpdateConcurrencyException alırsınız.

 

TimeStamp

Eşzamanlılık denetimi için rowversion veya zaman damgası alanlarını kullanmak daha yaygındır. Ancak ek açıklamayı ConcurrencyCheck kullanmak yerine, özelliğin türü bayt dizisi olduğu sürece daha belirli TimeStamp bir ek açıklama kullanabilirsiniz. Önce kod özellikleri özelliklerle aynı şekilde ConcurrencyCheck ele Timestamp alır, ancak aynı zamanda kodun oluşturduğu veritabanı alanının null değer atanamaz olmasını da sağlar. Belirli bir sınıfta yalnızca bir zaman damgası özelliğine sahip olabilirsiniz.

Blog sınıfına aşağıdaki özelliği ekleme:

    [Timestamp]
    public Byte[] TimeStamp { get; set; }

, ilk olarak veritabanı tablosunda null atanamayan bir zaman damgası sütunu oluşturan kodla sonuçlanabilir.

Blogs table with time stamp column

 

Tablo ve Sütun

Veritabanını Code First'in oluşturmasına izin veriyorsanız, oluşturduğu tabloların ve sütunların adını değiştirmek isteyebilirsiniz. Ayrıca, mevcut bir veritabanıyla Code First'i de kullanabilirsiniz. Ancak, etki alanınızdaki sınıfların ve özelliklerin adlarının veritabanınızdaki tablo ve sütunların adlarına uyması her zaman söz konusu değildir.

Sınıfım adlı Blog ve kurala göre kod ilk olarak bunun adlı Blogsbir tabloyla eşlenecek olduğunu varsayacak. Böyle bir durum söz konusu değilse, özniteliğine sahip Table tablonun adını belirtebilirsiniz. Örneğin, ek açıklama tablo adının InternalBlogs olduğunu belirtir.

    [Table("InternalBlogs")]
    public class Blog

Ek Column açıklama, eşlenmiş bir sütunun özniteliklerini belirtme konusunda daha ustadır. Bir adı, veri türünü, hatta tabloda bir sütunun görüntülenme sırasını bile belirtebilirsiniz. Özniteliğin bir örneği aşağıda verilmiştir Column .

    [Column("BlogDescription", TypeName="ntext")]
    public String Description {get;set;}

Column özniteliğini TypeName DataType DataAnnotation ile karıştırmayın. DataType, kullanıcı arabirimi için kullanılan bir ek açıklamadır ve Önce Kod tarafından yoksayılır.

Yeniden oluşturulduktan sonra tablo aşağıda verilmiştir. Tablo adı InternalBlogs olarak değiştirildi ve Description karmaşık türdeki sütun artık BlogDescriptionşeklindedir. Ad ek açıklamada belirtildiğinden, kod önce sütun adını karmaşık türün adıyla başlatma kuralını kullanmaz.

Blogs table and column renamed

 

DatabaseGenerated

Önemli veritabanı özelliklerinden biri, hesaplanan özelliklere sahip olma özelliğidir. Code First sınıflarınızı hesaplanan sütunlar içeren tablolarla eşlerseniz, Entity Framework'ün bu sütunları güncelleştirmeyi denemesini istemezsiniz. Ancak, verileri ekledikten veya güncelleştirdikten sonra EF'nin bu değerleri veritabanından döndürmesini istiyorsunuz. Ek açıklamayı DatabaseGenerated kullanarak sınıfınızdaki bu özelliklere sabit listesiyle Computed birlikte bayrak ekleyebilirsiniz. Diğer sabit listeleri ve IdentityşeklindedirNone.

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime DateCreated { get; set; }

Kod veritabanını ilk oluştururken bayt veya zaman damgası sütunlarında oluşturulan veritabanını kullanabilirsiniz, aksi takdirde kodun hesaplanan sütun için formülü belirleyemeyeceği için bunu yalnızca mevcut veritabanlarını işaret ederken kullanmanız gerekir.

Bunu varsayılan olarak okursanız, tamsayı olan bir anahtar özelliği veritabanında kimlik anahtarı olur. Bu, ayarıyla DatabaseGeneratedDatabaseGeneratedOption.Identityaynı olacaktır. Kimlik anahtarı olmasını istemiyorsanız değerini olarak DatabaseGeneratedOption.Noneayarlayabilirsiniz.

 

Dizin oluşturma

Dekont

EF6.1 Yalnızca Devam Eden - Index Özniteliği Entity Framework 6.1'de kullanıma sunulmuştur. Önceki bir sürümü kullanıyorsanız bu bölümdeki bilgiler geçerli değildir.

IndexAttribute kullanarak bir veya daha fazla sütunda dizin oluşturabilirsiniz. Özniteliğin bir veya daha fazla özelliğe eklenmesi, EF'nin veritabanını oluştururken veritabanında karşılık gelen dizini oluşturmasına veya Code First Migrations kullanıyorsanız ilgili CreateIndex çağrılarının iskelesini oluşturmasına neden olur.

Örneğin, aşağıdaki kod veritabanındaki Rating tablonun sütununda Posts bir dizin oluşturulmasına neden olur.

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        [Index]
        public int Rating { get; set; }
        public int BlogId { get; set; }
    }

Varsayılan olarak, dizin IX_<özellik adı> (yukarıdaki örnekte IX_Rating) olarak adlandırılır. Yine de dizin için bir ad belirtebilirsiniz. Aşağıdaki örnek, dizinin olarak adlandırılması PostRatingIndexgerektiğini belirtir.

    [Index("PostRatingIndex")]
    public int Rating { get; set; }

Varsayılan olarak, dizinler benzersiz olmayanlardır, ancak bir dizinin benzersiz olması gerektiğini belirtmek için adlandırılmış parametresini kullanabilirsiniz IsUnique . Aşağıdaki örnek, bir 'nin oturum açma adı üzerinde benzersiz bir Userdizin tanıtır.

    public class User
    {
        public int UserId { get; set; }

        [Index(IsUnique = true)]
        [StringLength(200)]
        public string Username { get; set; }

        public string DisplayName { get; set; }
    }

Birden Çok Sütunlu Dizinler

Birden çok sütuna yayılan dizinler, belirli bir tablo için birden çok Dizin ek açıklamasında aynı ad kullanılarak belirtilir. Çok sütunlu dizinler oluşturduğunuzda, dizindeki sütunlar için bir sıra belirtmeniz gerekir. Örneğin, aşağıdaki kod üzerinde Rating çok sütunlu bir dizin oluşturur ve BlogId IX_BlogIdAndRating olarak adlandırılır. BlogId dizindeki ilk sütun ve Rating ikinci sütundur.

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        [Index("IX_BlogIdAndRating", 2)]
        public int Rating { get; set; }
        [Index("IX_BlogIdAndRating", 1)]
        public int BlogId { get; set; }
    }

 

İlişki Öznitelikleri: InverseProperty ve ForeignKey

Dekont

Bu sayfa, Veri Ek Açıklamalarını kullanarak Code First modelinizde ilişkileri ayarlama hakkında bilgi sağlar. EF'teki ilişkiler ve ilişkileri kullanarak verilere erişme ve verileri işleme hakkında genel bilgi için bkz . İlişkiler ve Gezinti Özellikleri.*

Kod ilk kuralı, modelinizdeki en yaygın ilişkileri üstlenir, ancak yardıma ihtiyacı olan bazı durumlar vardır.

sınıfındaki anahtar özelliğinin Blog adını değiştirmek, ile ilişkisiyle Postilgili bir sorun oluşturdu. 

Veritabanı oluşturulurken, kod önce Post sınıfında özelliğini görür BlogId ve sınıf adı artı kimliği ile sınıfa yabancı anahtar olarak eşleştiği kuralına Blog göre bu özelliği tanır. Ancak blog sınıfında özellik yoktur BlogId . Bunun çözümü, içinde Post bir gezinti özelliği oluşturmak ve dataannotation kullanarak kodun ForeignKey önce iki sınıf (özelliği kullanarak Post.BlogId ) arasındaki ilişkiyi nasıl oluşturacağını ve veritabanında kısıtlamaların nasıl belirtileceğini anlamasına yardımcı olmaktır.

    public class Post
    {
            public int Id { get; set; }
            public string Title { get; set; }
            public DateTime DateCreated { get; set; }
            public string Content { get; set; }
            public int BlogId { get; set; }
            [ForeignKey("BlogId")]
            public Blog Blog { get; set; }
            public ICollection<Comment> Comments { get; set; }
    }

Veritabanındaki kısıtlama ile Posts.BlogIdarasında InternalBlogs.PrimaryTrackingKey bir ilişki gösterir. 

relationship between InternalBlogs.PrimaryTrackingKey and Posts.BlogId

InverseProperty, sınıflar arasında birden çok ilişki olduğunda kullanılır.

Sınıfında, blog gönderisini Post kimin yazdığını ve kimin düzenlediğini takip etmek isteyebilirsiniz. Post sınıfı için iki yeni gezinti özelliği aşağıdadır.

    public Person CreatedBy { get; set; }
    public Person UpdatedBy { get; set; }

Bu özellikler tarafından başvuruda bulunan Person sınıfını da eklemeniz gerekir. sınıfı, Person kişi tarafından yazılan tüm gönderiler için ve bu kişi tarafından güncelleştirilen tüm gönderiler için bir gezinti özelliğine sahiptir Post.

    public class Person
    {
            public int Id { get; set; }
            public string Name { get; set; }
            public List<Post> PostsWritten { get; set; }
            public List<Post> PostsUpdated { get; set; }
    }

İlk olarak kod, iki sınıftaki özellikleri kendi kendine eşleştiremez. veritabanı Posts tablosunda kişi için bir yabancı anahtar ve kişi için UpdatedByCreatedBy bir tane olmalıdır, ancak önce kod dört yabancı anahtar özelliği oluşturur: Person_Id, Person_Id1, CreatedBy_Id ve UpdatedBy_Id.

Posts table with extra foreign keys

Bu sorunları düzeltmek için ek açıklamayı InverseProperty kullanarak özelliklerin hizalamasını belirtebilirsiniz.

    [InverseProperty("CreatedBy")]
    public List<Post> PostsWritten { get; set; }

    [InverseProperty("UpdatedBy")]
    public List<Post> PostsUpdated { get; set; }

Person özelliği PostsWritten bunun türe başvurduğunu bildiği için Post ile ilişkisini Post.CreatedByoluşturur. Benzer şekilde, PostsUpdated öğesine Post.UpdatedBybağlanır. Ve kod ilk olarak fazladan yabancı anahtar oluşturmaz.

Posts table without extra foreign keys

 

Özet

DataAnnotations, yalnızca kod ilk sınıflarınızda istemci ve sunucu tarafı doğrulamasını açıklamanıza izin vermekle kalmaz, aynı zamanda kodun sınıflarınızla ilgili ilk olarak kendi kurallarına göre yapacağı varsayımları geliştirmenize ve hatta düzeltmenize de olanak sağlar. DataAnnotations ile yalnızca veritabanı şeması oluşturmayı yönlendirmekle kalmaz, aynı zamanda kod ilk sınıflarınızı önceden var olan bir veritabanına da eşleyebilirsiniz.

Bunlar çok esnek olsa da DataAnnotations'ın yalnızca kod ilk sınıflarınızda yapabileceğiniz en yaygın yapılandırma değişikliklerini sağladığını unutmayın. Bazı uç durumlarda sınıflarınızı yapılandırmak için, alternatif yapılandırma mekanizması olan Code First'in Fluent API'sine bakmanız gerekir.