DDD之EFCore实现值对象
DDD之EFCore实现值对象
Region
public record Region
{
public long Id { get; init; }
public MultilingualString Name { get; init; }
public Area Area { get; init; }
public RegionLevel Level { get; private set; }
public long? Population { get; private set; } //人口
public Geo Location { get; init; }
private Region() { }
public Region(MultilingualString name, Area area, Geo location,
RegionLevel level)
{
this.Name = name;
this.Area = area;
this.Location = location;
this.Level = level;
}
public void ChangePopulation(long value)
{
this.Population = value;
}
public void ChangeLevel(RegionLevel value)
{
this.Level = value;
}
}
//多语言
public record MultilingualString(string Chinese, string? English);
//区域大小
public record Area(double Value, AreaType Unit);
public enum AreaType
{
SquareKM,//平方米
Hectare, //公顷
CnMu //
}
//城市级别
public enum RegionLevel
{
Province,//省
City, //城市
County, //国家
Town //城镇
}
//经纬度
public 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;
}
}
RegionConfig
class RegionConfig : IEntityTypeConfiguration<Region>
{
public void Configure(EntityTypeBuilder<Region> builder)
{
builder.ToTable("T_Cities");
builder.OwnsOne(c => c.Area, nb =>
{
nb.Property(e => e.Value)
.HasColumnName("AreaValue")
.HasComment("区域大小");
nb.Property(e => e.Unit)
.HasColumnName("AreaUnit")
.HasMaxLength(20).IsUnicode(false)
.HasConversion<string>().HasComment("单位(平方米/公顷)"); ;
});
builder.Property(e => e.Population).HasComment("人口");
builder.OwnsOne(c => c.Location, nb =>
{
nb.Property(e => e.Longitude)
.HasColumnName("Longitude")
.HasComment("经度");
nb.Property(e => e.Latitude)
.HasColumnName("Latitude")
.HasComment("维度");
});
builder.Property(c => c.Level).HasMaxLength(20)
.IsUnicode(false).HasConversion<string>()
.HasComment("城市级别(国家/省/市/城镇)");
builder.OwnsOne(c => c.Name, nb =>
{
nb.Property(e => e.English).HasMaxLength(20).IsUnicode(false)
.HasColumnName("NameEnglish")
.HasComment("英文");
nb.Property(e => e.Chinese).HasMaxLength(20).IsUnicode(true)
.HasColumnName("NameChinese")
.HasComment("中文");
});
}
}
(1)“从属实体类型(owned entities)”:使用Fluent API中的OwnsOne等方法来配置。
(2)在EF Core中,实体的属性可以定义为枚举类型,枚举类型的属性在数据库中默认是以整数类型来保存的。EF Core中可以在Fluent API中用HasConversion
(4)查看数据库
执行命令add-mirgration 、update-database
(5)简化值对象的比较操作
ExpressionHelper
class ExpressionHelper
{
public static Expression<Func<TItem, bool>> MakeEqual<TItem, TProp>
(Expression<Func<TItem, TProp>> propAccessor, TProp? other)
where TItem : class where TProp : class
{
var e1 = propAccessor.Parameters.Single();
BinaryExpression? conditionalExpr = null;
foreach (var prop in typeof(TProp).GetProperties())
{
BinaryExpression equalExpr;
object? otherValue = null;
if (other != null)
{
otherValue = prop.GetValue(other);
}
Type propType = prop.PropertyType;
var leftExpr = MakeMemberAccess(propAccessor.Body, prop);
Expression rightExpr = Convert(Constant(otherValue), propType);
if (propType.IsPrimitive)
{
equalExpr = Equal(leftExpr, rightExpr);
}
else
{
equalExpr = MakeBinary(ExpressionType.Equal,
leftExpr, rightExpr, false,
prop.PropertyType.GetMethod("op_Equality")
);
}
if (conditionalExpr == null)
{
conditionalExpr = equalExpr;
}
else
{
conditionalExpr = AndAlso(conditionalExpr, equalExpr);
}
}
if (conditionalExpr == null)
{
throw new ArgumentException("There should be at least one property.");
}
return Lambda<Func<TItem, bool>>(conditionalExpr, e1);
}
}