Avoid circular references in the domain model

It should be such a common scenario that much has already been written about this, I hope even a very good example. I have a domain model in which a custom container contains objects. For example (properties and interfaces are 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, eg Console.WriteLine("entity1 parent container ID = " + entity1.ParentContainer.Id); Console.WriteLine("Container contains at least this entity ID: " + entityContainer.Entities[0].Id); } } 

Now I can easily cross the graph of objects in both directions, but created a circular link. Are you creating a third type for dependency divorce?

Thanks in advance

+7
design c # design-patterns domain-driven-design
source share
4 answers

There is nothing wrong with circular links as such, and they are widely used in the .NET Framework, for example. XmlNode.OwnerDocument, Control.Parent.

If you need to go through a tree, then the back link will be useful for use.

In COM, circular references are complex because if you were set up for the container and all its children in no way, the objects will not be cleaned up properly, since children still keep references to the parent. However, .NET garbage collection does not present a problem with how it is implemented.

+4
source share

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

Personally, I would just try to avoid the need to know the child about the parent.

Also; note that if you are following the route of abstraction (interface, etc.); this can make a big difference if you use (for example) XML serialization.


(edit comments) OK; firstly: what problem is the circular link (inside the assembly); if not, leave him alone. If there is a problem, you will need an additional type; presumably some interfaces for representing specific types - i.e. where Entity : IEntity , and EntityContainer knows only about IEntity (or vv with IEntityContainer or both)

+2
source share

This way, I don't see a problem with your class model, but you can easily make a clean slice. Make Entity implement the IEntity interface and force the EntityContainer to hold the IList, and if you have no specific reason to use IList, you should consider IEnumerable, this will make it easier for you to use the EntityClass you use. Since any IEntity array is passed, or a linq expression that selects IEntities is possible [/ p>

+1
source share

The use of circular reference objects in my book is fine if you use some kind of lazy loading pattern when designing these objects.

eg.

Do you want to access: Company.Employee And in another scenario: Employee.Company

What makes a circular link, i.e. Company.Employee.Company.Employee , etc.

If these properties are not lazy, for example, a Company object always loads its Employee property, and an Employee object always loads its company property, then it will not work too well when you enter a data source.

+1
source share

All Articles