I’m asking myself on how to build a parent/child relation in a correct way.
First, the context…
I have two content entities, associated with two config entities. The parent entity is called “Exchange” and the child entity is “Exchange item”.
“exchange item” is bundle of exchange_item_type, allowing to build exchange items of multiples types, like “ask a question”, “refuse to answer”, “answer the question”, “give details”, “validate answer”.
The “exchange” is the parent entity who “hold” exchange items.
The goal is to build a system that allow (left) entities (ie users) starting an “exchange” and use a workflow to discuss with another (right) entity.
Example : User A initiate an exchange with User B and “ask a question”. User B can “refuse to answer” or “answer the question”. If he “refuse to answer”, the exchange is marked as finished. If he “answer the question”, User B can “give details” or “validate answer”. If User B “give details”, User A can “refuse to answer” or “answer the question”, …
I built the exchange_item (content) and exchange_item_type (config) entities, but actually I’m not sure how to create the relation between exchange_item and exchange entities.
Two solutions :
The exchange has an entity_reference field with cardinality = unlimited to store each exchange_item related to.
the exchange_item has an entity_reference field with cardinality = 1 to store the parent exchange related to.
What are pro and cons using the first or the second solution ? What is the default way usually taken to do this kind of relation ? I know that both solutions can be implemented, but maybe one is better than the other…
Thanks in advance for any answer pointing useful information.
To establish a parent/child relationship between the “Exchange” and “Exchange Item” entities in Drupal, let’s explore the two possible solutions you’ve mentioned, along with their pros and cons, and decide which is the most appropriate based on your use case.
Option 1: Parent (Exchange) has an entity_reference field (unlimited cardinality) referencing multiple exchange_items.
In this approach, the “Exchange” entity would contain an entity_reference field with unlimited cardinality, which references multiple “Exchange Item” entities (child entities). Each “Exchange” entity can hold references to as many “Exchange Items” as needed.
Pros:
Logical grouping: The “Exchange” entity becomes the holder of its “Exchange Items.” It feels natural to think of an exchange as a collection of items, and having them listed in the parent entity is clear and accessible.
Easy querying: When fetching the “Exchange” entity, you can easily access all its related “Exchange Items” through the entity reference field. It simplifies querying, as you can get everything in one go.
Less duplication: You avoid repeating the reference to the parent entity inside each “Exchange Item.” Instead, the parent holds the collection of children.
Better overview: Administrators can more easily manage and track the entire exchange conversation from the parent entity without needing to query individual items.
Cons:
Field storage limit: Depending on the number of “Exchange Items” that can be created for each “Exchange,” the entity_reference field may reach its cardinality or performance limit if there are too many items. However, this issue is rare unless the volume of data is substantial.
More complex workflows: If your workflow involves dynamic updates to individual “Exchange Items,” modifying the child entities individually while maintaining their reference from the parent entity could be more complex.
Option 2: Child (Exchange Item) has an entity_reference field (cardinality = 1) referencing the parent (Exchange).
In this approach, the “Exchange Item” entity would have an entity_reference field (with cardinality = 1), which points back to the parent “Exchange” entity. Each “Exchange Item” will store its parent exchange.
Pros:
Scalability: If the number of “Exchange Items” per “Exchange” is large, this approach scales better because you avoid having a parent entity that stores references to many children. Instead, the children each hold a single reference to the parent.
Simpler item-level operations: If the workflow involves frequent interactions with individual “Exchange Items” (such as updating or deleting them), this approach might feel more natural since you’re primarily working with the items directly, each of which has a clear reference to its parent.
Flexibility: If your workflow involves handling “Exchange Items” independently from the parent “Exchange,” this method gives you more flexibility, as each “Exchange Item” can be queried or updated without modifying the parent.
Cons:
Harder to query from parent: To retrieve all “Exchange Items” belonging to an “Exchange,” you would need to perform additional queries (for example, fetching all child entities where the reference field points to the parent). This adds complexity when trying to display or manage all items associated with a specific exchange.
Fragmented view: If you’re administrating from the “Exchange” entity, it can be harder to get a complete view of all its associated items since they are stored and referenced individually. This could make managing exchanges more difficult.
Relationship data spread across entities: You end up spreading the parent-child relationship across multiple entities, which could make workflows or logic around the exchange less obvious and more challenging to track.
Considerations and Best Practices:
Cardinality and Scale: If you’re expecting a large number of “Exchange Items” per “Exchange,” Option 2 (having the child reference the parent) might be more scalable. However, if the number of items per exchange is moderate, Option 1 (having the parent hold references) might be simpler and more efficient.
Primary Interaction Level: Consider where the majority of your interaction happens. If you’re mostly managing or interacting with exchanges at the “Exchange” entity level, Option 1 makes more sense. However, if your primary interaction is with individual “Exchange Items,” then Option 2 might be more intuitive.
Query Complexity: Option 1 simplifies querying when you need to retrieve all “Exchange Items” for an “Exchange.” Option 2 requires more complex queries to gather all items related to a specific exchange.
Performance: In general, Option 2 may offer better performance at scale, as each “Exchange Item” is responsible for storing its own relationship. Option 1 might suffer if there are a very large number of child items per parent.
Recommendation:
For most typical use cases, where the number of “Exchange Items” per “Exchange” is moderate, and you’re primarily interacting with exchanges as a whole, Option 1 (Parent holds entity references) is likely the better choice. It simplifies querying, offers a more logical data structure, and provides an easier workflow for managing the overall exchange.
However, if you’re dealing with high scalability and expect a large number of “Exchange Items” per “Exchange,” or if you frequently need to manage items independently, then Option 2 (Child holds a reference to the Parent) could be more appropriate.
Choose based on your anticipated scale and interaction patterns!