You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现通用多表记录添加方法以遵循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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 12:05:33