Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid circular reference in domain model

this must be such a common scenario that there's been a lot written about it already, hopefully even a really good pattern. I have a domain model in which a custom container contains entities. For example (properties and interfaces excluded for brevity):

class Entity
{
    public int Id;
    public EntityContainer ParentContainer;
}


class EntityContainer
{
    public int Id;
    public IList<Entity> Entities = new List<Entity>();

    public void AddEntity(Entity entity)
    {
        entity.ParentContainer = this;
        Entities.Add(entity);
    }
}


class Main
{
    public Main()
    {
        Entity entity1 = new Entity();
        Entity entity2 = new Entity();
        EntityContainer entityContainer = new EntityContainer();
        entityContainer.AddEntity(entity1);
        entityContainer.AddEntity(entity2);

        // Can now traverse graph easily, e.g.
        Console.WriteLine("entity1's parent container ID = " + entity1.ParentContainer.Id);
        Console.WriteLine("Container contains at least this entity ID: " + entityContainer.Entities[0].Id);

    }
}

I can now easily traverse my object graph both ways, but have created a circular reference. Would you create a third type to divorce the dependencies?

Thanks in advance

like image 283
ng5000 Avatar asked May 28 '09 10:05

ng5000


People also ask

How can circular dependencies be avoided?

Circular dependencies can be introduced when implementing callback functionality. This can be avoided by applying design patterns like the observer pattern.

What is wrong with circular references?

The circular reference error message "There are one or more circular references where a formula refers to its own cell either directly or indirectly. This might cause them to calculate incorrectly. Try removing or changing these references, or moving the formulas to different cells."


3 Answers

There's nothing wrong with circular references, per se, and they are used extensively in the .NET Framework, e.g. XmlNode.OwnerDocument, Control.Parent.

If you need to traverse up the tree, then a back reference is fine to use.

In COM, circular references are tricky because if you were the set the container and all its children to nothing, then objects will not be cleaned up properly as the children still hold references to the parent. However the .NET garbage collection has no problem with this the way it is implemented.

like image 158
Patrick McDonald Avatar answered Oct 11 '22 07:10

Patrick McDonald


Does the container need to know about the type of the contents? If not, generics can avoid this - i.e. Container<T>, where you happen to use Container<Entity>. Other than that; pushing the necessary details into an interface (or base-class) in an assembly that both can reference is a common approach.

Personally, I'd try to simply avoid the need for the child to know about the parent.

Also; note that if you do go down the abstraction (interface etc) route; this can have a big implication if you are using (for example) xml serialization.


(edit re comments) OK; first: what problem is the circular reference (within an assembly) causing; if none, leave it alone. If there is a problem, then you'll need an extra type; presumably some interfaces to represent the concrete types - i.e. where Entity : IEntity, and EntityContainer only knows about IEntity (or vv with IEntityContainer, or both),

like image 43
Marc Gravell Avatar answered Oct 11 '22 07:10

Marc Gravell


Using circular referenced objects is ok in my book providing you are using some kind of lazy-loading pattern when designing those objects.

e.g.

You want to access: Company.Employee And in another scenario: Employee.Company

Which makes a circular reference i.e. Company.Employee.Company.Employee etc.

If these properties are not lazy-loaded e.g. A Company object always loads its Employee property and the Employee object always loads its Company property then it aint gonna work too well when you introduce a data source.

like image 1
iandayman Avatar answered Oct 11 '22 08:10

iandayman