目录
值对象优点
值对象的需求
值类型的实现
值类型GEO的实现
值类型MultilingualString的实现
案例:构建表达式树,简化值对象的比较
值对象优点
- 把有紧密关系的属性打包为一个类型
- 把领域知识放到类的定义中
class shangjia
{
long id;
string name;
Geo location;
}
class Geo
{
double jingdu;
double weidu;
}
值对象的需求
- “商品”实体中的重量属性。我们如果把重量定义为double类型,那么其实是隐含了一个“重量单位”的领域知识,使用这个实体类的开发人员就需要知道这个领域知识,而且我们还要通过文档等形式把这个领域知识记录下来,这又面临一个文档和代码修改同步的问题。
- 实现:定义一个包含Value(数值)、Unit(单位)的Weight类型,然后把“商品”的重量属性设置为Weight类型。
class Shangpin { long id; string name; Weight weight; } class Weight { long Value; WeightUnit Unit; } enum WeightUnit{G,KG}
- 很多数值类型的属性其实都是隐含了单位的,比如金额隐含了币种信息。
值类型的实现
“从属实体类型(owned entities)”:使用Fluent API中的OwnsOne等方法来配置。
在EF Core中,实体的属性可以定义为枚举类型,枚举类型的属性在数据库中默认是以整数类型来保存的。对于直接操作数据库的人员来讲,0、1、2这样的值没有“CNY”(人民币)、“USD”(美元)、“NZD”(新西兰元)等这样的字符串类型值可读性更强。EF Core中可以在Fluent API中用HasConversion<string>()把枚举类型的值配置成保存为字符串。
public class Entity1
{
public int Id{ get; set; }
public string Name{ get; set; }
public CurrencyName Currency{ get; set; }
}
enum CurrencyName
{
CNY,USD,NZD
}
builder..Property(e=>e.Currency).HasConversion<string>().HasMaxLenght(10);
值类型GEO的实现
record Geo{
public double Longitude { get; init; }
public double Latitude { get; init; }
public Geo(double longitude, double latitude)
{
if(longitude<-180||longitude>180)
throw new ArgumentException("longitude invalid");
if (latitude < -90 || latitude > 90)
throw new ArgumentException("longitude invalid");
this.Longitude = longitude;
this.Latitude = latitude;
}
}
builder.OwnsOne(c=>c.Location);
值类型MultilingualString的实现
record MultiLangString(string Chinese, string? English);
public class Blog
{
public int Id { get; set;}
public MultiLangString Title { get; set; }
public MultiLangString Body { get; set; }
}
//builder.OwnsOne(e=>e.Title);
//builder.OwnsOne(e=>e.Body);
builder.OwnsOne(c=>c.Title, x => {
x.Property(e=>e.Chinese).HasMaxLength(255);
x.Property(e=>e.English).HasColumnType("varchar(255)");
});
builder.OwnsOne(c=>c.Body, x => {
x.Property(e=>e.Chinese);
x.Property(e=>e.English).HasColumnType("varchar(Max)");
});
案例:构建表达式树,简化值对象的比较
目前版本,如果需要进行数据筛选,值对象的属性不能直接进行相等比较,只能把值对象的各个属性逐个进行比较,如果属性较多或需要相等比较的代码较多的话,操作会比较麻烦,可以构建表达式树来生成一个进行相等比较的表达式,从而简化EF Core中值对象的比较。
错误写法
var x = db.blogs.First(b => b.Title == new MultiLangString("你好", "hello"));
var a = db.blogs.First(b => b.Title.Equals(new MultiLangString("你好", "hello")));
正确写法
var a = db.blogs.First(b => b.Title.Chinese=="你好"&&b.Title.English=="hello");
NETBookMaterials/最后大项目代码/YouZack-VNext/Zack.Infrastructure/EFCore/ExpressionHelper.cs at main · yangzhongke/NETBookMaterials
Nuget:Zack.Infrastructure
var a = db.blogs.First(ExpressionHelper.MakeEqual((Blog b) => b.Title,(new MultiLangString("你好", "hello"))));