.NET EF - 如何使用 Clean Architecture 方法避免不同数据库上下文中相同模型的代码重复

.NET EF - how to avoid code duplication for identical models in different db contexts using Clean Architecture approach



我正在为多租户、基于 .NET 6 的应用程序构建 Web API 后端,我遇到了一个架构问题,自从过去几周以来这让我发疯,所以我非常感谢任何提示和建议.
整个解决方案构建在经典的 Clean Architecture(层:API、域、应用程序、基础设施、共享)中,这不是我认为的最好的想法,但我相信它现在是不可逆转的。无论如何,我想努力保存我迄今为止所创造的一切。

在应用程序中我有 2 个数据库(后面的代码中有 Entity Framework): 数据库 A:租户用户范围 - 每个 table 中的 TenantId 字段用于在 SQL 级别上实施的 RLS 机制,以防止租户间数据泄漏 数据库 B:内部用户范围 - 无 RLS 机制

问题是两个数据库共享大量共同的结构和逻辑。
当前模型(数据库和域)的简化示例:
数据库 A:

public class TenantEmployee {
  public Guid Id {get; protected set;}
  public string Name {get; protected set;}
  public string DepartmentId {get; protected set;}

  public void SetName(string name) { ... }
  public void SetDepartment(string id) { ... }
  public int GetWorkingHours() { ... }
}

数据库 B:

public class InternalEmployee {
  public Guid Id {get; protected set;}
  public string Name {get; protected set;}
  public string DepartmentId {get; protected set;}

  public void SetName(string name) { ... }
  public void SetDepartment(string id) { ... }
  public int GetWorkingHours() { ... }
}

目前,使用 CQRS (MediatR) 我必须实现如下逻辑:



这样我创建了很多代码重复。 我不想为那些 类 创建通用接口,因为我认为这可能会在未来某个时候扼杀应用程序的开发(模型随时可能会变得有点不同)。

有一个在基础设施层创建贫血数据库模型的想法,就像这样

internal class TenantEmployee {
  public Guid Id {get; set;}
  public string Name {get; set;}
  public string DepartmentId {get; set;}
}
internal class InternalEmployee {
  public Guid Id {get; set;}
  public string Name {get; set;}
  public string DepartmentId {get; set;}
}

然后像这样创建公共领域模型(在领域层):

public class Employee {
  public Guid Id {get; protected set;}
  public string Name {get; protected set;}
  public string DepartmentId {get; protected set;}

  public void SetName(string name) { ... }
  public void SetDepartment(string id) { ... }
  public int GetWorkingHours() { ... }
}

在这种方法中,我可以将域逻辑放在一个地方并使用通用存储库模式,该模式接受输入和输出的域模型以及将域模型映射到数据库模型并返回的内部存储库逻辑。这种解决方案在某些方面仍然给我留下了代码重复,但我想它可以让我在应用程序和域层中防止它。

不过,我想确保我没有错过任何更好的解决方案。

This way I'm creating a lot of code duplication. I do not want to create common interfaces for those classes because I think this may kill the application's development in some point in the future (Models may become a little bit different anytime).

如果你有太多重复,你认为应该合并你的代码是正确的。如果两个模型都应该能够有共同的代码,特定的代码,那么你的问题的解决方案可能是多态性

我建议有两个新的 classes Domain.TenantEmployeeDomain.InternalEmployee 都继承自抽象 Domain.Employee。您可以将常见行为放在父 class 中,将特定行为放在子行为中。

然后你的基础设施层可以转换Domain.TenantEmployeefrom/toDatabaseA.TenantEmployeeDomain.InternalEmployeefrom/toDatabaseB.InternalEmployee.