我开发的开源项目,让.NET7中的EFCore更轻松地使用强类型Id

我开发的开源项目,让.NET7中的EFCore更轻松地使用强类型Id
在领域驱动设计(DDD)中,有一个非常重要的概念:“强类型Id”。使用强类型Id来做标识属性的类型会比用int、Guid等通用类型能带来更多的好处。比如有一个根据根据Id删除用户的方法的签名如下:
void RemoveById(long id);
我们从方法的参数看不出来id代表什么含义,因此如果我们错误地把货物的id传递给这个方法,那么也是可以的。这样用long等通用类型来表示标识属性会让参数等的业务属性弱化。
而如果我们自定义一个UserId类型,如下:
class UserId
{public long Value{get;init;}public UserId(long value)
{ this.Value=value;
}
}这样User类的定义中Id属性的类型就从long变成了UserId类型,如下:
class User
{ public UserId Id{get;} public string Name{get;set;}
}对应的RemoveById方法的签名也变成了:
void RemoveById(UserId id);
这样不仅能一看就看出来id参数代表的业务含义,也能避免“把货物Id的值传递给用户Id参数”这样的问题。
在.NET 6及之前,Entity Framework Core(简称EF Core)中很难优美地实现强类型Id。在.NET7中,EF Core中提供了对强类型Id的支持,具体用法请参考EF Core官方文档中“Value generation for DDD guarded types”这部分内容。
尽管EF Core已经内置了对强类型Id的支持,但是它需要程序员编写非常多的代码。比如一个比较完善的强类型Id类的代码就要编写如下30多行代码:
public readonly struct PersonId
{ public Guid Value { get; } public PersonId(Guid value)
{
Value = value;
}
public override string ToString()
{ return Convert.ToString(Value);
}
public override int GetHashCode()
{ return Value.GetHashCode();
}
public override bool Equals(object obj)
{ if (obj is PersonId)
{
PersonId objId = (PersonId)obj; return Value == objId.Value;
} return base.Equals(obj);
}
public static bool operator ==(PersonId c1, PersonId c2)
{ return c1.Equals(c2);
}
public static bool operator !=(PersonId c1, PersonId c2)
{ return !c1.Equals(c2);
}
}还要编写一个ValueConverter类以及配置自定义的ValueGenerator……需要编写的代码的复杂程度让想使用强类型Id的开发者望而却步。
正因为这一点,所以连微软的文档中都警告到"强类型Id会增加代码的复杂性,请谨慎使用"。幸好,这个世界有我!
为了解决这个问题,我基于.NET的SourceGenerator技术编写了一个开源项目,这个开源项目会在编译时自动生成相关的代码,开发人员只要在实体类上标注一个[HasStronglyTypedId]即可。
项目地址:https://github.com/yangzhongke/LessCode.EFCore.StronglyTypedId
下面我用一个把所有代码都写到一个控制台项目中的例子来演示它的用法,多项目分层等更复杂的用法请见项目文档以及项目中的Examples文件夹中的内容。
注意:这个项目可能会随着升级而用法有所变化,具体用法请以最新官方文档为准。
用法:
1、 新建一个.NET7控制台项目,然后依次安装如下这些Nuget包:LessCode.EFCore、LessCode.EFCore.StronglyTypedIdCommons、LessCode.EFCore.StronglyTypedIdGenerator。当然我们的项目要使用SQLServer以及使用EF core的migration,所以还要安装如下的Nuget包:Microsoft.EntityFrameworkCore.SqlServer、Microsoft.EntityFrameworkCore.Tools。
2、 项目中新建一个实体类型Person
[HasStronglyTypedId]class Person
{ public PersonId Id { get; se我开发的开源项目,让.NET7中的EFCore更轻松地使用强类型Id
声明:除非特别标注,否则均为本站原创文章,转载时请以链接形式注明文章出处。如若本站内容侵犯了原著者的合法权益,可联系本站删除。




