Database design for Tagging multiple types of entities

后端 未结 6 1967
抹茶落季
抹茶落季 2021-02-02 04:19

I\'m currently designing a database schema that\'s used to store recipes. In this database there are different types of entities that I want to be able to tag (ingredients, reci

6条回答
  •  既然无缘
    2021-02-02 05:04

    I don't see anything wrong with having a single table for all tag assignments (as opposed to multiple tables - one for each taggable entity).

    However, one important detail in your design remains ambiguous to me: if you are going to have something along these lines

    - - - - - - - - - -
    Tag
        ID           // PK
        Name
        ...
    
    - - - - - - - - - -
    Taggable
        ID           // PK
        ...
    
    - - - - - - - - - -
    TagAssignment
        Tag_ID       // FK -> Tag.ID
        Taggable_ID  // FK -> Taggable.ID
        ...
    
    - - - - - - - - - -
    EntityOne
        Taggable_ID  // FK -> Taggable.ID
        ...
    
    - - - - - - - - - -
    EntityTwo
        Taggable_ID  // FK -> Taggable.ID
        ...
    

    then are your entity classes going to have their own primary keys or are you going to use EntityOne.TaggableID and EntityTwo.TaggableID as de facto primary keys for EntityOne and EntityTwo?

    In most general case, I would be cautious and let entities have their own IDs:

    - - - - - - - - - -
    EntityOne
        ID           // PK
        Taggable_ID  // FK -> Taggable.ID (Nullable)
        ...
    
    - - - - - - - - - -
    EntityTwo
        ID           // PK
        Taggable_ID  // FK -> Taggable.ID (Nullable)
        ...
    

    This would not require each entity to have a corresponding instance of Taggable and therefore this would not require every piece of code concerned with an entity to also be aware of tags. However, if tagging is going to be really ubiquitous in the system, and if you are sure that you won't need any other "common ancestors" for entities (that is, other than Taggable), then you might get away without "intrinsic" IDs for entities.

    NB: I never tried to implement anything like this, so all my recommendations are purely theoretical. So please do not shoot me if I do not see some obvious flaws. :-)


    In response to Bill Karwin's comment:

    You are right: the design described above does not prevent multiple entities to refer to same Taggable. But:

    1. Like I said, all depends on requirements. If we are sure that Taggable is going to be the only "common ancestor" of entities, then it is okay to use Taggable_ID FKs as PKs for entities. But, for example, what if some entities that happen to be "taggable" also have to be "watchable" (think notifications, notification schedules, etc.) or "whatever-able" :-)? Can we cut all those "abilities" off by tying any entity hard to Taggable?

    2. If you really want to have DB-level enforcement of one-taggable-one-entity constraint... AFAIK, there is at least one common way to do that without making FKs serve as PKs: by introducing "types" of taggables (which may be useful for some other functionality anyway).

    Something along these lines would let us have a cake and eat it:

    - - - - - - - - - -
    Taggable
        ID           // PK
        Type        
        ... 
        - - - - - - - -
        Constraint: (ID, Type) is unique
    
    
    - - - - - - - - - -
    EntityOne
        ID
        Taggable_ID   
        Taggable_Type // Constraint: always = 'EntityOne'
        ...
        - - - - - - - -
        FK: (Taggable_ID, Taggable_Type) -> (Taggable.ID, Taggable.Type)
    

    Of course, all this is more complicated than just having entities tied to taggables. But I was just trying to discuss what, in my humble opinion, should be considered in addition to the narrow picture provided by the original question.

提交回复
热议问题