Why does `has_one` in rails require a foreign key? - ruby-on-rails

Consider two tables Foo and Bar and consider models based on them. Now consider a one-to-one relationship between them.
Foo contains has_one :bar in it's declaration so that we're able to access Bar from Foo's objects. But then what I don't understand is why Bar needs a foreign key referencing Foo?
Shouldn't it be easier if they just compare both the ids to get the result?
I'm assuming that there will be problems with comparing both ids and I want to know what the problems are.

The problem with ids is that they store auto-incremented values. Let's consider 2 tables students and projects.
Let's assume a student can have at most 1 project. Which means he can either have a project or not.
Now consider 2 students A & B.
students table
id name
1 A
2 B
now projects table
id name
1 P1
2 NULL
in this case A has a project named as P1 but B doesn't and we're creating a null entry just to maintain and match the id of records present in projects with the students but this is not feasible in the long term. If in a school there are 1000 students then we'll have may be 500 empty rows for 500 students who are not working on a project.
That's why adding a column in projects table is a feasible solution to reduce the size of the table and maintain relationships as well and also if you're going to delete a record then the new id won't be same as the previous one as id's are auto-incremented.
now projects table
id name student_id
1 P1 1
is more feasible and flexible as well. You can make it has_many as well because a student can work on multiple projects as well.
I hope this helps you.

You can't assume that the DB engine will add the same IDs to rows in different tables. You can (I would not recommend) make an app with such behavior and implement it with triggers and constraints, but this would be a very creative (in a negative sense) approach to relational databases.

Related

Normalizing issue with data history

I have two entities: Location and Employee. Each employee works in a single location at a time. For any given moment in time, the model is as follows:
There is, however, a requirement to also store historical information for all locations and employees for every end-of-month. I can achieve this by adding a Month PK attribute in both entities, but: how do I handle the relationship in that case?
A foreign key has to reference a composite PK in its entirety. Several alternatives come to mind:
Option 1: repeat the Month attribute in the Employee entity to get the full PK as FK attributes. This feels a bit redundant? If an employee has existed in a given month, surely she has to work in a location in the same month - i.e. the two Month attributes have to always have the exact same value:
Option 2: re-use the Month attribute in the PK of the Employee entity as a foreign key referencing Location. I don't even know if this is allowed (note: I'm going to be using SQL Server eventually, if it matters here)?
Option 3: create a separate bridge entity that holds the history of Location-Employee relationships. This feels kind of neat, but then again I have some doubts as to whether or not I can use one Month attribute here or if I need two of them. Also, it would allow many-to-many relationships (an employee in several locations on a given month), which is not supposed to happen in this case and I'd like to be able to enforce this in the data model.
Am I missing something obvious here? What is the "correct" and properly normalized solution? Or should I just leave the FK constraints out?

Entity Framework many-to-many relation with filter in mapping

I'm trying to create a relation using Fluent API, but I can't get it to work. There are 2 tables: SecurityEntities and SecurityEntityRelations. The SecurityEntities table contains users and groups, the SecurityEntityRelation table is an association table that contains relations between the users and groups (it defines which groups contain which members). I already mamaged to relate the 2 entities within EntityTypeConfiguration:
HasMany(se => se.Groups).WithMany(g => g.Members).Map(seg =>
{
seg.MapLeftKey("ser_EntityName");
seg.MapRightKey("ser_MemberOf");
seg.ToTable("ser_SecurityEntityRelations");
});
This populates the SecurityEntity.Groups and Members properties. But one of the security groups is being concidered a "primary" group, which should be stored in a separate SecurityEntity.PrimaryGroup property. In SQL, this is implemented by a column in the SecurityEntityRelation table, which marks the relation as being "primary". (I know, a self-referencing foreign key in the SecurityEntity table would have been a better solution, but this was designed quite some time ago, and we're stuck with this implementation because our legacy code is also written this way) So, now my question is: how can I create an EF mapping like the one above, which specifies the same relation, but only when column "ser_IsPrimaryGroup" equals a fixed value of '1'?

How to create an Order Model with a type field that dictates other fields

I'm building a Ruby on Rails App for a business and will be utilizing an ActiveRecord database. My question really has to do with Database Architecture and really the best way I should organize all the different tables and models within my app. So the App I'm building is going to have a database of orders for an ECommerce Business that sells products through 2 different channels, a subscription service where they pick the products and sell it for a fixed monthly fee and a traditional ECommerce channel, where customers pay for their products directly. So essentially while all of these would be classified as the Order model, there are two types of Orders: Subscription Order and Regular Order.
So initially I thought I would classify all this activity in my Orders Table and include a field 'Type' that would indicate whether it is a subscription order or a regular order. My issue is that there are a bunch of fields that I would need that would be specific to each type. For instance, transaction_id, batch_id and sub_id are all fields that would only be present if that order type was a subscription, and conversely would be absent if the order type was regular.
My question is, would it be in my best interest to just create two separate tables, one for subscription orders and one for regular orders? Or is there a way that fields could only appear conditional on what the Type field is? I would hate to see so many Nil values, for instance, if the order type was a regular order.
Sorry this question isn't as technical as it is just pertaining to best practice and organization.
Thanks,
Sunny
What you've described is a pattern called Single Table Inheritance — aka, having one table store data for different types of objects with different behavior.
Generally, people will tell you not to do it, since it leads to a lot of empty fields in your database which will hurt performance long term. It also just looks gross.
You should probably instead store the data in separate tables. If you want to get fancy, you can try to implement Class Table Inheritance, in which there are actually separate but connected table for each of the child classes. This isn't supported natively by ActiveRecord. This gem and this gem might be able to help you, but I've never used either, so I can't give you a firm recommendation.
I would keep all of my orders in one table. You could create a second table for "subscription order information" that would only contain the columns transaction_id, batch_id and sub_id as well as a primary key to link it back to the main orders table. You would still want to include an order type column in the main database though to make it a little easier when debugging.
Assuming you're using Postgres, I might lean towards an Hstore for that.
Some reading:
http://www.devmynd.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination
https://github.com/devmynd/hstore_accessor
Make an integer column called order_type.
In the model do:
SUBSCRIPTION = 0
ONLINE = 1
...
It'll query better than strings and whenever you want to call one you do Order:SUBSCRIPTION.
Make two+ other tables with a foreign key equal to whatever the ID of the corresponding row in orders.
Now you can keep all shared data in the orders table, for easy querying, and all unique data in the other tables so you don't have bloated models.

How to Manage Dynamic Relationships?

I need help creating an appropriate database structure that will allow me to dynamically create "fields" and "values". I plan on using the following 5 tables.
TraitCategories
Groups
TraitGroupings
People
TraitValues
TraitCategories table holds only categories (i.e. "fields") of traits -- i.e. hair color, height, etc. -- and the categories can be added/removed as desired.
Groups table holds ad hoc/dynamic group labels -- i.e. Asian, South American, etc.
TraitGroupings is the join table for TraitCategories and Groups
The People table will be linked to the Groups table via a foreign key and thus will be assigned various categories (fields) of traits by leveraging the relationship between the Groups and TraitCategories tables.
But the question is, how do I assign per person values to the trait categories/fields?
I was thinking of having each row in the TraitValues table contain person_id and trait_category_id so that there will be a relationship between the TraitValues table and both the People and TraitCategories tables. Does this approach make sense? Will this approach allow me to get trait categories and values via the People table?
You are describing a form of EAV.
I'm not sure how practical this is going to be for representing in Ruby, but in you case, the database model would look similar to this:
(Most non-key fields omitted, for brevity.)
Note how we abundantly use the identifying relationships. This is what lets us propagate GroupId down both sides of the "diamond-shaped" dependency, and merge it into a single field at the bottom, in TraitValue.
This is what ensures a person cannot have a trait, unless it is also listed for that person's group. For example, a person can have a "hair color" only if the person's group has the "hair color" as well.
BTW...
The People table will be linked to the TraitGroupings via a foreign key -- and thus will be assigned various categories (fields) of traits.
If People has a FK that directly references TraitGroupings, then a person can have at most one trait grouping and therefore at most one trait category. From the wording of your question, that desn't appear to be what you want.

SQL Relationships

I'm using MS SQL Server 2008R2, but I believe this is database agnostic.
I'm redesigning some of my sql structure, and I'm looking for the best way to set up 1 to many relationships.
I have 3 tables, Companies, Suppliers and Utilities, any of these can have a 1 to many relationship with another table called VanInfo.
A van info record can either belong to a company, supplier or utility.
I originally had a company_id in the VanInfo table that pointed to the company table, but then when I added suppliers, they needed vaninfo records as well, so I added another column in VanInfo for supplier_id, and set a constraint that either supplier_id or company_id was set and the other was null.
Now I've added Utilities, and now they need access to the VanInfo table, and I'm realizing that this is not the optimum structure.
What would be the proper way of setting up these relationships? Or should I just continue adding foreign keys to the VanInfo table? or set up some sort of cross reference table.
The application isn't technically live yet, but I want to make sure that this is set up using the best possible practices.
UPDATE:
Thank you for all the quick responses.
I've read all the suggestions, checked out all the links. My main criteria is something that would be easy to modify and maintain as clients requirements always tend to change without a lot of notice. After studying, research and planning, I'm thinking it is best to go with a cross reference table of sorts named Organizations, and 1 to 1 relationships between Companies/Utilities/Suppliers and the Organizations table, allowing a clean relationship to the Vaninfo table. This is going to be easy to maintain and still properly model my business objects.
With your example I would always go for 'some sort of cross reference table' - adding columns to the VanInfo table smells.
Ultimately you'll have more joins in your SP's but I think the overhead is worth it.
When you design a database you should not think about where the primary/foreign key goes because those are concepts that doesn’t belong to the design stage. I know it sound weird but you should not think about tables as well ! (you could implement your E/R model using XML/Files/Whatever
Sticking to E/R relationship design you should just indentify your entity (in your case Company/supplier/utilities/vanInfo) and then think about what kind of relationship there is between them(if there are any). For example you said the company can have one or more VanInfo but the Van Info can belong only to one Company. We are talking about a one – to- many relationship as you have already guessed. At this point when you “convert” you design model (a one-to many relationship) to a Database table you will know where to put the keys/ foreign keys. In the case of a one-to-Many relationship the foreign key should go to the “Many” side. In this case the van info will have a foreign keys to company (so the vaninfo table will contain the company id) . You have to follow this way for all the others tables
Have a look at the link below:
https://homepages.westminster.org.uk/it_new/BTEC%20Development/Advanced/Advanced%20Data%20Handling/ERdiagrams/build.htm
Consider making Com, Sup and Util PKs a GUID, this should be enough to solve the problem. However this sutiation may be a good indicator of poor database design, but to propose a different solution one should know more broad database context, i.e. that you are trying to achive. To me this seems like a VanInfo should be just a separate entity for each of the tables (yes, exact duplicate like Com_VanInfo, Sup_VanInfo etc), unless VanInfo isn't shared between this entities (then relationships should be inverted, i.e. Com, Sup and Util should contain FK for VanInfo).
Your database basically need normalization and I think you're database should be on its fifth normal form where you have two tables linked by one table. Please see this article, this will help you:
http://en.wikipedia.org/wiki/Fifth_normal_form
You may also want to see this, database normalization:
http://en.wikipedia.org/wiki/Database_normalization

Resources