Does a foreign key need to appear in children of children? - foreign-keys

I have a set of tables with children of children, like so:
Clients (PK ClientID) which is parent (one to many) to
Property (PK PropertyID, FK ClientID) which is parent (one to many) to
Property Detail (PK PropDetailID, FK PropertyID) and Case (PK CaseID, FK PropertyID).
Should the foreign keys for the parent tables be repeated further down? That is, should my tables look like this:
Clients (PK ClientID)
Property (PK PropertyID, FK Client ID)
PropertyDetail (PK PropDetailID, FK PropertyID, FK Client ID)
Case (PK CaseID, FK PropertyID, FK ClientID)
instead? And if neither setup is normalized, what's the normalized way to do this?

No, the foreign keys should not be repeated because you can access this information with a simple join. Adding it to the grandchildren adds redundancy which can give problems when the two get out of sync. Your first design looks better than your second.
Depending on the meaning of the word property it could be that you are using an entity attribute value (EAV) model to store client properties. There are some situations where an EAV model is appropriate but in general you should try to avoid it. If possible try to use a fixed schema instead.
Further reading:
EAV FAIL

You don't need to have both Foreign keys for PropertyDetail/ Case. These ones can be navigated to.

There's no need to have the foreign keys repeated further down -- you can determine a property detail's ClientID by looking at the Property's ClientID.
All the information you need can be determined by simple joins.

Related

Define unique columns on ManyToMany in Doctrine

I'm trying to add unique columns on a pivot table created via a ManyToMany association.
I found this page of the documentation explaining how to generate a database unique constraint on some columns with this example:
/**
* #Entity
* #Table(name="ecommerce_products",uniqueConstraints={#UniqueConstraint(name="search_idx", columns={"name", "email"})})
*/
class ECommerceProduct
{
}
But this only works if I create the pivot table via a third entity and, in my case, I created the pivot table using a ManyToMany relation (in the same fashion as this code).
Is there a way to add unique columns on pivot table while still using ManyToMany or do I need to rely on a third entity?
While #Table annotation proposes a uniqueConstraints option, #JoinTable does not. Thus, if you want to add a unique constraint on your association table, you will have to actually create another entity explicitly.
That being said, the default join table should not need anything more than the default configuration set up by Doctrine. Currently, when adding a ManyToMany association, the join table is composed of two fields and a composite primary key relying on both fields is created.
If your association table only contains the two basic fields referring to both sides of your association (which is necessarily the case if you use #ManyToMany), the composite primary key should be all you need.
Here is the generated SQL for the basic example where a User has a ManyToMany association with Group (from this section of the documentation):
CREATE TABLE users_groups (
user_id INT NOT NULL,
group_id INT NOT NULL,
PRIMARY KEY(user_id, group_id)
) ENGINE = InnoDB;
ALTER TABLE users_groups ADD FOREIGN KEY (user_id) REFERENCES User(id);
ALTER TABLE users_groups ADD FOREIGN KEY (group_id) REFERENCES Group(id);
As you can see, everything is properly set up with a composite primary key which will ensure that there can't be duplicate entries for the couple (user_id, group_id).
Of course there is another alternative, Alan!
If you need a Zero to Zero relationship, the only alternative is defining the unique constraint per each pk in the agregated table, to make doctrine figuring out about zero to zero relationship.
The problem is that Doctrine's people hadn't considered zero to zero relationships, so the only alternative for this is manytomany relationship with one unique constraint per pk.
If you have doubts about final-state of your doctrine implementation of your E-R model, I strongly recommend mysql-workbench-schema-exporter. With this php tool, you can easily export your mysql workbench E-R schema to a Doctrine's working classes schema, so you would be able to easily explore all your alternatives ;-)
Hope this helps

Change primary key on manytomany field Django

Is it possible to change primary key of many to many field from default to uuid?
Table is already populated. What is the best way for migration?
You can create a migration that executes raw queries, add a new field to the table in the middle then generate the new UUID.
After that, another set of queries to drop the constraints on ID, add the new constraints to the new UUID field, and lastly drop the old ID field.
https://docs.djangoproject.com/en/2.0/ref/migration-operations/#runsql

Which is better? city.state.id or city.state_id

I have to table with relation.
State
id
name
City
id
name
state
Which is better in performance?
city.state.id or city.state_id
city.state_id is better anyway. city.state will do another fetch from database.You can avoid this using select_related.If you need only id of foriegn key, no need of select_related here.Just do city.state_id(since foriegn key id will fetch in the query which gives city object).
city.state_id is better than city.state.id. Because It makes only a query instead of two.
BTW, You can use Django Debug Toolbar for debugging queries.
the <field>_id field you see is the database column name
docs
Behind the scenes, Django appends "_id" to the field name to create its database column name. In the above example, the database table for the Car model will have a manufacturer_id column
So this means it doesn't need to make a separate query to retrieve the foreign key instance (See Select a single field from a foreign key for more details).
But this assumes you haven't used select_related or prefetch_related

Creating 'taggable' relationships

Say I have two tables that can have 'tags' associated with them. With potentially more in the future.
tracks -
id, title, artist, etc...
artists -
id, name, description, etc...
I want to be able to have a general table called 'tags'
tags -
id, title, description
How would I construct the joining table to create the relationship? Is it possible to have it such that foreign keys are applicable to both artists and tracks table?
I was thinking of a structure similar to:
tag_relations -
tag_id (foreign key to tags.id), item_id (either artists.id or tracks.id)
Is this a bad design not having any foreign key integrity on the item_id?
Laravel supports polymorphic relationships which I believe suit the purpose that I require. You can read up about them here.
http://four.laravel.com/docs/eloquent#polymorphic-relations

django models complex query

I have 3 tables say, TextObj, User, SecurityCheck. The third table has a Foreign Key attribute (textobj) referencing TextObj and there is a many-to-many field (sharedWith) from SecurityCheck to User.
class SecurityCheck(models.Model):
textobj=models.ForeignKey(TextObj)
owner=models.CharField(max_length=255)
sharedWith=models.ManyToManyField(User)
def __init__(self,owner,filename,requestingUsername):
self.owner=owner
self.textobj=TextObj.filter(filename=filename)
self.sharedWith.add(User.objects.filter(username=requestingUsername))
I need to do a query which fetches all the instances of Textobj which have a particular user in the sharedWith field and a particular filename(which is an attribute of TextObj)
You can easily do queries that span (reverse) relationship:
TextObj.objects.filter(securitycheck__sharedWith=user, filename="foo")
https://docs.djangoproject.com/en/dev/topics/db/queries/#lookups-that-span-relationships
Django offers a powerful and intuitive way to “follow” relationships in lookups, taking care of the SQL JOINs for you automatically, behind the scenes. To span a relationship, just use the field name of related fields across models, separated by double underscores, until you get to the field you want.
It works backwards, too. To refer to a “reverse” relationship, just use the lowercase name of the model.