如何实现通用多表记录添加方法以遵循DRY原则?
用泛型+接口实现DRY原则解决重复代码问题
你的核心问题是重复逻辑被硬编码在不同类型的方法中,泛型+统一接口是最直接的解决方案,既保证类型安全,又能彻底消除重复代码。
1. 定义统一接口,规范实体公共属性
首先给所有需要处理的实体(MyClass、MyClass1等)定义一个公共接口,确保它们都包含Version和Id属性:
public interface IVersionedEntity { int Version { get; set; } int Id { get; set; } } // 让你的实体实现这个接口 public class MyClass : IVersionedEntity { public int Version { get; set; } public int Id { get; set; } // 其他属性... } public class MyClass1 : IVersionedEntity { public int Version { get; set; } public int Id { get; set; } // 其他属性... }
2. 泛型实现「获取最新版本记录」方法
利用EF Core的_context.Set<T>()获取对应实体的DbSet,替代硬编码的DataTable:
public IEnumerable<T> GetRecordsWithLastVersion<T>() where T : class, IVersionedEntity { var records = _context.Set<T>().ToList(); // 获取最高版本记录的通用逻辑 int maxVersion = records.Max(r => r.Version); return records.Where(r => r.Version == maxVersion).ToList(); }
3. 泛型实现「添加新版本记录」方法
同样用泛型处理映射、版本号递增、Id递增逻辑,AutoMapper也支持泛型映射:
// 建议把IMapper通过依赖注入注入,不要每次创建新实例(优化性能) private readonly IMapper _mapper; public YourService(IMapper mapper, YourDbContext context) { _mapper = mapper; _context = context; } public void AddVersionedRecords<T>(IEnumerable<T> recordsToAdd) where T : class, IVersionedEntity { // 获取当前表的最大Id(只查一次,避免循环中重复查询) int maxId = _context.Set<T>().Max(r => r.Id); foreach (var record in recordsToAdd) { // 泛型映射生成新记录 var newRecord = _mapper.Map<T, T>(record); // 统一处理版本号和Id递增 newRecord.Version = record.Version + 1; newRecord.Id = ++maxId; _context.Set<T>().Add(newRecord); } _context.SaveChanges(); }
4. 配置AutoMapper泛型映射
在AutoMapper的启动配置中,为所有实现IVersionedEntity的类型添加映射(或直接注册单个类型):
// 在Startup/Program.cs中配置 services.AddAutoMapper(cfg => { // 注册单个类型的映射 cfg.CreateMap<MyClass, MyClass>(); cfg.CreateMap<MyClass1, MyClass1>(); // 或者用反射批量注册所有实现IVersionedEntity的类型 var entityTypes = typeof(IVersionedEntity).Assembly.GetTypes() .Where(t => typeof(IVersionedEntity).IsAssignableFrom(t) && !t.IsInterface); foreach (var type in entityTypes) { cfg.CreateMap(type, type); } });
5. 调用示例
现在只需要一行代码就能处理不同类型的实体:
// 处理MyClass var myClassLatestRecords = GetRecordsWithLastVersion<MyClass>(); AddVersionedRecords(myClassLatestRecords); // 处理MyClass1 var myClass1LatestRecords = GetRecordsWithLastVersion<MyClass1>(); AddVersionedRecords(myClass1LatestRecords);
为什么这比你尝试的反射方法更好?
- 类型安全:编译时就能检查类型错误,避免反射带来的运行时异常
- 代码简洁:无需手动传递
Type参数,逻辑更清晰 - 性能更优:泛型是编译时生成代码,比反射的运行时调用效率更高
内容的提问来源于stack exchange,提问作者AdamMarty2000
相关产品推荐
相关产品推荐

