There is the possibility to disable the #OneToMany relationship join table with the #JoinColumn annotation. The default is a join table.
What are the advantages and disadvantages for a production system for example?
When should I use a join table and when not?
Thank you.
By default #OneToMany will create a join table only if you'll use unidirectional relationship.
In other words, if you have Employee and Project entities and the Employee entity is defined as follows (assume there is no orm.xml entries for these entities):
#Entity
public class Employee {
// ...
#OneToMany
Set<Project> projects;
}
#Entity
public class Project {
// ...
}
the JPA provider will create a join table (notice there is no mappedBy attribute in #OneToMany annotation as there is no reference to Employee entity from the Project).
On the other hand, if you'll use bidirectional relationship:
#Entity
public class Employee {
// ...
#OneToMany(mappedBy="employee")
Set<Project> projects;
}
#Entity
public class Project {
// ...
#ManyToOne
Employee employee;
}
The join table will not be used, as there "many" side will be used to store the foreign key for this relationship.
However, you can force to use join table even in cases when you have bidirectional #OneToMany relationship with defined mappedBy attribute. You can achieve it using #JoinTable annotation on the owning side of the relationship.
There is also a possibility, as you've mentioned, to use #JoinColumn in case where join table would be used by default (unidirectional #OneToMany relationship).
It's best to test the FK and join table performance difference for yourself. I can just guess that less joins (in this case: FK) seems to have better performance.
Moreover, sometimes the DBA defines the database schema and you just need to fit your mappings to the existing schema. Then you have no choice over FK or join table - that's why you have a choice.
Join tables are needed for polymorphisms. E.g., if Employee and Manager links the same project and they are mapped with one-table-per-class strategy, at the relational DB level, the only way to know that project( id = 1, emp_id = 10 ) refers to a manager is to put emp_id in the manager_2_employee table. If one is not in such a situation, then emp_id can go directly into project.
As mentioned in comments above, by default hibernate goes for join table.
This results in better db normalization.
If having a choice, JoinColumn gives better performance over the join table as need for the joining of an extra table in the SQL Query is removed.
Related
I will preface it by saying I'm a database person, moving into .NET, MVC, EF etc. So I fully understand about joins and foreign keys and so on but I am struggling with the EF side.
I worked through a tutorial where we did the following:
create a Student table (StudentID and personal details), a Course table (CourseID and subject details), and an Enrollment table (EnrollmentID, student and course IDs and the grade given to that student for that class).
create Models, Controllers and Views for Student and Enrollment entities to allow editing the name of a Student, enrolling a student for a class and giving them a grade, list out all enrollments, etc.
In that tutorial the Enrollments table is (what I know as) a "bridge" table because student to class is a many-to-many relationship.
So do I only need this "intermediate" model/view/controller if it's a many-to-many scenario like this?
The actual structure I want to program is:
Article (ArticleID, title, author, summary, content...) is a member of a
Category (CategoryID, title, description, ...)
Then I want to have a drop down list (or whatever UI element) of Categories of which clicking on the selected Category will give a page with a table of Title/Author/Summary of the articles that go in that category.
If an Article can be in more than one category ("Effective Use of Catnip" could be under both "Playing Games with Cats" and "Life Hacks") is that where I would need a 'bridge' table?
Please can someone explain in simple terms - whether I am just being put off by the "many to many" nature of the data in that tutorial, or if the 'bridge' table structure is more fundamental to EF for navigating a PK/FK relationship.
I think the tutorial you are reading is trying to introduce you to the basic concepts of EF. If you have a many-to-many relationship, on database side you will always have three tables:
Student
Course
Enrollment (Student_Id, Course_Id)
On EF world, you can represent those three tables as three different entities. However, if you want to have a more "natural" way of representing the relation between Students and Courses, EF allows you to declare many-to-many as two lists:
public class Student {
... properties
virtual List<Course> Courses;
}
public class Course {
... properties
virtual List<Student> Students;
}
However, you need to instruct EF how this references on both side needs to be treated. For that, you can use fluent API. With this fluent API you can define the table name that references both tables/entities:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Student>()
.HasMany<Course>(s => s.Courses)
.WithMany(c => c.Students)
.Map(cs =>
{
cs.MapLeftKey("StudentRefId");
cs.MapRightKey("CourseRefId");
cs.ToTable("StudentCourse");
});
}
Check this article explaining the M:N relationship using fluent library API. Is really simple, and with that you don't need this additional element on the middle.
In terms of UI, you just need to select the list of courses the student want to take, or the list of students the course has to have. Is up to you how you want to present the information to the user, as both functionalities (students taking courses and courses defining its students) point to the same m:n relation.
I think a simple way can be to show a </select> list with the students, and then show the list of courses he can apply to.
The project you want to create uses the same ideas. Basically, with EF you will always need to think in terms of "tables". It is true that EF allows you to abstract your tables to entities, but still you need to follow some rules. To sum up: you are right. The "bridge" table is where you need to store the many-to-many relationships.
If I have the following unidirectional one to many relationship between two domain classes:
class Single {
static hasMany = [ multiples: Multiple ]
}
class Multiple {
...
}
Is there a way to cascade the delete from the Multiple class to the many relationship on Single?
What I have found that works is to add to add an onDelete: Cascade property to the FK that exists on the multiple_id column of the join table via the database script - however what I would really like to do is to express this in the GORM mapping DSL (and without creating a separate domain class to explicitly represent the join table). But there does not appear to be a way to manage relationships on the implicit join table of a uni one-to-many - unless I've missed something.
Is there a reason not to use bidirectional? If not, take a look at http://grails.org/doc/2.4.x/ref/Domain%20Classes/belongsTo.html?
I have a problem in my project.
In one database relations have a join to self with many to many.
What any of people solve this problem in Entity FrameWork?
Any many-to-many relationship should create a new table to represent the pairings.
Example: say you have a table People, and you want to show who gave birthday gifts. A person can give gifts to many friends, and a person may receive gifts from many other people.
CREATE TABLE People (person_id INT PRIMARY KEY);
CREATE TABLE GiftGiving (
from_person_id INT,
to_person_id INT,
PRIMARY KEY (from_person_id, to_person_id),
FOREIGN KEY (from_person_id) REFERENCES People(person_id),
FOREIGN KEY (to_person_id) REFERENCES People(person_id)
);
Re your comment:
For EF implementations, see these related questions:
Many to Many self Join with Entity Framework Code First
Entity Framework many-to-many self-reference
Self-referencing many-to-many recursive relationship code first Entity Framework
I simply put an ICollection to itself. Let EF handle the db layer.
public class Person{
public virtual ICollection OtherPersons {get;set;}
}
I've two domain classes which are bonded with a bidirectional one-to-one relationship to each other, this being implemented using hasOne.
class AssessmentData {
static hasOne = [assessmentField:AssessmentField, assessment:Assessment]
AssessmentField field
}
class Assessment {
AssessmentData assessmentData
}
But I'm quite a bit confused about the way Grails implements this relationship at the database level. As described here, it simply sets the foreign key at the child domain class only, in my case, to the Assessment and AssessmentField tables. Its my primitive instinct that both tables should have a foreign key referring to each other in order to establish a one-to-one bidirectional relationship. But since this is not the case, I wanna know how this is achieved by Grails.
Its my primitive instinct that both tables should have a foreign key referring to each other in order to establish a one-to-one bidirectional relationship
Your instincts have failed you. The domain described in your question will generate these 2 database tables:
assessment_data
----------------
id
assessment
----------------
id
assessment_data_id
Using SQL we can get the assessment associated with an assessment_data with id 4
select * from assessment where assessment_data_id = 4
We can also go the other way and get the assessment_data associated with an assessment with id 5 using
select ad.* from assessment_data ad
inner join assessment a ON a.assessment_data_id = ad.id
where a.id = 5
So if we can "go both ways" in SQL, then we can do it with HQL, criteria queries, dynamic finders, etc. because these all ultimately get translated to SQL.
I have already read Entity Framework One-To-One Mapping Issues and this is not duplicate as the business rule specs are different here.
There are two tables, Invoices and Orders.
Invoices
-> InvoiceID (Primary, Auto Number)
Orders
-> OrderID (Primary, Auto Number)
-> InvoiceID (FK InvoiceID of Invoices Table)
Now the problem is, EF requires One to Many relationship for this association if names of properties are not same. If names of properties are same then it serves purpose of derived class, but here Order is not derived class or Invoice.
InvoiceID(s) are generated for every shopping cart, but OrderID(s) are only generated for paid invoices, so Every Order has InvoiceID but every Order does not have corresponding Invoice.
If I create a seperate table for this, then I have to write too much code to do it. Is there any way I can remove this restriction and let EF still process my model.
However, currently if I change the model as follow, it works
Invoices
-> InvoiceID (Primary, Auto Number)
Orders
-> OrderID (Auto Number)
-> InvoiceID (Primary, FK InvoiceID of Invoices Table)
But is this good practice? Because by definition InvoiceID of Orders table will certainly be unique, but we will be referring everywhere OrderID for comparison and lot of other references. I know I can index the property, but I dont feel this design is perfect.
What seems to be the obvious solution here is to change the 1:* association between Invoice
and Order in the EDM into a 1:1 association. However, as you experienced, the mapping will not
validate when you have a Foreign Key Association between the two entities as in your model.
The only way to map a unique foreign key association is by using an Independent Association. This is the same type of association that we had in EF3.5, where foreign keys were not supported.
To turn the foreign key association into an independent association would mean removing the InvoiceID foreign key from the Order entity and recreating the association through mappings.
To make the change to the association, you’ll need to do the following:
Delete the InvoiceID foreign key property from Order entity.
Select the Asscoation between Invoice and Order.
In the Properties window for the association, open the Referential Constraints by
clicking the ellipses next to that property.
Delete the constraint by clicking the Delete button.
Right-click the association in the Designer and select Table Mapping from the context menu.
In the Mapping Details window, click the element to expose the drop-down.
From the drop-down, select Order. The mappings should populate automatically.
Return to the Properties window for the association.
For the property called “End2 Multiplicity,” which currently has the value * Collection of Orders, change that property to 1 (One of Order) using its drop-down list.
Validate the model by right-clicking the design surface and choosing Validate. You will see that the error message related to this mapping is gone.
When encountering this problem in your application, you’ll have to decide which is more important to your model and your application logic: the foreign key scalar (e.g., Order.InvoiceID) or being able to define a 1:1 association between one entity (Invoice) and another (Order) when they are joined through a foreign key (InvoiceID).
The good news is that the new EF4.0 Lazy Loading will be still working with Independent Associations, just the Foreign key is not exposed. To get that you would have to go over to the navigation property (Invoice) and read its InvoiceID like the code below:
Order order = context.Orders.First();
int invoiceID = order.Invoice.InvoiceID;
Or you can use the code below to read it right on the Order entity withought having to Lazy Load or Eager Load the Invoice property:
int invoiceID = order.InvoiceReference.EntityKey.EntityKeyValues[0].Value;