如何将类属性值存储至另一数据库表并标记需双存储属性?
几种实现类属性跨表同步的方案
嘿,你的需求我懂——就是想让Audited类里的部分属性既留在自身表,又同步到Summary这类别的领域对象表对吧?我给你分享几个实际项目里常用的实现方式,你可以根据自己的技术栈选:
方案1:自定义特性标记需要同步的属性
这是最直观的方式,通过自定义一个特性来标记哪些属性需要双写,然后在持久化的时候通过反射读取这些属性的值,同步到Summary对象。
首先定义一个自定义特性:
[AttributeUsage(AttributeTargets.Property)] public class SyncToSummaryAttribute : Attribute { // 可以加配置参数,指定对应Summary里的属性名 public string TargetPropertyName { get; set; } public SyncToSummaryAttribute(string targetPropertyName = null) { TargetPropertyName = targetPropertyName; } }
然后给你的Audited类属性加上这个标记:
public class Audited { public virtual int Id{ get; set; } [SyncToSummary("AuditedFieldName")] // 指定Summary里对应的属性名 public virtual string FieldName{ get; set; } [SyncToSummary] // 如果属性名一致,可省略参数 public virtual string FieldValue{ get; set; } }
接下来在数据持久化逻辑里(比如Repository的Save方法)处理同步:
public void SaveAudited(Audited audited) { // 先保存Audited到自身表 _auditedRepository.Save(audited); // 生成对应的Summary对象 var summary = new Summary(); // 反射获取所有带SyncToSummaryAttribute的属性 var properties = typeof(Audited).GetProperties() .Where(p => Attribute.IsDefined(p, typeof(SyncToSummaryAttribute))); foreach (var prop in properties) { var attr = prop.GetCustomAttribute<SyncToSummaryAttribute>(); // 获取目标属性名,默认和原属性名一致 var targetPropName = string.IsNullOrEmpty(attr.TargetPropertyName) ? prop.Name : attr.TargetPropertyName; var targetProp = typeof(Summary).GetProperty(targetPropName); if (targetProp != null) { // 复制属性值 targetProp.SetValue(summary, prop.GetValue(audited)); } } // 保存Summary到对应表 _summaryRepository.Save(summary); }
方案2:用映射工具简化赋值(比如AutoMapper)
如果你的项目已经在用AutoMapper这类映射工具,直接配置映射规则会更简洁,不用手写反射逻辑。
先配置Audited到Summary的映射:
public class MappingProfile : Profile { public MappingProfile() { CreateMap<Audited, Summary>() .ForMember(dest => dest.AuditedFieldName, opt => opt.MapFrom(src => src.FieldName)) .ForMember(dest => dest.FieldValue, opt => opt.MapFrom(src => src.FieldValue)) // 其他不需要同步的属性可以忽略 .ForMember(dest => dest.Id, opt => opt.Ignore()); } }
然后在保存的时候直接映射:
public void SaveAudited(Audited audited) { _auditedRepository.Save(audited); var summary = _mapper.Map<Summary>(audited); // 补充Summary的其他必要属性 summary.CreatedTime = DateTime.Now; _summaryRepository.Save(summary); }
方案3:领域层封装同步逻辑
如果想把同步逻辑内聚在领域对象里,让业务逻辑更清晰,可以给Audited类加一个生成Summary的方法:
public class Audited { public virtual int Id{ get; set; } public virtual string FieldName{ get; set; } public virtual string FieldValue{ get; set; } // 生成对应的Summary对象 public Summary GenerateSummary() { return new Summary { AuditedFieldName = this.FieldName, FieldValue = this.FieldValue, AuditedId = this.Id // 关联原Audited的ID }; } }
然后在业务层调用:
public void ProcessAudited(Audited audited) { _auditedRepository.Save(audited); var summary = audited.GenerateSummary(); _summaryRepository.Save(summary); }
这几种方案各有优劣:
- 自定义特性适合需要灵活配置的场景,后期改同步属性只需要加标记就行
- AutoMapper适合已有映射工具的项目,减少重复代码
- 领域层封装适合强调领域逻辑内聚的DDD项目,让对象自己负责生成关联对象
你可以根据自己项目的实际情况选~
内容的提问来源于stack exchange,提问作者Mohammad Shadmehr
相关产品推荐
相关产品推荐

