如何使用EF優雅的配置一對一的關系
在這兩天的時間已經有兩位同事問到EF(Code First)如何配置一對一的關系,這個說難也不難,說簡單吧,一旦設計跑偏那麽在Coding的過程中將會很痛苦。
先舉個很簡單的例子,兩個類User和Profile,User裏面存在用戶的基本信息比如郵箱和密碼,Profile裏面存放用戶的個人資料。
public class User { public int Id { get; set; } public string Email { get; set; } public string Password { get; set; } public virtual Profile Profile { get; set; } } public class Profile { public int Id { get; set; } public string Name { get; set; } public Gender Gender { get; set; } public string Phone { get; set; } public string Address { get; set; } public virtual User User { get; set; } }
上面的代碼應該是直接了當的。透過領域模型應該能充分描述出User和Profile的業務。分析:對於一個User來說只能有一個Profile(一對一),反過來對於一個Profile來說只能對應一個User(一對一),而且也必須有一個User。下面是通過fluent api做一些映射
public class UserMapping : EntityTypeConfiguration<User> { public UserMapping() { ToTable("tb_User"); } } public class ProfileMapping : EntityTypeConfiguration<Profile> { public ProfileMapping() { ToTable("tb_Profile"); HasKey(u => u.Id) .HasRequired(u => u.User) // 對於一個Profile來說必須有一個User否則Profile無家可歸 .WithOptional(u => u.Profile) // 同事一個User對應一個Profile 非必須 .WillCascadeOnDelete(false); // 不需要級聯刪除 } }
上面的代碼也應該也是直接了當的。那麽這樣生成的數據庫結構是什麽樣的呢?約束又是什麽樣的呢?又是否符合我們的業務需求
User表沒有什麽問題,Profile的ID字段不單單是一個主鍵,同時也是一個外鍵。我們回到具體的業務中來。當我插入一條User數據的時候要不要插入Profile數據呢?其實是都可以的,如果同時插入的話,User和Profile應該是一起往前走的,而且User的ID和Profile的ID是一樣的。那如果插入User的時候不插入Profile呢,其實也沒有問題,詳細的說明:
假如我插入兩條User數據,User表會有兩條數據,ID分別為1和2。Profile表為空,沒有數據。2用戶有一天回過頭來想完善自己的個人詳細信息,插進去的Profile數據ID應該為2,後來1用戶也來完善自己的個人資料,這個時候插入的Profile數據ID為1(雖然2用戶先完善的,2用戶的ProfileID還是2,1用戶的ProfileID還是1)。
static void Main(string[] args)
{
DemoDbContext db = new DemoDbContext();
var user = db.Users.SingleOrDefault(u => u.Id == 2);
Profile profile = new Profile
{
Address = "beijing"
};
user.Profile = profile;
db.SaveChanges();
}
順便對領域模型嘮叨幾句:
領域模型是領域驅動設計中最重要的對象,它們是描述我們業務的對象,應該最大力度保持幹凈,整潔。作為一名開發人員應該多花點時間放在領域的設計上。然而領域的設計應該是和領域專家(產品經理)強度溝通的情況下去完成設計的。比如要做一款財務軟件,程序員怎麽可能對財務非常精通,都是和財務專家或懂財務的人溝通的基礎上去完成我們的領域設計。所以在公司中應確保最好,最有經驗的開發人員分配到領域相關的任務上去。
如何使用EF優雅的配置一對一的關系