开发者

Complex business logic in repository

开发者 https://www.devze.com 2023-01-31 08:21 出处:网络
I have a method in a repository with a very complex business logic. I just read that there should be no business logic in a repository.

I have a method in a repository with a very complex business logic. I just read that there should be no business logic in a repository.

Removing the business logic from this method will require me to distribute the logic among two other repositories (because it involves two other entities).

Then my question is -what patte开发者_运维百科rn should I use to implement this complex logic? It will need to consume these three repositories, but I cannot place it in a controller because I need to reuse it. Thank you for your help.


Complex business logic usually goes into a service layer. A service may depend on one or more repositories to perform CRUD operations on your models. Thus a single service operation representing a business operation may depend on multiple simple operations. Then you could reuse this service layer in your controllers and other applications.

Obviously your service shouldn't depend on specific repository implementations. In order to provide a weaker coupling between the service layer and the repositories you could use interfaces. Here's an example:

public interface IProductsRepository { }
public interface IOrdersRepository { }
...

public interface ISomeService 
{
    void SomeBusinessOperation();
}

public class SomeServiceImpl: ISomeService
{
    private readonly IProductsRepository _productsRepository;
    private readonly IOrdersRepository _ordersRepository;

    public SomeServiceImpl(
        IProductsRepository productsRepository, 
        IOrdersRepository ordersRepository
    )
    {
        _productsRepository = productsRepository;
        _ordersRepository = ordersRepository;
    }

    public void SomeBusinessOperation()
    {
        // TODO: use the repositories to implement the business operation
    }
}

Now all that's left is configure your DI framework to inject this specific service into your controller.

public class FooController : Controller
{
    private readonly ISomeService _service;
    public FooController(ISomeService service)
    {
        _service = service;
    }

    public ActionResult Index()
    {
        // TODO: Use the business operation here.
    }
}

You can see how interfaces allow us to provide weak coupling between the layers. All the plumbing is performed by the DI framework and everything is transparent and easily unit testable.


I would use a domain driven design approach. A very good book on DDD is the following: .NET Domain-Driven Design with C#: Problem-Design-Solution. Look also for Fowlers Enterprise Patterns and Evans Domain Driven Design books. The basic idea is that a repository is basically infrastructure. All the domain logic goes into your model.

Example a repository method looks like this:

public void InsertAddresse(Company company)
{
    foreach (Address address in company.Addresses)
    {
        this.InsertAddress(address, company.Key, (company.HeadquartersAddress == address));
    }
}

On the other hand a model object looks like this:

public class Contact : Person, IAggregateRoot, IHasAddresses
{
    private string jobTitle;
    private string email;
    private string phoneNumber;
    private string mobilePhoneNumber;
    private string faxNumber;
    private string remarks;
    private Company currentCompany;
    private IList<Address> addresses;

    public Contact()
        : this(null)
    {
    }

    public Contact(object key)
        : this(key, null, null)
    {
    }

    public Contact(object key, string firstName, string lastName) 
        : base(key, firstName, lastName)
    {
        this.jobTitle = string.Empty;
        this.email = string.Empty;
        this.phoneNumber = string.Empty;
        this.mobilePhoneNumber = string.Empty;
        this.faxNumber = string.Empty;
        this.remarks = string.Empty;
        this.currentCompany = null;
        this.addresses = new List<Address>();
    }

    public string JobTitle
    {
        get { return this.jobTitle; }
        set { this.jobTitle = value; }
    }

    public string Email
    {
        get { return this.email; }
        set { this.email = value; }
    }

    public string PhoneNumber
    {
        get { return this.phoneNumber; }
        set { this.phoneNumber = value; }
    }

    public string MobilePhoneNumber
    {
        get { return this.mobilePhoneNumber; }
        set { this.mobilePhoneNumber = value; }
    }

    public string FaxNumber
    {
        get { return this.faxNumber; }
        set { this.faxNumber = value; }
    }

    public string Remarks
    {
        get { return this.remarks; }
        set { this.remarks = value; }
    }

    public Company CurrentCompany
    {
        get { return this.currentCompany; }
        set { this.currentCompany = value; }
    }

    public IList<Address> Addresses
    {
        get { return this.addresses; }
    }

    protected override void Validate()
    {
        //some logic here
    }

    protected override BrokenRuleMessages GetBrokenRuleMessages()
    {
        return new ContactRuleMessages();
    }
}


I think your super repository just break Single Responsibility Principle. I would leave repository as simple as possible (KISS pattern ;), and would create other layer between controllers and repository, e.q. business layer.

To reuse and simplify the code have a look at Dependency Injection (implement IoC)

Actually I would suggest to have a look at SOLID principles.

0

精彩评论

暂无评论...
验证码 换一张
取 消