I have a database schema to log operations users perform in my webapp:
Log
---
Id
Log_Type_Id
Performed_by_Person_Id
Performed_to_Person_Id
Comment_Id
Story_Id
Photo_Id
etc_Id
Person_Log
----------
Person_Id
Log_Id
This way I can notify users of entries in their log with details about what exactly happened. The problem is the Log table has to contain every possible type of user operation (they modified a story or comment, created a story or comment or photo, updated a profile, etc). And almost all of those fields will necessarily be null for each entry.
Ideally I have individual Log tables that the overall Log refers to, maybe something like:
Log
---
Id
Performed_by_Person_Id
Log_Comment
-----------
Id
Log_Id
Comment_Id
Log_Photo
---------
Id
Log_Id
Photo_Id
Person_Log
----------
Person_Id
Log_Id
The problem there is that I then don’t have an easy way to notify users of things going on pertaining to them. I easily get the log entry for them, but then I have to query each “child” table to see the specifics… I can store the name of the child Log table in Log, but that seems so inelegant. Is there a better, more relational, way of doing this that also works well with ORM systems?
Your case looks like an instance of the Gen-Spec design pattern. Gen-spec is familiar to object oriented programmers through the superclass-subclass hierarchy. Unfortunately, introductions to relational database design tend to skip over how to design tables for the Gen-Spec situation. Fortunately, it’s well understood. A google search on “Relational database generalization specialization” will yield several articles on the subject. Or you can look at the following previous discussion.
The trick is in the way the PK for the subclass (specialized) tables gets assigned. It’s not generated by some sort of autonumber feature. Instead, it’s a copy of the PK in the superclass (generalized) table, and is therefore an FK reference to it.
Thus, if the case were vehicles, trucks and sedans, every truck or sedan would have an entry in the vehicles table, trucks would also have an entry in the trucks table, with a PK that’s a copy of the corresponding PK in the vehicles table. Similarly for sedans. It’s easy to figure out whether a vehicle is a truck or a sedan by just doing joins, and you usually want to join the data in that kind of query anyway.