[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