I have an existing data model where I can rename things freely to match CakePHP's conventions. I have a type of graph node, where a node can have an arbitrary number of child nodes and an arbitrary number of parent nodes (uni-directional relationships).
Here's the table of nodes, following CakePHP's conventions:
Table: nodes
Column: node_id (INT)
Column: description (TEXT)
My question is what the join table should look like? Here is what it looks like now:
Table: nodes_nodes
Column: parent_node_id (INT)
Column: child_node_id (INT)
And what the documentation implies it should be:
Table: nodes_nodes
Column: node_id (INT)
Column: node_id (INT)
Notice that two column names are the same, which obviously won't work. What should these two columns be called? Or can CakePHP's conventions not handle this situation without configuration?
As neilcrookes noted, there are some articles on this on the web about doing this in CakePHP. Here is one of them, using User HABTM User (friends) as an example.
In that linked article, you can ignore everything after the User class definition if you aren't going to be paginating on the model.
If a node has child nodes, do those child nodes automatically have the first node as a parent?
This relationship may be similar to a users to users relationship where the relationship symbolises the common 'friend' notion in social networks. Suggest you have a google around for user/friend data models to see if that helps.
Related
Problem description
I am currently working on a project which requires a relational database for storage.
After thinking about the data and its relations for a while I ran into a quite repetitive problem:
I encountered a common data schema for entity A which contains some fields e.g. name, description, value. This entity is connected with entity B in multiple n-1 relations. So entity B has n entities A in relation rel1 and n entities A in relation rel2.
Now I am trying to break down this datamodel into a schema for a relational database (e.g. Postgres, MySQL).
After some research, I have not really found "the best" solution for this particular problem.
Some similar questions I have found so far:
Stackoverflow
DBA Stackexchange
My ideas
So I have thought about possible solutions which I am going to present here:
1. Duplicate table
The relationship from entity B to entity A has a certain meaning to it. So it is possible to create multiple tables (1 per relationship). This would solve all immediate problems but essentially duplicate the tables which means that changes now have to be reflected to multiple tables (e.g. a new column).
2. Introduce a type column
Instead of multiple relationships, I could just say "Entity B is connected with n entity A". Additionally, I would add a type column that then tells me to which relation entity A belongs. I am not exactly sure how this is represented with common ORMs like Spring-Hibernate and if this introduces additional problems that I am currently unaware of.
3. Abstract the common attributes of entity A
Another option is to create a ADetails entity, which bundles all attributes of entity A.
Then I would create two entities that represent each relationship and which are connected to the ADetails entity in a 1-to-1 relationship. This would solve the interpretation problem of the foreign key but might be too much overhead.
My Question
In the context of a medium-large-sized project, are any of these solutions viable?
Are there certain Cons that rule out one particular approach?
Are there other (better) options I haven't thought about?
I appreciate any help on this matter.
Edit 1 - PPR (Person-Party-Role)
Thanks for the suggestion from AntC. PPR Description
I think the described situation matches my problem.
Let's break it down:
Entity B is an event. There exists only one event for the given participants to make this easier. So the relationship from event to participant is 1-n.
Entity A can be described as Groups, People, Organization but given my situation they all have the same attributes. Hence, splitting them up into separate tables felt like the wrong idea.
To explain the situation with the class diagram:
An Event (Entity B) has a collection of n Groups (Entity A), n People (Entity A) and n Organizations (Entity A).
If I understand correctly the suggestion is the following:
In my case the relationship between Event and Participant is 1-n
The RefRoles table represents the ParticipantType column that descibes to which relationship the Participant belongs (is it a customer or part of the service for the event for example)
Because all my Groups, People and Organizations have the same attributes the only table required at this point is the Participant table
If there are individual attributes in the future I would introduce a new table (e.g. People) that references the Participant in a 1-1 relationship.
If there are multiple tables going to be added, the foreign key of the multiple 1-1 relationship is mutually exclusive (so there can only be one Group/Person/Organization for a participant)
Solution suggested by AntC and Christian Beikov
Splitting up the tables does make sense while keeping the common attributes in one table.
At the moment there are no individual attributes but the type column is not required anymore because the foreign keys can be used to see which relationship the entity belongs to.
I have created a small example for this:
There exist 3 types (previously type column) of people for an event: Staff, VIP, Visitor
The common attributes are mapped in a 1-1-relationship to the person table.
To make it simple: Each Person (Staff, VIP, Visitor) can only participate in one event. (Would be n-m-relationship in a more advanced example)
The database schema would be the following:
This approach is better than the type column in my opinion.
It also solves having to interprete the entity based on its type in the application later on. It is also possible to resolve a type column in an ORM (see this question) but this approach avoids the struggle if the ORM you are using does not support resolving it.
IMO since you already use dedicated terms for these objects, they probably will diverge and splitting up a table afterwards is quite some work, also on the code side, so I would suggest you map dedicated entities/tables from the beginning.
What is the right plural/singular table naming convention in CakePHP.
This:
posts
posts_pictures
posts_picture_captions <-- Not sure about this
Or this:
posts
posts_pictures
posts_pictures_captions <-- Not sure about this
I know CakePHP want the tables in alphabetical order but this should in this question ignored. Please only consider plural/singular table naming.
Cake Inflector Should do exactly what you are looking to do.
From the cakephp book:
Model class names are singular and CamelCased. Person, BigPerson, and
ReallyBigPerson are all examples of conventional model names.
Table names corresponding to CakePHP models are plural and
underscored. The underlying tables for the above mentioned models
would be people, big_people, and really_big_people, respectively.
You can use the utility library Inflector to check the singular/plural
of words. See the Inflector for more information.
Field names with two or more words are underscored: first_name.
Foreign keys in hasMany, belongsTo or hasOne relationships are
recognized by default as the (singular) name of the related table
followed by _id. So if a Baker hasMany Cake, the cakes table will
refer to the bakers table via a baker_id foreign key. For a table like
category_types whose name contains multiple words, the foreign key
would be category_type_id.
See http://book.cakephp.org/2.0/en/getting-started/cakephp-conventions.html#model-and-database-conventions
So at first, your "posts_pictures" table should be named "post_pictures".
As a result, neither of the two is correct. The correct name according to the cake naming conventions is "post_picture_captions".
I have been asked to add a new address book table to our database (SQL Server 2012).
To simplify the related part of the database, there are three tables each linked to each other in a one to many fashion: Company (has many) Products (has many) Projects and the idea is that one or many addresses will be able to exist at any one of these levels. The thinking is that in the front-end system, a user will be able to view and select specific addresses for the project they specify and more generic addresses relating to its parent product and company.
The issue now if how best to model this in the database.
I have thought of two possible ideas so far so wonder if anyone has had a similar type of relationship to model themselves and how they implemented it?
Idea one:
The new address table will additionally contain three fields: companyID, productID and projectID. These fields will be related to the relevant tables and be nullable to represent company and product level addresses. e.g. companyID 2, productID 1, projectID NULL is a product level address.
My issue with this is that I am storing the relationship information in the table so if a project is ever changed to be related to a different product, the data in this table will be incorrect. I could potentially NULL all but the level I am interested in but this will make getting parent addresses a little harder to get
Idea two:
On the address table have a typeID and a genericID. genericID could contain the IDs from the Company, Product and Project tables with the typeID determining which table it came from. I am a little stuck how to set up the necessary constraints to do this though and wonder if this is going to get tricky to deal with in the future
Many thanks,
I will suggest using Idea one and preventing Idea two.
Second Idea is called Polymorphic Association anti pattern
Objective: Reference Multiple Parents
Resulting side effect: Using dual-purpose foreign key will violating first normal form (atomic issue), loosing referential integrity
Solution: Simplify the Relationship
The simplification of the relationship could be obtained in two ways:
Having multiple null-able forging keys (idea number 1): That will be
simple and applicable if the tables(product, project,...) that using
the relation are limited. (think about when they grow up to more)
Another more generic solution will be using inheritance. Defining a
new entity as the base table for (product, project,...) to satisfy
Addressable. May naming it organization-unit be more rational. Primary key of this organization_unit table will be the primary key of (product, project,...). Other collections like Address, Image, Contract ... tables will have a relation to this base table.
It sounds like you could use Junction tables http://en.wikipedia.org/wiki/Junction_table.
They will give you the flexibility you need to maintain your foreign key restraints, as well as share addresses between levels or entities if that is desired.
One for Company_Address, Product_Address, and Project_Address
From my understanding, cakephp doesn't support database inheritance relationship. However, I want to create a database with different type of Users.
In this case, there are three types of Users: Seller, Customer, and Administrator. Every users should have basic User information such as password, username, etc.
However, each types of users will have its own unique set of datas. For example, seller may have inventory_id while customer may have something like delivery_address, etc.
I have been thinking of creating a workaround to this problem without destroying cakephp convention. I was going to create three additional foreign keys, admin_id, seller_id and customer_id, inside User table, which links to other table. However, knowing that this is an IS-A relationship not HAS-A, I would have to make sure that two of the ids are NULL value. Therefore, this workaround seems ugly to me..
Is there any other simpler, better approach?
For this type of database structure I would probably look at adopting an Entity-Attribute-Value model. This would mean your customer may have a delivery_address and your user may have an inventory_id but as far as your relationship in Cake is concerned your both your user and customer would just have an attribute_id ... you can then create another table that stores what type of attributes are available.
It it's simplest form, your user and customer would be attached to an *attribute_lookup* or *attribute_link* table by a hasMany (probably) relationship. That attribute_lookup/link table would be connected by a belongsTo/hasOne relationship to the actual Attribute Type and Attribute Value models.
Providing that you normalise your tables correctly, you can stick well within Cake relationship conventions.
You can read more about EAV here.
I have been thinking about this problem for some time now, and I have eventually got around to build a solution for it. What I came up with is a new ORM that can be used on top of CakePHP.
It sort of works as CakePHP 3.0 with entities that represent an id/model, but it is much more advanced and supports multi table inheritance and single table inheritance.
Check it out: https://github.com/erobwen/Cream
I have a problem where I am stuck :(. I have to build a relationship of a relationship( strange !).
For example, I have a relation where one entity A can have many B (OneToMany)
A ----> B
Now I need another relationship where an entity C will have an OneToOne relationship with the composite relationship between A and B. Like,
C--> (A--->B) , not C-->A-->B
Not that C will have a relation with A and A has with B,it should be like like C--> D (A --> B).
The generated joined tables does not have any primary key in JPA and now I am thinking How can I map this relationship. Please be noted that the normal A-->B is also needed as this can not be embeddable and it should be persistent.
Thanks.
Example:
Location and Event are my two entities and I want to relate CleanPlan on it. Means one CleanPlan is related to event-1 of location-1. so I am specifying that have a cleanplan on location-1 in event-1. Does that make sense?
I would say this
or this, depending on Event-Location cardinality.
There are two aspects of this problem in JPA.
1) A mapping table is craeted.
2) A mapping row is created instead of mapping table.
I think the 2nd option will make your life easier. But that is only possible if Event and Location has an unidirectional relation. Then on ManyToOne side, put "mappedBy". And that will generate a mapping table on ManyToOne table. And you can refer that column on CleanPlan table.