這個開源項目讓Entity Framework Core 7中輕松使用強類型Id
在領域驅(qū)動設計(DDD)中,有一個非常重要的概念:“強類型Id”。使用強類型Id來做標識屬性的類型會比用int、Guid等通用類型能帶來更多的好處。比如有一個根據(jù)根據(jù)Id刪除用戶的方法的簽名如下:
我們從方法的參數(shù)看不出來id代表什么含義,因此如果我們錯誤地把貨物的id傳遞給這個方法,那么也是可以的。這樣用long等通用類型來表示標識屬性會讓參數(shù)等的業(yè)務屬性弱化。
而如果我們自定義一個UserId類型,如下:
這樣User類的定義中Id屬性的類型就從long變成了UserId類型,如下:
對應的RemoveById方法的簽名也變成了:
這樣不僅能一看就看出來id參數(shù)代表的業(yè)務含義,也能避免“把貨物Id的值傳遞給用戶Id參數(shù)”這樣的問題。
在.NET 6及之前,Entity Framework Core(簡稱EF Core)中很難優(yōu)美地實現(xiàn)強類型Id。在.NET7中,EF Core中提供了對強類型Id的支持,具體用法請參考EF Core官方文檔中“Value generation for DDD guarded types”這部分內(nèi)容。
盡管EF Core已經(jīng)內(nèi)置了對強類型Id的支持,但是它需要程序員編寫非常多的代碼。比如一個比較完善的強類型Id類的代碼就要編寫如下30多行代碼:
還要編寫一個ValueConverter類以及配置自定義的ValueGenerator……需要編寫的代碼的復雜程度讓想使用強類型Id的開發(fā)者望而卻步。
為了解決這個問題,我基于.NET的SourceGenerator技術編寫了一個開源項目,這個開源項目會在編譯時自動生成相關的代碼,開發(fā)人員只要在實體類上標注一個[HasStronglyTypedId]即可。
?
項目地址:https://github.com/yangzhongke/LessCode.EFCore.StronglyTypedId
?
下面我用一個把所有代碼都寫到一個控制臺項目中的例子來演示它的用法,多項目分層等更復雜的用法請見項目文檔以及項目中的Examples文件夾中的內(nèi)容。
注意:這個項目可能會隨著升級而用法有所變化,具體用法請以最新官方文檔為準。
用法:
1、 新建一個.NET7控制臺項目,然后依次安裝如下這些Nuget包:LessCode.EFCore、LessCode.EFCore.StronglyTypedIdCommons、LessCode.EFCore.StronglyTypedIdGenerator。當然我們的項目要使用SQLServer以及使用EF core的migration,所以還要安裝如下的Nuget包:Microsoft.EntityFrameworkCore.SqlServer、Microsoft.EntityFrameworkCore.Tools。
2、 項目中新建一個實體類型Person
我們注意到Person上標注的[HasStronglyTypedId(typeof(Guid))],它代表這個類啟用強類型Id,編譯器在編譯的時候自動生成一個名字叫PersonId的類,所以我們就聲明了一個名字叫Id、類型為PersonId的屬性來表示實體的標識。
PersonId在數(shù)據(jù)庫中保存的默認是long類型,如果想保存為Guid類型,就可以寫成[HasStronglyTypedId(typeof(Guid))]。
編譯一下項目,如果能夠編譯成功,我們反編譯生成的dll,就能看到dll中自動生成了PersonId、PersonIdValueConverter兩個類。

3、 編寫DbContext,代碼如下:
4、 進行數(shù)據(jù)庫的遷移等操作,這部分屬于EF Core的標準操作,我不再介紹。對EF Core的用法不熟悉的朋友,請到嗶哩嗶哩、youtube等平臺搜索“楊中科 .NET Core教程”。
5、 編寫代碼進行測試
強類型Id讓我們能夠更好的在EFCore中實現(xiàn)DDD,我開源的這個項目能夠讓開發(fā)者只要在實體類上標注一行[HasStronglyTypedId]就可以完成強類型Id的使用。希望它能夠幫到你,歡迎把它分享到你所在的技術社區(qū)。