Techniques to create an object designer - php

I've been trying to create an application where everything is effectively an object with a series of fields. I've abstracted it to the level that you have the following tables:
ObjectTemplate
Field
LinkObjectTemplateField
FieldType
Each ObjectTemplate has a series of fields (a many-to-many relationship), which can be found in LinkObjectTemplateField. Field is linked to FieldType (many-to-one relationship). Field also has an ObjectTemplateID field - so let's suppose we have an object template called Section, and another object template called Question (as in for a questionnaire). Section would have Question as a field for questionnaire designers to use to define which questions appear in a section. Each Question would then be linked to a series of Values (or none at all in the case that it is of FieldType 'Text'.
We're able to create fields, field types and object templates so far. However I've come to realise that actually all 3 of these could be represented within the above tables, and I could probably kill off one of these tables too (so I only have ObjectTemplate and LinkObjectTemplateField, where Field is an ObjectTemplate in it's own right so there is a link simply between ObjectTemplate and itself via LinkObjectTemplateField).
My aim is to have one table structure for ALL object types, both as it currently stands and in the future. I'll have a class which picks up all of the fields for a particular object, and the fields it is expecting based on the objecttemplate, and decides how to present the fields based on the template. This seems to be getting very complex and I keep finding myself getting confused. I have a week left to work on this, so my questions are: should I plough on with this? Are there any better techniques to achieve this, or any flaws in my approach? Should I have stuck with the old structure (an entire table for each object type, with the same fields as most other object types for the core details - name, description, deleted etc.)?
Edit
I have been going over my approach again and come to the following conclusions:
Each object type, including object template itself, should have its' own record in the objecttemplate table.
Each object template, field and fieldtype should then have its' own row in the object table.
In this way, for example, Text, Dropdown etc. will be objects using the fieldtype object template. The IDs of these will be used in the functions for writing the forms - they will be declared as constants and referenced via MAIN::TEXT, MAIN::DROPDOWN and so on.

You are effectively trying to implement o form of EAV, and unless you actually need the flexibility it brings, is considered an anti-pattern.
Such "inner platform" is usually a poor replica of the real thing. In a nutshell:
It's difficult to enforce constraints that are otherwise available to "normal" tables and fields, including data types, NULL-ability, CHECKs, keys, and foreign keys.
You no longer have a good "target" for setting permissions or creating triggers.
It's difficult to limit an index to a specific "column", or make it use a "native" type.
It's difficult to reconstruct the "original" object. Usually, a lot of JOINing is required and the resulting object is not represented as a single row (which may be awkward to the client). Indexes and query optimizer can no longer work optimally.
So unless you absolutely have to be able to change data structure without changing database structure, just use what DBMS already provides through "normal" tables/columns/constraints...
My aim is to have one table structure for ALL object types, both as it currently stands and in the future.
Well, you kind of already have that built-in to your DBMS: it's called "data dictionary". Yes, you change it through CREATE/ALTER/DROP statements instead of INSERT/UPDATE/DELETE, but at the logical level it's a similar thing.
Should I have stuck with the old structure (an entire table for each object type, with the same fields as most other object types for the core details - name, description, deleted etc.)?
Probably.
BTW, if you have a lot of common fields (and/or constraints), consider putting them in a common "base" table and then "inheriting" other tables from it.

Related

How can I deal with polymorphism in a product database? [duplicate]

I do not have much experience in table design. My goal is to create one or more product tables that meet the requirements below:
Support many kinds of products (TV, Phone, PC, ...). Each kind of product has a different set of parameters, like:
Phone will have Color, Size, Weight, OS...
PC will have CPU, HDD, RAM...
The set of parameters must be dynamic. You can add or edit any parameter you like.
How can I meet these requirements without a separate table for each kind of product?
You have at least these five options for modeling the type hierarchy you describe:
Single Table Inheritance: one table for all Product types, with enough columns to store all attributes of all types. This means a lot of columns, most of which are NULL on any given row.
Class Table Inheritance: one table for Products, storing attributes common to all product types. Then one table per product type, storing attributes specific to that product type.
Concrete Table Inheritance: no table for common Products attributes. Instead, one table per product type, storing both common product attributes, and product-specific attributes.
Serialized LOB: One table for Products, storing attributes common to all product types. One extra column stores a BLOB of semi-structured data, in XML, YAML, JSON, or some other format. This BLOB allows you to store the attributes specific to each product type. You can use fancy Design Patterns to describe this, such as Facade and Memento. But regardless you have a blob of attributes that can't be easily queried within SQL; you have to fetch the whole blob back to the application and sort it out there.
Entity-Attribute-Value: One table for Products, and one table that pivots attributes to rows, instead of columns. EAV is not a valid design with respect to the relational paradigm, but many people use it anyway. This is the "Properties Pattern" mentioned by another answer. See other questions with the eav tag on StackOverflow for some of the pitfalls.
I have written more about this in a presentation, Extensible Data Modeling.
Additional thoughts about EAV: Although many people seem to favor EAV, I don't. It seems like the most flexible solution, and therefore the best. However, keep in mind the adage TANSTAAFL. Here are some of the disadvantages of EAV:
No way to make a column mandatory (equivalent of NOT NULL).
No way to use SQL data types to validate entries.
No way to ensure that attribute names are spelled consistently.
No way to put a foreign key on the values of any given attribute, e.g. for a lookup table.
Fetching results in a conventional tabular layout is complex and expensive, because to get attributes from multiple rows you need to do JOIN for each attribute.
The degree of flexibility EAV gives you requires sacrifices in other areas, probably making your code as complex (or worse) than it would have been to solve the original problem in a more conventional way.
And in most cases, it's unnecessary to have that degree of flexibility. In the OP's question about product types, it's much simpler to create a table per product type for product-specific attributes, so you have some consistent structure enforced at least for entries of the same product type.
I'd use EAV only if every row must be permitted to potentially have a distinct set of attributes. When you have a finite set of product types, EAV is overkill. Class Table Inheritance would be my first choice.
Update 2019: The more I see people using JSON as a solution for the "many custom attributes" problem, the less I like that solution. It makes queries too complex, even when using special JSON functions to support them. It takes a lot more storage space to store JSON documents, versus storing in normal rows and columns.
Basically, none of these solutions are easy or efficient in a relational database. The whole idea of having "variable attributes" is fundamentally at odds with relational theory.
What it comes down to is that you have to choose one of the solutions based on which is the least bad for your app. Therefore you need to know how you're going to query the data before you choose a database design. There's no way to choose one solution that is "best" because any of the solutions might be best for a given application.
#StoneHeart
I would go here with EAV and MVC all the way.
#Bill Karvin
Here are some of the disadvantages of
EAV:
No way to make a column mandatory (equivalent of NOT NULL).
No way to use SQL data types to validate entries.
No way to ensure that attribute names are spelled consistently.
No way to put a foreign key on the values of any given attribute, e.g.
for a lookup table.
All those things that you have mentioned here:
data validation
attribute names spelling validation
mandatory columns/fields
handling the destruction of dependent attributes
in my opinion don't belong in a database at all because none of databases are capable of handling those interactions and requirements on a proper level as a programming language of an application does.
In my opinion using a database in this way is like using a rock to hammer a nail. You can do it with a rock but aren't you suppose to use a hammer which is more precise and specifically designed for this sort of activity ?
Fetching results in a conventional tabular layout is complex and
expensive, because to get attributes
from multiple rows you need to do JOIN
for each attribute.
This problem can be solved by making few queries on partial data and processing them into tabular layout with your application. Even if you have 600GB of product data you can process it in batches if you require data from every single row in this table.
Going further If you would like to improve the performance of the queries you can select certain operations like for e.g. reporting or global text search and prepare for them index tables which would store required data and would be regenerated periodically, lets say every 30 minutes.
You don't even need to be concerned with the cost of extra data storage because it gets cheaper and cheaper every day.
If you would still be concerned with performance of operations done by the application, you can always use Erlang, C++, Go Language to pre-process the data and later on just process the optimised data further in your main app.
If I use Class Table Inheritance meaning:
one table for Products, storing attributes common to all product types. Then one table per product type, storing attributes specific to that product type.
-Bill Karwin
Which I like the best of Bill Karwin's Suggestions.. I can kind of foresee one drawback, which I will try to explain how to keep from becoming a problem.
What contingency plan should I have in place when an attribute that is only common to 1 type, then becomes common to 2, then 3, etc?
For example: (this is just an example, not my real issue)
If we sell furniture, we might sell chairs, lamps, sofas, TVs, etc. The TV type might be the only type we carry that has a power consumption. So I would put the power_consumption attribute on the tv_type_table. But then we start to carry Home theater systems which also have a power_consumption property. OK its just one other product so I'll add this field to the stereo_type_table as well since that is probably easiest at this point. But over time as we start to carry more and more electronics, we realize that power_consumption is broad enough that it should be in the main_product_table. What should I do now?
Add the field to the main_product_table. Write a script to loop through the electronics and put the correct value from each type_table to the main_product_table. Then drop that column from each type_table.
Now If I was always using the same GetProductData class to interact with the database to pull the product info; then if any changes in code now need refactoring, they should be to that Class only.
You can have a Product table and a separate ProductAdditionInfo table with 3 columns: product ID, additional info name, additional info value. If color is used by many but not all kinds of Products you could have it be a nullable column in the Product table, or just put it in ProductAdditionalInfo.
This approach is not a traditional technique for a relational database, but I have seen it used a lot in practice. It can be flexible and have good performance.
Steve Yegge calls this the Properties pattern and wrote a long post about using it.

Laravel CMS logic for shared functions/fields

I'm pretty new to Laravel, so I'm struggling with the logic for what is essentially a CMS with multiple content types.
Say I have 3 content types; Food, Books and Cars. Every item in all content types has a name, URL and a couple of other fields.
I can create, update and delete any of these resources with most likely the same code replicated 3 times. The only difference would be with a create or update as the field names would differ between them.
Should I just duplicate these fields/functions for each controller, or create some common ground in one place?
The crossover of fields/functions initially will not be huge, however, it seems inefficient let's say if I had 10 content types and I want to add one field to all of them I have to update code in a large number of places.
If I had a central "Node" that contained the id's and common fields for ALL items in every content type, then have this linked to individual tables for the custom fields, I'm in a much better position when I want to add, update or delete common fields.
I've currently got 3 controllers and have only worked on one so far so I have an index(), show() and edit() function in the controller.
As a test, I created a Node model with php artisan make:model Node -mcr and simply extended the existing Controllers so they were extending NodeController. Which just threw up an error like this;
Declaration of App\Http\Controllers\FoodController::show(App\Food$food) should be compatible with App\Http\Controllers\NodeController::show(App\Node $node)
This is likely not the way to go about it anyway, but I simply do not know the recommended practice for this.
Most appropriate and standard best practice for your problem is,
have a single database table, let's say table name as node, which will contain all the common fields, and have another table as categories and relate it with node table (1-m) to categorize type of node such as car,book,food etc., and make one more table, let's say node_meta which will store all additional attributes depending on the type of node,
(you may have a look on the wordpress CMS database ER Diagram which has similar db design.)
Polymorphic relation is not a good idea for this as stated by another user above, it has some limitation when it comes to querying underlying data, for example you cannot apply whereHas query and still there is no official solution to this problem.

EAV Model Scheme for Stock System or different apprroach?

I'm developing a stock and warehouse management system using relational databases (MySQL) and PHP. Due to the fact that the stock products will have multiple characteristics (widths, heights, weights, measures, colors, etc) there raises the need of having a database model approach of storing the attributes and the possibility to add/edit new attributes, alter product types and so on.
So, in the current concept I can see only 3 viable models:
store all attributes in a single table, as separated column and
based on product type (probably category) to serve them to the end
user to fill
the EAV (Entity - Attribute - Value) model that will involve
something like this:
a category table containing classes of attributes
a class of attributes table that will contain separate classes with multiple attributes (in this manner we ensure that we can add to a category a class of attributes without the need to manually add to similar categories attributes one after the other)
a attributes table responsible for the attribute itself
a attributes values table where we store the values
Store all common attributes in a single table and create multiple tables for all different category type: this model would require to change the database every time we encounter a new category type
The second model is inspired from here.
After reading a lot regarding the EAV model I now have doubts over this model and I am little concern regarding the ways I will have to connect different product attributes in orders / invoices and so on.. Even the validation of forms seems that it will be a real pain of using the EAV model, but still.. I wouldn't like to have a single table with 100+ columns and then to be ready to add new columns whenever a new attribute is to be added..
So, the question would be: is there a cheaper solution? Or could the EAV model be improved?
I know it's a long and old debate, but everybody is just pointing to NoSQL and I only rely on RDBMS..
EDIT:
The downside of those approaches (or of most of the approaches found) is that:
for a specified attribute there probably should exist a measure unit
(eq. attribute weight should have a drop down with measuring units)
a specified attribute should be mandatory or not
all attributes should have a validation on form submit
Until now, the only feasible solution would be to create a new table for every new category, and deal in that table with all custom attributes and rules. But, yet again, it would end up to a real pain when a new category is to be set up.
EDIT 2:
The option of using a Json column in MySQL, does not solve from my point of view any of the downsides mentioned above.. OR, maybe I am wrong and I don't clearly see the big picture..
I gather that these are your primary requirements:
Flexible attributes
Your exact need here is unclear: it sounds like you either expect the attributes to change, or at least expect that all attributes will not always be applicable to all products (i.e. a sparse matrix)
Products are also categorized, and the category will (at least partially) determine what attributes are applicable to a product
The attributes themselves may have additional properties aside from their value, that must be provided by the user (i.e. a unit that goes with a weight)
Input validation is a must, and checks things like:
All required attributes are present
Attributes which are not applicable are not present
Attributes have valid values
User-provided attribute properties have valid values
You probably also want to make sure you can search/filter efficiently by attributes
These different requirements all result in different technical needs, and different technical solutions. Some are matters of database, and some will have to be solved in code regardless of database choice. Obviously you are aware of some of these issues, but I think it is worth really breaking it down:
Flexible Attributes
Having a list of flexible attributes (as you know) does not work well with RDBMS systems where your table schema has to be pre-defined. This includes pretty much all of the SQLs, and definitely MySQL. The issue is that changing the table schema is expensive and for large tables can take minutes or hours, making it practically impossible to add attributes if you have to add a column to a table to do it.
Even if your list of attributes rarely changes, a large table of attributes is very inefficient if most products don't have a value for most attributes (i.e. a sparse matrix).
In the long run, you just won't get anywhere if your attributes are stored as a column in tables. Even if you break it down per-category, you are still going to have large empty tables that you can't add columns to dynamically.
If you stick with an RDBMS your only option is really an EAV system. Having considered, researched, and implemented EAV systems, I wouldn't worry too much about all the hype you hear about them on the internet. I know that there are lots of articles out there talking about the EAV "anti-pattern", and I'm the kind of person who takes proper use of software design patterns seriously, but EAV does have a perfectly valid time and place, and this is it. In the long run you will not be able to do this on an RDBMS without EAV. You could certainly look at a NoSQL system that is designed for this specific kind of problem, but when the rest of your database is in a standard RDBMS, installing or switching to a NoSQL system just to store your attribute values is almost certainly overkill. You certainly aren't going to want to lose the ACID compliance that a RDMBS comes with, and most NoSQL systems don't guarantee ACID compliance. There is a wave of NewSQL systems out there that are designed to get the best of both worlds, but if this is just one part of a larger application (which I'm sure is the case), it probably isn't worth investigating completely new technologies just to make this one feature happen. You could also consider using something like JSON storage inside MySQL to store your attribute values. That is a viable option now that MySQL has better JSON support, but that only makes a small change to the big picture: you would still need all your other EAV tables to keep track of allowed attributes, categories, etc. It is only the attribute values that you would be able to place inside of the JSON data, so the potential benefits of JSON storage are relatively small (and have other issues that I will mention down the road).
So in summary, I would say that as long as the rest of your application runs on a RDBMS, it is perfectly reasonable to use EAV to manage flexible attributes. If you were trying to build your entire system in an EAV inside of a RDBMS, then you would definitely be wasting your time and I'd tell you to go find a good NoSQL database that fits the problem you are trying to solve. The disadvantages of EAV do still apply though: you can't easily perform consistency checks within your RDBMS system, and will have to do that yourself in code.
Categorized products with category-specific attributes
You've pretty much got it here. This is relatively straight-forward inside an EAV system. You will have your attributes table, you will have a category table, and then you will need a standard one-to-many or many-to-many relationship between the attributes and categories table which will determine which attributes are available to which category. You obviously also have a relationship between products and categories, so you know which products therefore need which attributes.
Your option #3 is designed to fulfill this requirement, but having a table with each attribute as a column will scale very poorly as your system grows, and will definitely break if you ever need to dynamically add attributes. You don't want to be running ALTER TABLE statements on the fly, especially if you have more than a few thousand records.
Managing attribute properties
It is one thing to store dynamic attributes and values. It is another problem entirely to store dynamic attributes, values, and associated meta data (i.e. store a weight as well as the unit the weight is in). This however is no longer a database problem, but rather a code problem. In terms of actually storing the information your best bet is to probably store your meta data inside your attribute values table, and rely upon some code abstractions to handle the input validation as well as form building. That can get quite complicated quite fast, especially if done wrong, and talking through such a system would take another entire post. However, I think you are on the right track: for a fancier attribute that requires both a value and meta data, you need to somehow assign a class that is responsible for input processing and form validation. For instance for a simple text field you have a "text" class that reads the user's value out of the form and stores it in the proper "attribute_values" table, with no meta data stored. Then for your "weight" attribute you would have a "weight" attribute that stores the number given by the user (i.e. 0.5) but then also stores the unit the user specified with that number (i.e. 'lbs') and persists both to the "attribute_values" table (in pseudo-SQL): INSERT INTO attribute_values value='0.5', meta_data='{"unit":"lbs"}', product_id=X, attribute_id=X. Ironically JSON probably would be a good way to store this meta data, since the exact meta data kept will also vary by attribute type, and I doubt you would another level of tables to handle that variation in your EAV tables.
Again, this is more of a code problem than storage problem. If you decided to do JSON tables the overall picture to meet this requirement wouldn't change: your "attribute type classes" would simply store the meta data in a different way. That would probably look something like: UPDATE products SET attributes='{"weight":0.5,"unit":"lbs"}' WHERE id=X
Input Validation
This will have to be handled exclusively by code regardless of how you store your data, so this requirement doesn't matter much in terms of deciding your database structure. A class-based system as described above will also be able to handle input validation, if properly executed.
Sort/Search/Filter
This doesn't matter if you are exclusively using your attributes for data storage/retrieval, but will you be searching on attributes at all? With a proper EAV system and good indexes, you can actually search/sort efficiently in an RDBMS system (although it can start to get painful if you search by more than a handful of indexes at a time). I haven't looked in detail, but I'm pretty sure that using JSON for storage won't scale well when it comes to searching. While MySQL can work with JSON now and search the columns directly, I seriously doubt that such searching/sorting makes use of MySQL indexes, which means that it won't work with large databases. I could be wrong on that one though. It would be worth digging into before committing to a MySQL/JSON storage setup, if you were going to do something like that.
Depending on your needs, this is also a good place to compliment an RDBMS system with a NoSQL system. Having managed large-ish (~1.5 million product) e-commerce systems before, I have found that MySQL tends to fall flat in the searching/sorting category, especially if you are doing any kind of text searching. In an e-commerce system a query like: "Show me the results that best match the term 'blue truck' and have the attribute 'For ages 3-5'" is common, but doing something like that in MySQL is about impossible, primarily because of the need for relevancy based sorting and scoring. We solved this problem by using Apache Solr (Elastic is a similar solution) and it managed our searching/sorting/search term scoring very well. In this case it was a two database solution. MySQL kept all the actual data and stored attributes in EAV tables, and anytime something got updated we pushed a record of everything to Apache Solr for additional storage. When a query came in from a user we would query Apache Solr which was an expert at text searching and could also handle the attribute filtering with no trouble, and then we would pull the full product record out of our MySQL database. The system worked beautifully. We had 1.5 million products, thousands of custom attributes, and had no trouble running the whole thing off of a single virtual server. Obviously there was a lot of code going on behind the scenes, but the point is that it definitely worked and wasn't difficult to maintain. Never had any issues with performance from either MySQL or Solr.
Well, this is just one approach. You could simplify this if you don't need or want all of this.
You could, for example, use a Json column in Mysql, to store all of the extra attributes. Another idea, in the product type, add a json column to store the custom attributes and types, and use this to draw the form on the screen.
I would recommend you to go through an EAV database first in order to understand the database creation & its values.
You can follow magento DB structure which uses EAV model.
EAV stands for Entity attribute and value model. Let’s closely have a look at all parts.
Entity: Data items are represented as entity, it can be a product or customer or a category. In the database each entity have a record.
Attribute: These are belongs to different entity, for example a Customer entity have attributes like Name, Age, Address etc. In Magento database all attributes are listed in a single table.
Value: Simply the values of the attributes, for example for the Name attribute the value will be “Rajat”.
EAV is used when you have many attributes for an entity and these attribute are dynamic (added/removed).
Also there is a high possibility that many of these attribute would have empty or null value most of the time.
In such a situation EAV structure has many advantages mainly with optimized mysql storage
For Your case - Category can also have attributes, products can also have attributes so on with customers etc ...
Let's take an example of categories. Following are the tables provided by magento:
1. catalog_category_entity
2. catalog_category_entity_datetime
3. catalog_category_entity_decimal
4. catalog_category_entity_int
5. catalog_category_entity_text
6. catalog_category_entity_varchar
7. catalog_category_flat
Follow this link to know more about table
Magento Category Tables
For attributes which are select box. You can put dropdown values under option values.
Follow this to link to understand magento eav structure which will give you clear picture about how EAV model work & how you can make a best use of it.
magento table structure
There are three approaches if you want to stick with a relational database.
The first is best if you know in advance the attributes for all the products. You chose one of the three ways to store polymorphic data in a relational model.
It's "clean" from a relational point of view - you're just using rows and columns, but each of the 3 options has its own benefits and drawbacks.
If you don't know your attributes at development time, I'd recommend against these solutions - they'd require significant additional tooling.
The next option is EAV. The benefits and drawbacks are well documented - but your focus on "validating input forms" is only one use case for the data, and I think you could easily find your data becomes "write only". Providing sorting/filtering, for instance, becomes really hard ("find all products with a height of at least 12, and sort by material_type" is almost impossible using the EAV model).
The option I prefer is a combination of relational data for the core, invariant data, and document-centric (JSON/XML) for the variant data.
MySQL can query JSON natively - so you can sort/filter by the variant attributes. You'd have to create your own validation logic, though - perhaps by integrating JSON Schema in your data entry applications.
By using JSON Schema, you can introduce concepts that "belong together", and provide lookup values. For instance, if you have product weight, your schema might say weight always must have a unit of measure, with the valid options being kilogram, milligram, ounce, pound etc.
If you have foreign key relationships in the variant data, you have a problem - for instance, "manufacturer" might link to a manufacturers table. You can either model this as an explicit column, or in the JSON and do without SQL's built-in foreign key tools like joins.

Adding properties to object at runtime, and saving to a database

I have a set of model class definitions, each with some properties and methods.
Each new model class definition is mapped to its own database table, the properties forming the table columns. Each newly created object can then be adequately saved for a rainy day.
My question is, how can I elegantly allow for additional properties to be added at runtime, and have it saved without re-migrating all the tables in the database.
For example, say I have an "Article" object with name, creation date and article body as properties (initially), but at runtime a user decides that for a particular article they'd like to add a synopsis as a property, how do I save the new entity to the database?
I guess I'm trying to (amongst other things) mimic adding fields in Drupal or Custom Fields in Wordpress.
As one has to specify the data type of each column when creating or updating a table, the only way I can think of doing this is by creating a column with an array as its data type. This solution feels a bit awkward though, and just wondering how others have done it.
Your help would be much appreciated.
as a lowest common denominator you could persist your objects as a series of key-value pairs, but this sounds clunky and slow. I could also envisage nightmares when you have objects containing objects etc.
Or, you could serialize them before storage (as xml documents, perhaps?) But this forgoes any kind of structure at the database level and would complicate matters if you wished to query the database on specific column values.
But if I were you I'd read up on some "hibernation" utilities e.g. Hibernate (!) to get a feel for how they persist things. These utilities are already solving your exact problem, and you can guarantee they'll have put a fair amount of thought into it.
If you're lucky there may even be such a utility you could use out of the box, without necessarity understanding the nitty gritty.

Is this an appropriate use of a MySQL enumeration data type?

I have recently started doing freelance PHP + MySQL development in my free time, to supplement my income from a full-time job where I write C#/SQL Server code. One of the big database-related differences I've noticed is that MySQL has an enum datatype, whereas SQL Server does not.
When I noticed the enum datatype, I immediately decided to flatten my data model in favor of having a big table that makes use of enumerations rather than many smaller tables for discrete entities and one big "bridge" sort of table.
The website I'm currently working on is for a record label. I only have one table to store the releases for the label, the "releases" table. I have used enumerations everywhere I would normally use a foreign key to a separate table--Artist name, Label name, and several others. The user has the ability to edit these enumeration columns through the backend. The major advantage I see for enumerations over using a text field for this is that artist names will be reused, which should improve data integrity. I also see an advantage in having fewer tables in the database.
Incidentally, I do still have one additional table and a bridge table--there is a "Tags" feature to add tags to a particular release, and since this is a many-to-many relationship, I feel a discrete tag table and a bridge table to join tags to releases is appropriate
Having never encountered an ENUM datatype in a database before, I wonder if I am making wise use of this feature, or if there are problems I haven't foreseen that might come back to bite me as a result of this data architecture. Experienced MySQL'ers, what do you think?
In short, this is not a good design. Foreign keys have a purpose.
From the documentation for the ENUM type:
An enumeration can have a maximum of 65,535 elements.
Your design will not allow you to store more than 65k distinct artist names.
Have you considered what happens when you add a new artist name? I assume you are running an ALTER TABLE to add new enum types? According to a similar SO question this is a very expensive operation. Contrast this with the cost of simply adding another row to the artist table.
What happens if you have more than one table that needs to refer to an artist/artist's name? How do you re-use enum values across tables?
There are many other problems with this approach as well. I think that simplifying your database design like this does you a real disservice (foreign keys or having multiple tables are not a bad thing!).
I'm going to be honest - I stopped when I read...
I have used enumerations everywhere I
would normally use a foreign key to a
separate table--Artist name, Label
name, and several others.
If I understand correctly, that means there is an enumeration of all artists. But that enumeration of artists is definitely going to be a point of variation: there will be more artists. I sincerely doubt the record label never plans on increasing or changing the list of artists ;)
As such, in my opinion, that is an incorrect use of an enumeration.
I also don't think it's appropriate to perform an ALTER TABLE for what is inevitably a rather mundane use case. (Create/Read/Update/Destroy artist) I have no numbers to back up that opinion.
You have to look at it as a question of what information is an entity or an attribute of an entity: for a record label, artists are entities, but media types may not be. Artists have lots of information associated with them (name, genre, awards, web site url, seniority...) which suggests they are an entity, not an attribute of another entity such as Release. Also, Artists are Created/Read/Updated and Destroyed as part of regular everyday use of he system, further suggesting they are entities.
Entities tend to get their own table. Now, when you look at the Media Type of these Releases, you have to ask yourself whether Media Type has any other information... if it's anything more than Name you have a new Entity. For example, if your system has to keep track of whether a media type is obsolete, now there are 2 attributes for Media Type (name, is obsolete) and it should be a separate entity. If the Medai Types only have a Name within the scope of what you're building, then it's an attribute of another entity and should only be a column, not a table. At that point I would consider using an enumeration.
I dont think you can use enumerations in fields like artists. Its like you are restricting your application from growing. It will be really hard to maintain the column. Using ENUM is not a problem its own. But will be an issue in the following situations
When you need to add additional options to the enum colum. If you are table contains lots of data, it will take good time to rebuild your table when adding an additional option
When you need to port the the database to another technology (enum is not available in all database products, for eg MSSQL)

Categories