1

I have the following dilemma with designing a piece of software.

  1. How can I design a relation between the follwing entities so that a configuration rule can be global or apply to a building / room or a combination of buildings / rooms?
  2. How should the result data

I think I should use the following entities:

ConfigurationRule {
    id: number; 
    key: string;
    value: any;
}

Global: {
    building: Building[]; 
}

Building: {
    id: number; 
    name: string;
    rooms: Room[];
    stories: number;
    builddate: date:
}

Room: {
    id: number; 
    name: string;
    dimensions: {
        height: number;
        width: number;
        depth: number;
    }
}

We have the following requirements:

  • a building consists of many rooms (one-to-many)
  • a configuration rule may be applied to one or more buildings (one-to-many)
  • a configuration rule may be global and will apply to all buildings and rooms in the building
  • a building configuration rule overrules a global rule
  • a room configuration rule overrules a building rule

Sample data

configurationRules = [  
    { id: 1, key: 'hasPower', value: "220Volts" }  
    { id: 2, key: 'hasInternet', value: false },  
    { id: 3, key: 'hasInternet', value: 'fiber' },  
    { id: 4, key: 'hasInternet', value: 'dsl' },  
    { id: 5, key: 'hasInternet', value: 'sattelite' },  
    { id: 6, key: 'plotter', value: true },  
]

Buildings = [  
    { id: 1, name: 'Location A' },  
    { id: 2, name: 'Location B' },  
    { id: 3, name: 'Location C' },
    { id: 4, name: 'Location D' }
]

Rooms = [  
    { id: 1, name: 'Room A1' },  
    { id: 2, name: 'Room A2' },  
    { id: 3, name: 'Room A3' },  
    { id: 4, name: 'Room A4' },  
    { id: 5, name: 'Room B1' },  
    { id: 6, name: 'Room B2' },  
    { id: 7, name: 'Room C1' },  
    { id: 8, name: 'Room C2' },  
    { id: 9, name: 'Room C3' },  
    { id: 10, name: 'Room C4' },  
    { id: 11, name: 'Room C5' },  
]   { id: 12, name: 'Room D1' },  
]

Sample relations:

  • configuration rule 1 should be global and apply to all rooms in all buildings
  • configuration rule 2 should be global and apply to all rooms in all buildings
  • configuration rule 3 should be applied to building A & B and thereby to all rooms in these buildings
  • configuration rule 4 should apply to only building C
  • configuration rule 5 should apply to only room C3
  • configuration rule 6 should apply to only room D1

So that following function can be executed with:
configRuleByIdAppliesTo(1) => return a result for global
configRuleByNameAppliesTo('hasInternet') => return a result for the config rules 2, 3 and 4 with the applied config rules. getConfigRulesForBuilding({ id: 2, name: 'Location B' }) => return a result for with config for the building and rooms.

2
  • What's wrong with having three different types of configuration rules (global, building, room)?
    – Doc Brown
    Jan 12, 2023 at 20:08
  • I guess that would be fine, but how would this be represented in the entities / relations and database? Jan 12, 2023 at 20:59

2 Answers 2

1

Forget about the types. You only have one hierarchical type. lets call it Room

Room
{
  Id //use a guid
  parentId //null = its the world
} 

configurationRoomMapping
{
  ConfigurationId
  RoomId
}

Now if you want to find out if a rule applies to particular room you just check the mapping for the room and then loop up that rooms parents checking each in turn, building the list of configurations as you go.

9
  • I like this idea, but I only have 3 levels (Global, Building and Room) and level 1 should be a building and 2 should be a room. I forgot to mention that rooms and buildings have different properties. Also a building can't be a child of a building. How would this be representated and enforced in this hierarchy? Jan 12, 2023 at 21:43
  • add a "type" property globe, building, room add more tables using the same id for the extra data put the rules in your repository object etc etc.
    – Ewan
    Jan 12, 2023 at 21:45
  • Could you extend your answer with an example of this? And how to guard the types to the corresponding levels? Jan 12, 2023 at 21:57
  • 2
    totally going to get a "no power on 4th floor" situation before the project is over and my genius design will save your ass!
    – Ewan
    Jan 13, 2023 at 9:00
  • 1
    I will provide my final solution in an answer. But Ewans approach makes more sense because its easily extendable if a new level is needed or a new entity needs to be added. Jan 13, 2023 at 9:10
0

Solution

I finally went with the following solution (extending on @Ewan answer).

This gives me, imho flexibility to add new levels and types without much hustle. Without opening the classes for modifications, I just need to add a class for the new type.

Location {
    id: number;
    parentId: number | null;
}

Global {
    location: Location; 
}

Building {
    id: number; 
    location: Location; 
    name: string;
    stories: number;
    builddate: date:
}

Room {
    id: number; 
    location: Location; 
    name: string;
    dimensions: {
        height: number;
        width: number;
        depth: number;
    }
}

ConfigurationRule {
    id: number; 
    key: string;
    value: any;
}

ConfigurationLocationMapping {
  configurationId: number;
  locationId: number;
}

Please let me know what you think of this solution?

1
  • you wont know what type to instantiate from your database when you load them. if you want to extend my design with type, just add "type" to the base class and inherit from it.
    – Ewan
    Jan 21, 2023 at 13:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.