What's the meaning of foreignKey in Sequelize.hasMany/belongsTo? - mysql

I was recently using Sequelize the ORM.
I have two tables. One is Users and the other is Posts
The schema of these two tables are as follows
Users {
id: Integer,
name: String,
age: Integer
}
Posts {
id: Integer, // refers to the id of post itself
author_id: Integer, // refers to the id of the author of this post
title: String,
content: String
}
I want to create an one(Users)-to-many(Posts) association between them. In order to do that, I need to specify the hasMany & belongsTo in the models.
However, I am very confused about the meaning of the parameters foreignKey / sourceKey / targetKey.
Say that I already define and create my table with migrations. The name of the attribute which is the foreignKey is author_id in this case.
My guess is, in belongsTo, foreignKey means "the name of the attribute that is going to be foreignKey in the source table"?
But in hasMany, foreignKey means "the name of the attribute that is referenced by the coming foreignKey"
So, foreignKey in belongsTo will be author_id (in table Posts) but foreignKey in hasMany will be id (in table Users) ?
Furthermore, what on earth do the sourceKey/targetKey mean!?

Well... you have an interesting case above... if you used user_id instead of author_id then you might get away without declaring these as sequelize might assume them correctly... However because you named it author_id then your hasMany definitely needs to know that the foreign key is named author_id in your post table... Let's say that you named your id in the user table something like "user" instead of "id".... well sequelize won't understand that and be able to infer what it is joining on, so you would say the the sourceKey = "user" and foreignKey = "author_id"... To further that one more you may run into issues in database design where you need to specify what the targetKey or otherKey is because someone was naming things whacky... so like you said above in your belongsTo author_id would have no clue that it was supposed to map back to "user" for it's join, so you would specify foreignKey = "author_id" and otherKey = "user"... This stuff took me a while to wrap my head around as well because i did not get to design the database i implements graphql/sequelize against... Therefore i had to make wide use of sourceKey, targetKey, and otherKey etc etc in my joins..
Try and think of it really logically and it will make more sense... if your primary key is always "id" and your foreignKey is always "tablename_id" then you won't need to worry too much about the other properties.. but when naming doesn't line up, sequelize needs to be told what keys to use, and that is why those other properties exist.. Sequelize is damn smart, but it can't make up for poor db design or bad join column naming... Hope this helps, if not i have plenty of examples i can post for you.. Cheers

Related

Mysql avoid redundant foreign keys

I have the following database schema:
t_class: Stores metadata about a class (primary key: class_ID)
t_students: linked to class by foreign key class_ID
t_exams: Stores metadata about an exam (no foreign keys so far)
t_grades: Links t_exams to t_students as the both having a n to m relationsship (has no primary key, but two foreign keys: exam_ID and student_ID). It also has the column grade which stores the result of each student in an exam.
The problem: It is possible that t_grades has no entries for a particular exam. With the current schema there's no way to get all exams of a class if t_grades has no entry.
My solution:
a) Add a key class_ID to t_exams. Downsides: It is more a less a redundant key and I can't add it as a foreign key (results in mysql error 1452)
b) Automatically add all students of a class to t_grades and just leave t_grades.grade empty. This feels very redundant as well.
Question: Is there a better way to solve this specific problem or should I stick with one of my solutions?
Create Code:
Sample database from this post
From the actual database I'm using (it's mostly German unfortunately
I really don't like the way you've graphed your database design, but I understand your problem.
In my opinion you should connect the t_exams directly to t_classes, since all students in a class should take the exam. So, that's your first solution.
In simple terms: A student belongs to a class, a class can get an exam, and an exam, a student took, can be graded.
This seems like a perfectly logical design to me. I don't get why you cannot implement this? I guess we need to see your CREATE TABLE queries?
I agree: My graph is also far from perfect, but just like with yours: I hope you get the idea.

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

Rails table association with ENUM column

Given the table uploads which holds the relation between 4 different apps and users:
field type
dogTag int (foreign key to dvd)
app enum
uploader int (foreign key to user)
mod string
...
And the table dvds:
dogTag int (primary key)
title string
...
And the table users:
id int (primary key)
...
How can I properly construct a model relations between the dvds table and the uploads table within Rails if it depends on an ENUM column?
With sql I simply do:
JOIN uploads ON uploads.dogTag = dvds.dogTag
WHERE uploads.app = 'dvd'
But have no idea how to create this relationship in Rails and haven't found a lot of info on this.
Thanks
I don't have too much idea on how to create relation with enum column,but if it's a four model in your app that has one upload model then you can use polymorphic association,ryan has great railscasts
Well you could re-organise your db to make the enum type a look up table, you could create a non-persistent model to implement it.
Thing is if you had started from the model instead of the database, you wouldn't have gone anywhere near mysql's enum type, and that's why you are struggling to find much, you've gone at it bass ackwards.
My advice get rid of it...

Database Design w/ Foreign Keys Question

I'm trying to use foreign keys properly to maintain data integrity. I'm not really a database guy so I'm wondering if there is some general design principle I don't know about. Here's an example of what I'm trying to do:
Say you want to build a database of vehicles with Type (car, truck, etc.), Make, and Model. A user has to input at least the Type, but the Make and Model are optional (if Model is given, then Make is required). My first idea is to set up the database as such:
Type:
-id (PK)
-description
Make:
-id (PK)
-type_id (FK references Type:id)
-description
Model:
-id (PK)
-make_id (FK references Make:id)
-description
Vechicle:
-id (PK)
-type_id (FK references Type:id)
-make_id (FK references Make:id)
-model_id (FK references Model:id)
How would you setup the FKs for Vehicle to ensure that the Type, Make, and Model all match up? For example, how would you prevent a vehicle having (Type:Motorcyle, Make:Ford, Model:Civic)? Each of those would be valid FKs, but they don't maintain the relationships shown through the other tables' FKs.
Also, because Model isn't required, I can't just store the model_id FK and work backwards from it.
I'm not tied to the database design at all, so I'm open to the possibility of having to change the way the tables are set up. Any ideas?
P.S. - I'm using mysql if anyone's interested, but this is more of a general question about databases.
Edit (Clarifications):
-type_id and make_id are needed in the vehicle table unless there is some way to figure those out in the case that model_id is null;
-the relationships between type_id, make_id, and model_id need to be maintained.
What you are looking for is a CHECK constraint. Unfortunately MySQL does not currently support this. You could emulate such functionality with triggers but you would need to create both an INSERT and an UPDATE trigger for it to work.
However, as other answers have indicated, all you should really be storing is the vehicle model. In you application you should be drilling down to the type if it's available.
Like this:
Type:
id (PK)
description
Make:
id (PK)
type_id (FK references Type:id, not null)
description
Model:
id (PK)
make_id (FK references Make:id, not null)
description
Vechicle:
id (PK)
model_id (FK references Model:id)
Basically don't double reference make and type from vehicle as well. You'll run into problems if you do that. You can get the make and type from the model of the vehicle (if defined). Model must have make. Make must have type.
Think about that for a second: if vehicle has a given model but vehicle and model both have a make, those values can be different. This kind of inconsistency can develop because of information redundancy. You want to avoid that generally.
If you need to figure out the make and type of a vehicle the SQL starts to look like this:
SELECT v.id, v.model_id, m.make_id, k.type_id
FROM vehicle v
LEFT JOIN model m ON v.model_id = m.id
JOIN make k ON m.make_id = k.id
JOIN type t ON k.type_id = t.id
And so on.
Here is one approach:
- One make (Ford, GM, Honda) can have many models, one model belongs to only one make.
- Model is of a certain type (car, truck bike).
- Vehicle is of a certain model. One vehicle can be of only one model; there can be many vehicles of a model.
Model table contains columns common to all models; while car, truck, and motorcycle have columns specific to each one.
When modeling a DB, consider data, entities and relationships; don't start from the UI -- there is a business layer in between to sort things out. It is OK to use MySQL, you can enforce check and foreign key constraints on your application layer.
Your design is fine for data integrity, it will be the job of your application to maintain that a Vehicle must be made up of Makes from a particular Type and Models of a particular Make.
If you want to maintain vehicle type/make/model integrity in the database you could add a check constraint to your Vehicle table that makes sure the Vehicle's make's type id equals the provided type id. And if the model id is not null, make sure it's make id is the same as the make id provided.
I see you already accepted an answer, but an alternate approach that handles your actual structural problem and doesn't use triggers or check constraints would be to create dummy entries in the Make and Model tables with a description of "n/a" or such, one for each entry in Type and Make respectively, and then get rid of the redundant columns in Vehicle.
That way, if all you know is the Type of a vehicle, you'd find the dummy entry in Make that references the appropriate Type, then find the dummy entry in Model that references that Make, then reference that Model from the new row in Vehicle.
The main downsides of course would be extra housekeeping to create the dummy rows, either ahead of time when adding a Type or Make, or on demand when adding a Vehicle with missing data.

Define a one-to-one relationship with LinqToSQL

I'm playing around with LinqToSQL using an existing multi-lingual database, but I'm running into issues mapping a fairly important one-to-one relationship, so I suspect I am using the feature incorrectly for my database design.
Assume two tables, Category and CategoryDetail. Category contains the CategoryId (PK), ParentId and TemplateId. CategoryDetail contains the CategoryId (FK), LanguageId, Title and Description (in the appropriate language), with a combined PK of CategoryId and LanguageId.
If I drag-and-drop these tables into the LinqToSQL designer, the resultant object model has Category with a collection of CategoryDetail objects, which should never be the case. I'd like to be able to filter on LanguageId at the DataContext level, meaning that the whole Category is encapsulated within Category.CategoryDetail, not all language version encapsulated within Category.CategoryDetails.
This database worked fine on my old object library (an old-school custom BOL and DAL), but I fear that LinqToSQL would require this to change in order to give me the required result.
What is the best way to make this relationship (and language filtering) as seamless as possible?
You can view properties of the association. (Right click on the line representing the association and show properties.) The properties will tell you if it is a one-to-one or one-to-many relationship. This is reflected in code by having either a single entity association (one-to-one) or an entity set association (one-to-many).
I would have to assume cant be a true 1 to 1. Sounds like you have a PK of CatID and Lang ID on the Cat Details table. That would explain why its putting a collection. I could be wrong as you didnt mention the PK's of the CatDetails table
EDIT: A combined Pk of CatID and Lang ID makes that a 1:m relationship, and Linq to SQL is actually doing the correct thing. The only way it could possibly be a true 1:1 is if you had a lang ID on the cat table as well and that was part of the FK. I htink you may have to rethink what you want to do, or how you want to implement it.
I think LINQ to SQL models the database structure directly.
You have two tables so it creates 2 objects.
Have you had a look at LINQ to Entities this allows you to create another layer above the database strucure to make for more readable classes.
Since you don't have a 1:1 relationship the mapping alone will not provide the desired functionality. However it is easy to provide a method in the parent auto-generated class that does the job:
public partial class Category
{
public IEnumerable<CategoryDetail> GetDetailsByLanguage(string langID)
{
return this.CategoryDetails.Where(c => c.LangID == langID);
}
}