[C#.NET][Entity Framework] Code First 使用 Attribute / Fluent 來設定關聯屬性
續上篇,http://www.dotblogs.com.tw/yc421206/archive/2014/03/15/144403.aspx
當 EF 慣用預設行為,已經沒有辦法滿足的時候,可以使用 Attribute 或 Fluent 應用程式來開發
System.ComponentModel.DataAnnotations 命名空間,有一些可以套用在 EF 的 Attribute
KeyAttribute | 表示唯一識別實體的一個或多個屬性 |
MaxLengthAttribute | 指定屬性中所允許之陣列或字串資料的最大長度 |
MinLengthAttribute | 指定屬性中所允許之陣列或字串資料的最小長度 |
必填欄位 | |
StringLengthAttribute | 指定資料欄位中允許的最小和最大字元長度 |
System.ComponentModel.DataAnnotations.Schema 命名空間,這很明顯就是要給 SQL 用的了,就不再列表了
有關 Attribute 可以參考以下連結
http://msdn.microsoft.com/zh-tw/data/jj591583#Relationships
Attribute很好用,可以直接跟 ASP.NET MVC 做驗証,在閱讀上也是相當直覺,不過…
還是會有一些情況是無法透過 Attribute 來處理,這時候就必須要用 Fluent 來開發,我們可能會用到以下方法
- EntityTypeConfiguration<TEntityType> 方法
- RequiredNavigationPropertyConfiguration<TEntityType, TTargetEntityType> 方法
- DependentNavigationPropertyConfiguration<TDependentEntityType>.WillCascadeOnDelete 方法
Fluent 可以寫在兩個地方
- 衍生 DbContext 類別的 OnModelCreating 方法裡
- 實作 EntityTypeConfiguration<TEntity>,提供給 OnModelCreating 調用或是套用在衍生 DbContext 類別上,如 http://www.dotblogs.com.tw/yc421206/archive/2014/03/15/144399.aspx
public class SystemDbContext : DbContext { … }
{ protected override void OnModelCreating(DbModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.Configurations.Add(new CategoryConfiguration()); } }
一對多對應寫法
{ public CategoryConfiguration() { // Primary Key this.HasKey(t => t.Id); // Properties this.Property(t => t.Id) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); this.Property(t => t.Name).IsRequired() .HasMaxLength(100); // Table & Column Mappings this.ToTable("Category"); this.Property(t => t.Id).HasColumnName("Id"); this.Property(t => t.Name).HasColumnName("Name"); } }
{ public ProductConfiguration() { // Primary Key this.HasKey(t => t.Id); // Properties this.Property(t => t.Id) .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); this.Property(t => t.Name).IsRequired() .HasMaxLength(100); this.Property(t => t.UnitPrice).HasPrecision(10, 2); // Table & Column Mappings this.ToTable("Product"); // Relationships this.HasRequired(t => t.Category) .WithMany(t => t.Products) .HasForeignKey(t => t.CategoryId) .WillCascadeOnDelete(false); } }
在 OnModelCreating 裡調用
{ public DbSet<Category> Categories { get; set; } public DbSet<Product> Products { get; set; } public SystemDbContext() : base("localdb") { Database.SetInitializer(new DropCreateDatabaseAlways<SystemDbContext>()); } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Configurations.Add(new CategoryConfiguration()); modelBuilder.Configurations.Add(new ProductConfiguration()); } }
一對一關聯互查
我想要在 Employee 與 Identity 能夠用物件
{ public int Id { get; set; } public string Name { get; set; } public virtual Identity Identity { get; set; } } public class Identity { [Key] [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] public int Id { get; set; } [Required] public string Account { get; set; } public string Password { get; set; } public virtual Employee Employee { get; set; } }
上面的寫法 EF 預設不支援,我們可以透過 Fluent 來關聯它們
{ modelBuilder.Entity<Employee>(); modelBuilder.Entity<Identity>() .HasOptional(q => q.Employee) .WithOptionalPrincipal(t => t.Identity) .Map(t => t.MapKey("IdentityId")); }
產生的 Schema 如下圖:
雖然資料表仍是相同,就物件的操作來講的確能達到互相查詢的效果
這裡還有更多的Fluent
http://msdn.microsoft.com/zh-tw/data/jj591617.aspx
http://msdn.microsoft.com/zh-tw/data/hh134698.aspx
文章出自:http://www.dotblogs.com.tw/yc421206/archive/2014/03/18/144424.aspx
若有謬誤,煩請告知,新手發帖請多包涵
Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET