How to create mysql table with many hasMany association in CakePHP? - mysql

I'm defining a completely new database. I have now faced a problem
which I would describe as "usual" but still could not find good
information from web. So here's the problem:
I have many tables in my database (which I would describe as guides) such as:
Skills
Places
Activities
and so on...
Now to all these guide types I'd like to add a comment feature and
other similar features like attaching images and videos. I have many guide types so I dropped the idea of having a separate comment image and video tables for each of them. I need one table for each of them.
The question is, what is the best way to achieve this? I have heard and read about 3 solutions and I'm not familiar with none of them.
I have read about using UUIDs would fix this problem but I'm not very familiar how they function. Could someone elaborate on that if that is the correct way to go? Something about UUIDs I read but not quite understood it.
Other thing I have read about is creating a hierarchial model "tree table" which would hold association links. More info at Managing Hierarchical Data in MySQL.
I have also read about creating object tables and using program like object inheritance inside MySQL in a similar way like the hierarchical model.
UUIDs sound most simple so I would appreciate help in there.
I don't know anything about how to use them. But here's how I thought it works - at least you'll get a hang of it what I'm trying to achieve here and how/what I'm misunderstanding about them:
I would create a new table: Guides which could have UUID field.
Then link all those guide types (Skills etc.) to guide table (Guide as parent and the other as child)
Parent and Child have both UUID fields and when creating a guide Parent and Child gets same UUID so they can be linked. Child also has its own Id field.
Then link comments to Guides by using UUID field that points to Guide plus separate id int field for comments.
Please tell me if this is correct way or is it total garbage and if so, how I should do it?

Have you though about using a normal hasMany relationship with a condition? Read about it here.
class Skill extends AppModel {
var $hasMany = array(
'Comment' => array(
'className' => 'Comment',
'conditions' => array('Comment.type' => 1), // 1 for skills, 2 for places etc. or something like that.
)
);
}

Check http://cakeapp.com, create your DB layout there and download the SQL later.

I read more about UUIDs and since they allow application wide unique IDs I was able to do "inheritance" style of database.
I used my own prefix at the start of the every table name to avoid reserved table name collisions such as object. You can use any kind of prefix, for example: my_ and to use it like: my_object. All tables should use prefixes in this example.
So I created table Objects. It has the id field with Binary(36) type. Cake recognizes it as UUID field. Then I used 1:1 identifying relationships and inherited other tables from it, which I wanted to interact with others.
So I created 1:1 identifying relationship to Comments, Videos, Pictures table so that the table had the identifying foreign key being also a primary key.
Then I created Mappings table to which I used two 1:1 non-identifying relationships without primary key. This means this was really HABTM relationship to self.
Now this let me to "inherit" other tables from Objects table, like News table with again 1:1 identifying relationship. Then it was possible to link Comments, or anything other that has the 1:1 identifying relationship to Object, to News table by using the Mappings table.
I hope this will help others who are pondering this kind of solution aswell.

Related

SQL many-to-many relation 3 ways

Hej all,
Let's say I have 4 tables named "user", "office", "product", "event".
And another table named "document". A same document can be assigned to
one or many users, offices, products and events. So here we need a
many-to-many relationship. But I have 3 ways to do that :
-a table named "user_document", another named "office_document", "product_document" and "event_document" which all have a field named
"document_id" which is foreign key for document id and another field
"user_id" (for user_document) which is foreign key to user id (and so
on with office, product and event of course...)
OR
-a table named "document_ownership" which has these fields : "document_id", "user_id", "office_id", "product_id" and "event_id".
Here document_id should be not Null and one (or more) of other fields
that can be Null. For example if I set a same document for a user and
a product, I will have a row with document_id, user_id and product_id
not Null.
OR
-a table named "document_ownership" that will have these fields : "document_id", "relation_type" and "relation_id". Here relation_type
field is for example a string (which represent the relation table
name) or a foreign key pointing to another additionnal table named for
example "relationtype" in which we have strings like "user" (id=1),
"office" (id=2), "product" (id=3) and "event" (id=4) (which also
represent the relation table name), and relation_id which is the id of
the specified relation table (relation_type)
My question is, what is the pro/cons of all these 3 ways of doing what I want and what should be the best practice please ?
Thanks in advance for your advices,
Michal
This question is not really answerable as asked. A purist would say that approach 1 is correct but it is not always that simple. Think of it like this - your database design should express the relationships between the data and what the data means. So each of your approaches imply several things about the nature of the data.
Approach 1 says that user, office, product and event are important, and oh yeah they can have documents. Maybe.
Approach 2 says that documents are important, and we need to track what each document relates to. So the document is the key thing and everything else is annotated around that.
Approach 3 is more complicated and technical and does not really give an idea of how you want the data to be used.
In all cases the data is same. It is just designing the data to tell the story of how it should be used.
Sorry to wax lyrical. Just my $0.02.
In a data conception (Merise) view you have :
Document-0,n---------0,n-User
Document-0,n---------0,n-Event
...
This is the logical view.
When you transform this to physical data view you will end up with 1 more table for each relation.
So the 1st solution is the way to go, if you want to apply best practice in data modelisation.
Concerning the two other solutions, which breaks some normal form :
the second solution is a total no go. You will have a lot of null value everywhere and will strugle to do some basic statistic because of that.
The third solution, that looks like a spaghetthi plate, will globally work and is, in my point of view, a good alternative. IF you can handle the loss of constraint integrity

CakePHP Two Relationships Between Models

I have the following tables: 'assets', 'pictures', 'assets_pictures', 'othermodels', 'othermodels_pictures', etc...
From the above you probably already figured that table 'pictures' serves as a repository of images and is related to multiple models, including 'assets'.
I want model 'Asset' (table 'assets'), to have:
hasMany relationship with 'Picture' (using table 'assets_pictures')
hasOne relationship with 'Cover' (table 'pictures'), based on a 'cover_id' field in 'assets' associated with 'Picture.id'
So far it seems to work when I setup HABTM relationship between Asset and Picture, and 'Asset' belongsTo 'Cover'. Somehow this doesn't sound right, moreover changing the cover picture of an asset wipes out all HABTM relationships in 'assets_pictures' for that asset, so I know something's wrong here. I'm at loss...
It doesn't sound right because you are setting up multiple relationships between two tables at the database level. Not sure which ones, but this definitely breaks a few database normalization rules.
Imagine that later on you decide that you want to be able to track not only the cover, but also the back. You would have to add another field to the asset table called back_id, which would point back to pictures. A real mess...
The proper way to represent this is to include a 'type' field in the assets_pictures table:
You can default this field to "normal" (or even null), and change it to "cover" when needed. Note that this field allows for additional picture types (e.g. "back").
HABTM relationships can handle this without too many problems. The parameter 'unique'=>'keepExisting' prevents CakePHP from dropping other relationships already in place (which is the default behavior).
However, things can get complicated with 'rich' HABTM relationships, particularly when trying to save data. If this happens, and before you pull out your hair, you may want to go down the 'hasMany through' route.
For convenience, and to retrieve information, you may want to set up an additional HABTM relationship for Cover in model Asset, which would look something like this:
public $hasAndBelongsToMany = array(
'Cover' => array(
'className' => 'Picture',
'conditions' => array('AssetCover.type' => 'cover'),
)

Database Design - structure

I'm designing a website with courses and jobs.
I have a jobs table and courses table, and each job or course is offered by a 'body', which is either an institution(offering courses) or a company(offering jobs). I am deciding between these two options:
option1: use a 'Bodies' table, with a body_type column for both insitutions and companies.
option2: use separate 'institution' and 'company' tables.
My main problem is that there is also a post table where all adverts for courses and jobs are displayed from. Therefore if I go with the first option, I would just need to put a body_id as a record for each post, whereas if I choose the second option, I would need to have an extra join somewhere when displaying posts.
Which option is best? or is there an alternative design?
Don't think so much in terms of SQL syntax and "extra joins", think more in terms of models, entities, attributes, and relations.
At the highest level, your model's central entity is a Post. What are the attributes of a post?
Who posted it
When it was posted
Its contents
Some additional metadata for search purposes
(Others?)
Each of these attributes is either unique to that post and therefore should be in the post table directly, or is not and should be in a table which is related; one obvious example is "who posted it" - this should simply be a PostedBy field with an ID which relates another table for poster/body entities. (NB: Your poster entity does not necessarily have to be your body entity ...)
Your poster/body entity has its own attributes that are either unique to each poster/body, or again, should be in some normalized entity of their own.
Are job posts and course posts substantially different? Perhaps you should consider CoursePosts and JobPosts subset tables with job- and course-specific data, and then join these to your Posts table.
The key thing is to get your model in such a state that all of the entity attributes and relationships make sense where they are. Correctly modeling your actual entities will prevent both performance and logic issues down the line.
For your specific question, if your bodies are generally identical in terms of attributes (name, contact info, etc) then you want to put them in the same table. If they are substantially different, then they should probably be in different tables. And if they are substantially different, and your jobs and courses are substantially different, then definitely consider creating two entirely different data models for JobPosts versus CoursePosts and then simply linking them in some superset table of Posts. But as you can tell, from an object-oriented perspective, if your Posts have nothing in common but perhaps a unique key identifier and some administrative metadata, you might even ask why you're mixing these two entities in your application.
When resolving hierarchies there are usually 3 options:
Kill children: Your option 1
Kill parent: Your option 2
Keep both
I get the issue you're talking about when you kill the parent. Basically, you don't know to what table you have to create a foreign key. So unless you also create a post hierarchy where you have a post related to institution and a separate post table relating to company (horrible solution!) that is a no go. You could also solve this outside the design itself adding metadata in each post stating which table they should join against (not a good option either as your schema will not be self documentation and the data will determine how to join tables... which is error prone).
So I would discard killing the parent. Killing the children works good if you don't have too many different fields between the different tables. Also you should bear in mind that that approach is not good to solve issues wether the children can be both: institution and companies but it doesn't seem to be the case. Killing the children is also the most efficient one.
The third option that you haven't evaluated is the keeping both approach. This way you keep a dummy table containing the shared values between the bodies and each of the bodies have a FK to this "abstract" table (if you know what I mean). This is usually the least efficient way but most likely the most flexible. This way you can easily handle bodies that are of both types, and also that are only of type "body" but not a company nor an institution themselves (if that is even possible or might be possible in the future). You should note that in order to join a post to an institution you should always reference the parent table and then join the parent with the children.
This question might also be useful for you:
What is the best database schema to support values that are only appropriate to specific rows?

Refactoring a One-to-many relation to a Many-to-Many in MySQL: How to formulate the query?

In the initial 'version' of the application that I'm working on, a design consideration wasn't taken into account - no one thought of it.
However, it seems that the original one-to-many relation needs to be refactored into a many-to-many. My question is how best to do this? I'm using MySQL for persistence.
Populating the relationship table will only be a one time effort, I'd rather go with a simple query or a stored procedure approach (I'm not well versed with the latter); rather than write java/jdbc based logic to do it (I know I can and it's not too difficult, but that's not what I want)
So here's an example of the relation:
|VirtualWhiteBoard| -1------*- |Post|
A virtual white board can have many posts. The new functionality is: 1 post should belong to multiple white boards if the user chooses to 'duplicate' current white board (not thought of before)
The schema looks like this:
VirtualWhiteBoard (wallName, projectName,dateOfCreation,..., Primary_Key(wallName, projectName));
Post(post_id, wallName,postData,..., Primary_Key(post_id), Foreign_Key(wallName, projectName));
The virtual white board has a composite primary key (wallName, projectName) and each post has a post_id as primary key
Question: Take the primary keys from VirtualWhiteBoard and Post and add it to the new relation 'has_posts':
|VirtualWhiteBoard| -1------*- |has_Post| -*------1- |Post|
To keep the previous relationships intact and then drop the foreign key column of wallName in Post.
How best to achieve this? Would a query suffice or stored procedures would be required?
(Although I can do this in the 'application' I'd prefer to do it this way, since such refactorings are bound to arise and I don't want unnecessary java-code lying around that'll need to be maintained and would personally prefer to have such a skill too :)
Create your has_Post table with two columns post_id and wallName and populate it with this query:
INSERT INTO has_Post(post_id, wallName) SELECT post_id, wallName FROM Post
Then delete the wallName column from Post table.

What should i call this table to follow cakePHP naming conventions?

I have a main Users table, but then i have a secondary Users_Info table, that contains personal info of every user, to follow the cakePHP naming conventions, how should I name this table if its supposed to be plural?
Thanks
Why not use something more intuitive like say a "profiles" table? Unless you are already using that for something else in your app. In your case remember that only the last word in your table name needs to be plural. Note that "users_infos" table sounds more like name for a HABTM table, only when following cake conventions you would order the table names alphabetically as "infos_users" for a HABTM table (http://book.cakephp.org/view/1044/hasAndBelongsToMany-HABTM). So to answer your question you should be able to simply add an s to your table name as stated above and it should work.
cheers
What serialk says is true: using a "profiles" table is the best schema design. Nevertheless, if you are unable to use "profiles" table, and since each user will generally have a single profile (Unless your application is providing option of multiple profile identities for each user), I guess you won't be needing a HABTM table "infos_users".
Coming to Cake's conventions, the conventions are designed to be as close to real world as possible. The table where books are stored is called Books and where categories are stored is called Categories. But the table where news is stored is still called as News and the table where information is stored is still called as Information, not Informations.
So, you can safely proceed using users_info table. It is not a violation of Cake's conventions. Cake will generate a UsersInfo model and a UsersInfo controller which you can use without any issue even though both or singular.