Kod İlk Veri Ek Açıklamaları
Not
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ğunu etkinleştirmek 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.
Anahtar
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.
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 InvalidOperationException
ile 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.
Not
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.
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.
Not
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.
MaxLength ve MinLength
MaxLength
ve MinLength
öznitelikleri, aynı ile Required
yaptığı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.
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.
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 ComplexType
iş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.
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 Designer ile çalışıyorsanız, bu özellik olarak ayarlanmasıyla ConcurrencyMode
Fixed
uyumlu olur.
Ö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 BloggerName
de 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.
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ı Blogs
bir 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.
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 DatabaseGenerated
DatabaseGeneratedOption.Identity
aynı olacaktır. Kimlik anahtarı olmasını istemiyorsanız değerini olarak DatabaseGeneratedOption.None
ayarlayabilirsiniz.
Dizin oluşturma
Not
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ı PostRatingIndex
gerektiğ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 User
dizin 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
Not
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 Post
ilgili 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.BlogId
arasında InternalBlogs.PrimaryTrackingKey
bir ilişki gösterir.
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 UpdatedBy
CreatedBy
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.
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.CreatedBy
oluşturur. Benzer şekilde, PostsUpdated
öğesine Post.UpdatedBy
bağlanır. Ve kod ilk olarak fazladan yabancı anahtar oluşturmaz.
Ö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.