0

i'm stuck with this problem while designing aggregates in a DDD project.

Please consider the following scenario:

public abstract class BaseAppType{ 
public abstract int GetUserOwnerId(); 
public List<AppTypeHost> Hosts {get;set;} = new List<AppTypeHost>()
}

public class PersonalAppType:BaseAppType //this is an aggregate root
{
    public int override GetUserOwnerId(){ return Hosts.Select(h=>h.UserId).Single(); }
}

public class TeamAppType:BaseAppType //this is another aggregate root
{
    publi int TeamOwnerId {get;set;} 
    public int override GetUserOwnerId(){ //this is much harder becase i don't have the info in the object }
} 

public class Team {
    public List<TeamMember> TeamMembers = new List<TeamMember>();
}

public class TeamMember {
    public int TeamId {get;set;}
    public int UserId {get;set;}
    public TeamMemberRole Role {get;set;} //this might be either Owner or Member
}

So basically i've two types of appointments that share common info, functionality and shape via a root class.

Now i've to implement GetUserOwnerId in the two derived class, which are two distinct aggregates root.

In the PersonalAppType it is kind of easy because the information of the userOwner is within one of the entity of the aggregate so i simply query the object in memory and return it.

In the TeamAppType it is more diffuclt because the information is in another aggregate root ( basically for my business rules, the owner of the TeamAppType is the Owner of the Team AggregateRoot).

Since Team is another AggregateRoot i could not load it into the TeamAppType aggregate and i pretty stuck...

I've tried:

the route of injecting a service in the TeamAppType so that i can call it within the GetUserOwnerId but i don't like it because it feel "wrong" to inject a service within a domain constructor and it is kind of hard because when i retrieve the aggregate root from ef core, it doesn't inject the service ( because it uses the default construcor with 0 params )

I've also tried the route of doing it in a domain service, something like this:

public class AppTypeOwnerResolverService{
    public int GetUserOwnerId (BaseAppType appType)
    {
        switch (appType.GetType())
        {
        case "PersonalAppType":
            //retrieve owener of PersonalAppType
        break
        
        case "TeamAppType":
            //retrieve owener of TeamAppType
        break
        
        }
    }
}

but it feels off because it looks like the GetUserOwnerId should stay within the inherited class and this reduces the benefits of polymorfism.

Do you have any suggestion on how to approach this problem?

Thanks to everyone for the help.

Ale
  • 43
  • 4

1 Answers1

0

Another option would be to have a Team aggregate emitting domain events, (i.e. TeamOwnerAssigned) and having a domain event handler that modifies the TeamAppType aggregate based on this event.

pgorecki
  • 639
  • 6
  • 8
  • Hi, thanks for your help. Do you mean saving the information about who is the owner within the TeamAppType and updating it via events evry time the team owner is changed? Yes, this might work. Im not in love with this solution because i prefer to have only one "source of truth" but this might work. Let's see if there are other options also – Ale Feb 01 '23 at 22:37
  • Yes, this is what I mean. another solution I like is the domain service you already proposed. I'd add `public int override GetUserOwnerId(AppTypeOwnerResolver resolver) { return resolver.resolve(this) }` to a base class and implement `PersonalAppTypeResolver` and `TeamAppTypeResolver` to handle both cases. – pgorecki Feb 02 '23 at 07:59