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);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!