0

I'm designing a database structure with some particular rules and I'm trying to define a proper data model, basically one that fits those rules.

There are 3 entities:

  1. Group (fields: subgroups, items ...)
  2. SubGroup (fields: group, items ...)
  3. Item (fields: enabled, description ...)

Those entities have relationships:

  • A SubGroup belongs to a Group (a Group owns several SubGroup)
  • An Item can belong to a Group, or a SubGroup (only one at a time)

And there are special rules:

  • An Item that belongs to a Group is inherited to all the related SubGroup
  • An Item that is inherited by a SubGroup from its Group can be overridden (I call it inheritance because that's how it feels, something that gets inherited by a parent and can be overridden or used as it is)
    • The main override use-case I have is with the enabled field, because we may want to disable an item coming by inheritance in some cases
  • Do not duplicate content (Items, in particular) in the DB (the inheritance should be done when querying the DB Model, at the application level)

This example is kept simple, but the reality is a bit more complex, there can be more "SubGroup" levels, like "SubSubGroup", so the structure should handle those gracefully as well


Attempt 1

At first, I imagined a traditional relationship:

enter image description here

And this would work fine if it wasn't for those "special rules". Because there is no way with this structure to override an inherited Item.

Therefore, I made a second attempt to handle those as well.


Attempt 2

I made another design attempt by using a kind of "proxy" table, basically a n-n relationship table named ItemOverride (the name is horrible but I haven't found anything better) in addition of the existing entities (Group, SubGroup and Item)

The entity ItemOverride contains the following fields:

  • ItemId
  • EntityType (Group or SubGroup)
  • EntityId (id related to the selected EntityType)

The entity ItemOverride extends the Item entity, so that it contains the same fields, allowing any field to be overridden.

Example of content in ItemsOverride table:

+--------+------------+----------+-----------------+---------------------+
| ItemId | EntityType | EntityId | Enabled         |    OverriddenHeight |
+--------+------------+----------+-----------------+---------------------+
|     1  | group      |        1 | true            | null                |
|     2  | group      |        2 | true            | 20                  |
|     3  | subgroup   |        1 | false           |                     |
+--------+------------+----------+-----------------+---------------------+

This design seems to provide the proper structure, I've added OverriddenWidth and OverriddenHeight to illustrate overridden fields. The point being to only store what's overridden and leave other values empty so that it relies on the actual Item entity to get those values.

But, I feel like it's getting much more complicated than it needs to be and I wonder if there isn't a better way to handle this.

Here are some potential pain points I can see with this structure:

  • If the entity ItemOverride inherits Item, then the fields which don't allow "null" will have to be set in the ItemOverride table, which will lead to a waste of space, duplicated content and other problems because it'll make it harder to see what's really overridden from what's inherited
  • If there is no inheritance between ItemOverride and Item then the ItemOverride model will "uselessly" duplicate most of its fields, and adding/updating/removing fields will have to be done in two tables instead of one

So, I don't know if this design is "good enough", or can be improved/simplified. I'd be interested to dive-in similar project with such inherit/override needs, if you know any.


Summary:

My second attempt seems to fit my needs and it's what I'd use if I had to start immediately because I don't see how to improve it.

There is no data redundancy with this design, but it's still unclear how to handle the data override when a SubGroup inherits a Group's Item. If the override is limited to the required field then it's rather easy, but if it's many fields then it becomes a bit more complicated to maintain. Using model/table inheritance may complicate things also, because we don't want to store non-override values and therefore want to allow null for all fields in the ItemOverride table (which maybe isn't possible if we enforce non-nullable rules in the Item entity because they'll be applied to ItemOverride as well)

Question: Is there a way to use both inheritance and override without duplicating either the columns configuration nor the data themselves?


For the record, I'm using Django. Its powerful internal ORM deals gracefully with ContentTypes and DynamicRelationship, they allow to reference a dynamic entity using a model's fields. (what I've referenced as EntityType/EntityId) and that's one of the reason why the 2nd attempt design is designed that way (easier to rely on something my framework provides). But I'm open to completely different possibilities/choices.

Vadorequest
  • 16,593
  • 24
  • 118
  • 215
  • "Its powerful internal ORM deals gracefully" ouch – philipxy Mar 13 '19 at 17:15
  • 1
    What is your question? Please make it suit [ask]--ask a specific question about a specific situation. Please research, because these general design issues are faqs. Google 'site:stackoverflow.com' re sql/database inheritance/subtyping & hierarchies (fixed & arbitrary depth). PS Please [use text, not images/links, for text--including tables & ERDs.](https://meta.stackoverflow.com/q/285551/3404097) Use images only for what cannot be expressed as text or to augment text. Images cannot be searched for or cut & pasted. Don't give photos. – philipxy Mar 13 '19 at 17:21
  • My current generic comment re "better"/"best" etc: There's no such thing as "better"/"best" in engineering unless you define it. Also unfortunately all reasonable practical definitions require a ridiculous amount of experience with a ridiculous number of factors that interact with chaotic sensitivity to details. Make straightforward designs. When you demonstrate via measurement that a design and all alternatives you can think of have problems (whatever that means at the time), then ask a very specific question. Which should also define "better"/"best". https://meta.stackexchange.com/q/204461 – philipxy Mar 13 '19 at 17:23
  • Duly noted for the image, since it's a diagram I assumed it was fine. Regarding better/best, I defined the term by `basically one that fits those rules and is flexible enough to evolve if needs be` (but I removed it since it still caused some confusion). The 2nd attempt is better than the 1st because it fits the requirements better. But I wonder if there isn't even a better way to do it still. Thanks for the Google internal SO research, not used to do that. – Vadorequest Mar 13 '19 at 17:57
  • 1
    That definition is too vague for someone given the designs to decide. It begs the question. See my comment re measurement. Also there is still no question in your post. (Let alone an on-topic one.) Read it. PS A "basically" or "essentially" or "in other words" that doesn't introduce or summarize a clear & precise description just means "unclearly". PS [Are there any options to a join table for many-to-many associations?](https://stackoverflow.com/a/28358446/3404097) [What are the options for storing hierarchical data in a relational database?](https://stackoverflow.com/q/4048151/3404097) – philipxy Mar 13 '19 at 18:18
  • What do you mean by "re measurement", I mean the "re". It's also used in `Re rows making statements` in https://stackoverflow.com/questions/28347679/are-there-any-options-to-a-join-table-for-many-to-many-associations/28358446#28358446 - I'm reading the links you posted, I'll try to reformulate my question once I have a better understanding. Thanks! – Vadorequest Mar 13 '19 at 18:25
  • 1
    What did you learn googling "re"? (I often use it in SO comments instead of "about" because it's shorter.) – philipxy Mar 13 '19 at 18:27
  • 1
    (Historically, "Re:" was used in snail mail the way "Subject:" & "Re:" are used in email. Email "Re" stands for re not reply or regarding.) – philipxy Mar 13 '19 at 18:37
  • I've reworked the question itself, and also read those links (and other) but they didn't really help me find a better solution in my use case. They did show me other ways (and much worse (complicated) ways of doing what I want. Eventually made me figure this design isn't so bad as it is actually :) But maybe someone will prove me wrong! – Vadorequest Mar 13 '19 at 20:02

0 Answers0