Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Purpose of IAggregateRoot interface in in Microsoft Repository Pattern document

I am looking at the Respository Pattern in Microsoft website.

Respository Pattern

I section i am not understand what IAggregateRoot does?

public interface IRepository<T> where T : IAggregateRoot
    {
        //....
    }

Can each respository class interact each others e.g. Product respository may be used by OrderRespository.

like image 345
LittleFunny Avatar asked Dec 11 '22 00:12

LittleFunny


1 Answers

TL;DR:

The IAggregateRoot interface doesn't really do anything except mark classes that are aggregate roots so that if a class doesn't implement that interface,

public class Repository<NotARootAggregate> : IRepository<NotARootAggregate>

...won't compile. It helps us not to create a repository for a class that isn't an aggregate root.


That generic constraint is just a way of preventing the creation of repository for something that isn't an aggregate root.

What is an aggregate root and why does it matter when we're creating a repository? Here's a really contrived example:

public interface IAggregateRoot { }

public enum TreeType
{
    Apple, Lemon
}

public class Fruit
{
    public Fruit(TreeType fruitType) { FruitType = fruitType; }

    public TreeType FruitType { get; }
}

public class TreeBranch
{
    private List<Fruit> fruitOnBranch = new List<Fruit>();

    public TreeBranch(TreeType branchType) { BranchType = branchType; }

    public TreeType BranchType { get; }

    public void AddFruit(Fruit fruit)
    {
        if (fruit.FruitType != BranchType)
        {
            throw new ArgumentException("Wrong type of fruit!");
        }
        fruitOnBranch.Add(fruit);
    }
}

public class Tree : IAggregateRoot
{
    private List<TreeBranch> branches = new List<TreeBranch>();

    public Tree(TreeType treeType) { TreeType = treeType; }

    TreeType TreeType { get; }

    public void AddBranch(TreeBranch branch)
    {
        if(branch.BranchType != TreeType)
        {
            throw new ArgumentException("Wrong type of branch!");
        }
        branches.Add(branch);
    }
}

It's designed so that it's impossible to add the wrong kind of branch to a tree or the wrong kind of fruit to a branch. So it's impossible to add a lemon to an apple tree. It's also impossible to change a lemon into an apple. The code enforces the rule that the right fruit grows on the right tree.

Having the tree as the aggregate root means that we're only going to save the tree to the database along with its branches and fruit. We'll never save just the branches or fruit. As long as we enforce that, we won't accidentally add lemons to apple trees.

If we defined a FruitRepository then we could accidentally go around that and save incorrect fruit.

So declaring the repository with that generic constraint:

public interface IRepository<T> where T : IAggregateRoot
                                ^^^^^^^^^^^^^^^^^^^^^^^^

means that a class that implements the interface won't compile unless T implements IAggregateRoot.

So the only purpose of IAggregateRoot is to mark a class and say, "This is an aggregate root. It's okay to define a repository for it." That's why the documentation you referenced calls it a "marker interface."

It's a little bit weird because you could just put that interface on Fruit or TreeBranch, and then you'd be able to create a repository for them. Nothing will stop you from doing that. But the idea is that you or someone else will know not to do that. (But if you already knew not to do that, then you didn't need the IAggregateRoot interface to stop you from creating the repository, right?) So it's a slightly weak guard against making a mistake.

like image 188
Scott Hannen Avatar answered Apr 09 '23 19:04

Scott Hannen