C
C#this hour
sonodan.

Controlling state changes from the root object

Hey all. I have the following structure of objects, which basically consists of a PhaseHolder, which contains a collection of Phase. Each Phase can hold a Comment, and each Comment can hold a list of Reply.
public class PhaseHolder
{
private readonly List<Phase> _phases = new();

public IReadOnlyCollection<Phase> Phases => _phases.AsReadOnly();

public bool IsCommentable { get; set; }

public void AddPhaseComment(string comment)
{
var phase = _phases.First();

if (IsCommentable)
{
phase.AddComment(comment);
}
}

public void AddPhase()
{
_phases.Add(new Phase());
}
}

public class Phase
{
private readonly List<Comment> _comments = new();

public IReadOnlyCollection<Comment> Comments => _comments.AsReadOnly();

public void AddComment(string comment)
{
_comments.Add(new Comment(comment));
}
}

public class Comment
{
private readonly List<Reply> _replies = new();

public IReadOnlyCollection<Reply> Replies => _replies.AsReadOnly();

public string Description { get; set; }

public Comment(string comment)
{
Description = comment;
}

public void AddReply(string reply)
{
_replies.Add(new Reply(reply));
}
}

public class Reply
{
internal string Description { get; set; }

public Reply(string description)
{
Description = description;
}
}
public class PhaseHolder
{
private readonly List<Phase> _phases = new();

public IReadOnlyCollection<Phase> Phases => _phases.AsReadOnly();

public bool IsCommentable { get; set; }

public void AddPhaseComment(string comment)
{
var phase = _phases.First();

if (IsCommentable)
{
phase.AddComment(comment);
}
}

public void AddPhase()
{
_phases.Add(new Phase());
}
}

public class Phase
{
private readonly List<Comment> _comments = new();

public IReadOnlyCollection<Comment> Comments => _comments.AsReadOnly();

public void AddComment(string comment)
{
_comments.Add(new Comment(comment));
}
}

public class Comment
{
private readonly List<Reply> _replies = new();

public IReadOnlyCollection<Reply> Replies => _replies.AsReadOnly();

public string Description { get; set; }

public Comment(string comment)
{
Description = comment;
}

public void AddReply(string reply)
{
_replies.Add(new Reply(reply));
}
}

public class Reply
{
internal string Description { get; set; }

public Reply(string description)
{
Description = description;
}
}
The PhaseHolder object contains a bool property that should control adding comments, but this can be avoided:
var phaseHolder = new PhaseHolder();
phaseHolder.AddPhase();
phaseHolder.AddPhaseComment("Adding comment in desired way");
var phase = phaseHolder.Phases.FirstOrDefault();
phase?.AddComment("Avoiding IsCommentable check");
var phaseHolder = new PhaseHolder();
phaseHolder.AddPhase();
phaseHolder.AddPhaseComment("Adding comment in desired way");
var phase = phaseHolder.Phases.FirstOrDefault();
phase?.AddComment("Avoiding IsCommentable check");
I could create an read-only IPhase interface , but these models also serve as my EF core models, which need a concrete type, e.g. IReadOnlyCollection<Phase>
1 Reply
becquerel
becquerel7h ago
this is plausibly something you could prevent at the database level with a constraint or a trigger or at the EF level by overriding one of its methods (interceptors etc) but more generally this feels like a case where it would be worth separating your ef models from your domain objects if you want to enforce this business concern in code load your data with the ef models, immediately map them to in-app only classes which uphold this variant more strongly (runtime exceptions perhaps, or other methods - maybe nested classes would let the phaseholder control access to the phase comments) i'm not familiar with DDD but it sounds like you essentially want your phase holder to be an aggregate root, so it may be worth looking up strategies DDD people use for implementing those
Want results from more Discord servers?
Add your server