仓库/服务模式问题 .NET Core

huangapple go评论58阅读模式
英文:

Repository/Service Pattern Issues .NET Core

问题

我有一些架构问题,正在努力解决。我需要找到更好的方法来完成我的目标。

以下是我的服务/存储库的简要示意图。我的问题是在激活它们时出现了循环引用。问题在于每个服务中都有我需要的代码,例如在LoadService中,我可能需要触发CustomerService中的方法,反之亦然。

需要帮助理解这里的最佳方法。我正在尽量将这些服务分离职责原则(SRP)。

LoadRepository

public class LoadRepository 
{
    private readonly DBContext _DBContext;

    public LoadRepository(DBContext DBContext)
    {
        _DBContext = DBContext;
    }

    public override DbSet<LoadEntity> LoadDbSet()
    {
        return _DBContext.Load;
    }
}

LoadService

public class LoadService 
{
    private readonly LoadRepository _loadRepository;
    private readonly ICustomerService _customerService;

    public LoadService(
        LoadRepository loadRepository,
        ICustomerService customerService
    ) 
    {
        _loadRepository = loadRepository;
        _customerService = customerService;
    }    
}

CustomerRepository

public class CustomerRepository 
{
    private readonly DBContext _DBContext;

    public CustomerRepository(DBContext DBContext)
    {
        _DBContext = DBContext;
    }

    public override DbSet<CustomerEntity> LoadDbSet()
    {
        return _DBContext.Customer;
    }
}

CustomerService

public class CustomerService 
{
    private readonly CustomerRepository _customerRepository;
    private readonly ILoadService _loadService;

    public CustomerService(
        CustomerRepository customerRepository,
        ILoadService loadService
    ) 
    {
        _customerRepository = customerRepository;
        _loadService = loadService;
    }    
}
英文:

Having some architecture issues that I'm trying to work through. I need to find a better way to do what I'm trying to do.

Below is a brief mockup of how my services/repos look. My problem is I am getting a circular reference when activating them. The problem is there is code in each service that I need for example in the LoadService I may need to trigger a method in the CustomerService and vice versa.

Need help to understand the best approach here. I am trying to get these services in a SRP as much as possible.

LoadRepository

public class LoadRepository 
{
    private readonly DBContext _DBContext;

    public LoadRepository(DBContext DBContext)
    {
        _DBContext = DBContext;
    }

    public override DbSet<LoadEntity> LoadDbSet()
    {
        return _DBContext.Load;
    }
}

LoadService

public class LoadService 
{
    private readonly LoadRepository _loadRepository;
    private readonly ICustomerService _customerService;

    public LoadService(
        LoadRepository loadRepository,
        ICustomerService customerService
    ) 
    {
        _loadRepository = loadRepository;
        _customerService = customerService;
    }    
}

CustomerRepository

public class CustomerRepository 
{
    private readonly DBContext _DBContext;

    public CustomerRepository(DBContext DBContext)
    {
        _DBContext = DBContext;
    }

    public override DbSet<CustomerEntity> LoadDbSet()
    {
        return _DBContext.Customer;
    }
}

CustomerService

public class CustomerService 
{
    private readonly CustomerRepository _customerRepository;
    private readonly ILoadService _loadService;

    public CustomerService(
        CustomerRepository customerRepository,
        ILoadService loadService
    ) 
    {
        _customerRepository = customerRepository;
        _loadService = loadService;
    }    
}

答案1

得分: 1

在我的个人经验中,最好避免相互引用相同级别的依赖关系。将常见功能移到一些辅助类中,或将所有所需的存储库注入到相应的服务中。例如:

public class LoadService 
{
    private readonly LoadRepository _loadRepository;
    private readonly CustomerRepository _customerRepository;

    public LoadService(
        LoadRepository loadRepository,
        CustomerRepository customerRepository
    ) 
    {
        _loadRepository = loadRepository;
        _customerRepository = customerRepository;
    }        
}

另一种减轻问题的方法(如果当前重构过于复杂)是使用惰性注入,例如通过使用工厂以 Func 作为参数:

// 默认的依赖注入不提供自动的 Func 注册
Services.AddScoped<Func<ICustomerService>>(sp => () => sp.GetRequiredService<ICustomerService>)
public class LoadService 
{
    private readonly LoadRepository _loadRepository;
    private readonly Func<ICustomerService> _customerServiceFactory;

    public LoadService(
        LoadRepository loadRepository,
        Func<ICustomerService> customerService
    ) 
    {
        _loadRepository = loadRepository;
        _customerServiceFactory = customerService;
    }   
}

当需要时,调用工厂 - _customerServiceFactory().SomeMethod()。请注意,这种方法可能会导致递归调用时栈溢出,例如 ICustomerService.Foo() 调用 ILoadService.Bar(),后者又调用 ICustomerService.Foo(),这种情况只能在运行时捕获到。

英文:

In my personal experience it is better to avoid dependencies on the same level referencing each other. Move common functionality into some helper classes and/or inject all needed repositories into the corresponding services. For example :

public class LoadService 
{
    private readonly LoadRepository _loadRepository;
    private readonly CustomerRepository _customerRepository;

    public LoadService(
        LoadRepository loadRepository,
        CustomerRepository customerRepository
    ) 
    {
        _loadRepository = loadRepository;
        _customerRepository = customerService;
    }        
}

Another approach to mitigate the problem (if currently refactoring is to much of headache) - use lazy injection via factories, for example something like the following using factory via Func:

// default DI does not provide automatic Func registration
Services.AddScoped&lt;Func&lt;ICustomerService&gt;&gt;(sp =&gt; () =&gt; sp.GetRequiredService&lt;&gt;(ICustomerService))
public class LoadService 
{
    private readonly LoadRepository _loadRepository;
    private readonly Func&lt;ICustomerService&gt; _customerServiceFactory;


    public LoadService(
        LoadRepository loadRepository,
        Func&lt;ICustomerService&gt; customerService
    ) 
    {
        _loadRepository = loadRepository;
        _customerServiceFactory = customerService;
    }   
}

And when it is needed invoke the factory - _customerServiceFactory().SomeMethod(). Though note that this method can result in SO if you have cycle in invocations (i.e. ICustomerService.Foo() calls ILoadService.Bar() which calls ICustomerService.Foo()) which can be caught only in runtime.

huangapple
  • 本文由 发表于 2023年2月18日 04:02:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/75488779.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定