Inserting using id in many-to-many relationship in SQLAlchemy - sqlalchemy

Suppose I have an Article model and a Tag model in a many-to-many relationship using an association table. The tag has attributes id (primary key) and tag_name. Articles have many tags.
I want to create a new Article with tags, and I have the ids of existing tags to be added.
I have something like this:
self.tags = [ Tag.query.filter_by(id=tag_id).first() for tag_id in tag_ids ]
(I am using Flask-SQLAlchemy.)
How do I do this without unnecessarily querying for the Tag objects?
I want to in effect just insert the tag_id, article_id association in the association table; can I do this without using a raw statement?

If you have the association table mapped directly, like TagAssociation, then you can just create TagAssociation(article_id=x, tag_id=y). If OTOH the table is only present in the secondary argument of relationship(), the ORM doesn't have a direct system, you'd need to run an insert(), though you'd use Session.execute(), that is, Session.execute(assoc_table.insert(), params={"article_id": x, "tag_id": y}).

Related

Is having relationships to a pivot table a good idea?

Suppose we have the following tables:
companies
id
name
...
categories
id
name
category_company
category_id
company_id
Now, for each category the company belongs to we need to store the products they offer for that category. I'm wondering if it's a good idea to add an auto-incrementing primary key to the pivot table and then use that id on the products table as shown below.
category_company
id
category_id
company_id
products
id
category_company_id
name
Is there a better way to handle this? In the real proyect that I'm working on I have 5 more tables that depend on the category company relationship.
There are other approaches to your problem, but yours is correct too. You may or may not have the id in your category_company table, depending on if you are using some specific framework or ORM, but as #AndrewShmig stated you don't need it.
IMPORTANT: Remember you are building many-to-many relationships, so you need to add a primary key or unique compound index to 'category_company' table on columns 'category_id' and 'company_id', even if you are keeping the 'id' column. You don't want the same Company listed twice in a Category, or vice versa.
In MVC model ORM's your approach (with an 'id' in category_company / pivot) is prefered, because you can assign additional information to the relationship itself, treatening your pivot table like another object.
Is not the same, but think of these two cases:
If you are a more Object Oriented programmer, something like the second option may fit your needs (which is kind of what you have), plus you can add extra information for the relationship like 'categorized_by', 'date_of_categorization' or something like that.
*If you have 5+ tables that depend on that relationship (like 'products'), of course handling the relationship in an intermediate table is way better than to have 'category_id' and 'company_id' fields in each of them.
Sources:
http://guides.rubyonrails.org/association_basics.html#the-has-and-belongs-to-many-association
Many-to-many relationships examples

How do I add mulltiple records and avoid using multi-field values?

I'm creating a database for personnel records and trying to ease record creation for the user and avoid a kludgy solution. The tables are:
people:
people_id,
person_name,
person_category_id
person_category:
person_category_id,
person type
document_requirement:
document_requirement_id,
document_requirement_name,
person_category_id,
document_section_id
document_section:
document_section_id,
document_section
I've created an append query (inner join) that populates a table caLLed document_repository which contains all of the required documents for all of the people. (I use a primary key composed of people_ID & document_id to avoid duplicates when the append query runs.) Here is the document_repository table.
document_respository:
document_repository_id,
people_id,
person category_id,
document_id,
document_section_id,
document_attachment
I'd like to be able to allow the user to create a document requirement that is applicable to multiple person categories. I understand I should avoid multi field values, which doesn't work anyway with inner joins. For example, if people categories include doctors and nurses, I'd like to be able to create a new document requirement that applies to both people categories (e.g., doctors and nurses), without having to create two separate document requirements.
More information needed?
Suggestions on design changes and/or queries?
Thanks!
snapshot of tables and relationships
What you describe is a many to many relationship. Each document requirement can be applicable to multiple person categories and different document requirements can be applicable to the same person category.
To have a many to many relationship between two entities (tables) in your database, you need another table to relate them. This additional table contains the primary key of both tables and each record in this table represents a link between the two entities.
Your naming is different between your text and your diagram, but I'll assume you want to have document_requirement records that can link to zero or more person_category records.
You need a table which for example could be called document_requirement_person_category and contains the following fields:
document_requirement_id - foreign key referencing PK of document_requirement
person_category_id - foreign key referencing PK of person_category
You then add a record to this link table for each person category that relates to each document requirement.
Edit: BTW, (if I'm reading your schema correctly), you already have a many to many relationship in your schema: document_repository allows a relationship between multiple people and a document requirement as well as multiple document requirements and a person. That's a many to many relationship.

1 table or 2 tables?

I have table called UserComments.
It contains 3 columns:
id, user_id, and comment_id.
I query this table 2 separate ways.
1 by user id and
1 by comment id. Both of these fields are indexed.
I want to add an additional column tags.
I will only need this column when querying by comment id.
Does it make more sense to add the column to the existing table (and not return it back to avoid data transfer)?
OR
Create a new table and perform the join when necessary?
Why is 1 better than the other?
You should use a separate table for the specific purpose of tags.
Lets take this stack overflow question as an example. You have created a question with 3 tags. This means that ONE comment has THREE tags or in other words a one-to-many relationship.
The proper way to model one-to-many is with a separate table. Now, lets look at the differences.
One Table:
You will have one table. You will not be able to model a one-to-many so you will have to create your own method for having multiple tags such as a CSV for the tags.
example:
id, user_id, comment_id, tags
'2', '276', '2738', 'mysql,sql,sql-server'
Can you see how this is getting confusing already? You will need to write your own code to parse out the csv. Now, imagine you wanted to search by tag. Oh man... the nightmare that will become.. and the slowness if you use a sql regex or like...
On the other hand, a two table would have a second table
comment_id, tag
123, mysql
123, sql
123, sql-server
You grab all entries with 123, you have your list. Now if you want to search by tag, EASY.
My guess is you already have a separate table somewhere else for users, and you grab all users comments using this comment table. You did that inherently because users and comments are a one-to-many relationship. Same concept here.
Adding as answer because consensus agrees:
Generally speaking, more tables is better. Reason being, you want to avoid redundant data. Your User table should be on it's own. Your comments table should have it's own ID and a field for the UserID - join on that. And subsequent things you need that are not comments or new users should have their own tables with the same scheme.
From this you will have the benefit of having your Users sitting on their own, and be able to easily join each user to an indefinite number of comments with no redundancy.
I would do something like this. I would create a table just for tags rather then having a column containing n instances of say 'sql-server' tag when you can related it to a Tag table. So sql-server has an id of 1. int 1 over varchar 'sql'server' takes less space plus allows easy expand on.
Comment
CommentID
..etc
UserComment
UserCommentID
CommentID
UserID
CommentTag
CommentTagID
UserCommentID
TagID
Tag
TagID
Description

Designing complex relations tables

I have some problems with database projecting.
I have some item types, let's say those are "news", "articles", "files", etc.
Also I have "categories" table to store categories for each type. Type is specified in special field "category_type". So there're defined constants in my application code: news = 0, articles = 1, files = 2, etc.
Now the question is - what will be the correct way to build connections tables?
One way: I can create several tables for each type - "news2categories", "articles2categories", "files2categories", etc.
And the second option is to build one global table, which will have 3 fields "item_id (int), item_type (int), category_id (int)". Well actually I already have one global table for categories with type division by one field only. But is it the right way? I don't want to spawn dozens of identical tables, but on the other hand relations with one table and multiple types are seem to be too abstract and complex. Please advise.
DB will be used by Yii framework mainly, if it makes any sense in solving this problem.
What is the difference between articles, news, and files? Can a each of these have multiple categories (many-to-many)? Assuming yes on the many-to-many need of multiple categories to each type (article, news, etc...) and that they are each sufficiently different from each other, I'd have the following tables:
category
news
category_news
article
article_category
file
category_file
Each category linking table would have 2 columns: category_id and item_id (news_id, article_id, etc...)
I use the db coding standard of naming all db tables in the singular (feel free change to plural -ack- if Yii does otherwise) and having my linking tables the name of each linked table separated with an underscore (names in alphabetical order).
Whatever you do, be consistent.
First way seems problematic since you might want your design to be flexible with adding / removing different types. If you add new type, you will have to add a new table, which I feel is not a good design.
How about this design.
Table : Category,
Columns :
CategoryID (PK)
TypeID (FK to Types table.)
Table : Types, Columns: TypeID (PK), TypeValue
Store Types news, article, etc in Types table. This will make design more flexible with adding or removing types and categories.

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);
}
}