I am trying to configure a new database design seeing as we have decided to make the move to Hibernate. Previously in my Java code I had the following three classes
Super class
public abstract class Card {
private String firstname;
private String lastname;
private String email;
...
}
A card sub class
public class ContactCard extends Card{
private String variable1;
private String variable2;
private String variable3;
public ContactCard(){
super(firstname, lastname, email);
...
}
}
And a few others to follow. This seemed to work fine. However I am starting to get a little confused. Here we have the subclasses in is a relationships, some card is a card. I am failing to map this in to database tables though.
For example, to incorporate the process of a card table in the database I could have a table for each sub class type, and inside this table i could have an id which references a card table (which is generated when a user registers). But, this now means that in my database I have transformed the is a relationship in to has a? The subclass now has a card rather than is a card.
I am confused and hope someone can clear things up for me.
Thanks
The confusion stems from the fact that the ORM has to translate objects to relations and vice versa. is a is a relation that means a subclass in OOP terms, a class that extends the base class. However, in RDBMS terms you have relations (or tables, the two mean the same thing) and records/entities that belong to said relations.
Now, if you have a table that is mapped to your Card class, then the subclass (I will call it MyCard for now) cannot be inherited per se in your RDBMS, since there is no inheritance. So, instead of inheriting the record, some convention is needed in order to represent that concept instead.
If MyCard has a foreign key mapped to Card, then this means that there is a many-to-one relation (as long as Card does not have a foreign key as well, in which case there would be a one-to-one relation).
If I would have to create an is a relation in the table, then the first (but not best) idea I would come up with would be to have a foreign key both in the Card and the MyCard relation towards each-other, because this would technically force that the relation between the two tables is not being duplicated. However, what if you have a MyCard base relation and some other possible relations, like MyCard1, MyCard2, ... MyCard999 and your Card does not necessarily have matches to each of them, then your Card relation would be filled with 999 fields that rarely have values.
Even if there is a single MyCard relation, having a foreign key from Card to it is unnecessary, because, if we are consistently using it as an is a relation, then it will be an is a relation rather than a has a, even if there is no technical difference between the two representations.
As a result, it is better to only create a foreign key from MyCard to Card only, because then
your schema is as simple as possible
your schema is as easy to be maintained as possible
So, how can we represent this in OOP?
We can have a field in MyCard that represents the Card.
In short: this looks like an is a relation, but since it is consistently used as a has a relation, it is essentially a has a relation.
Related
I am currently studying OOP and UML together, there is confusion regarding the use of association class or just the plain association. Let say a Company hires Person, as far as I know there are two ways to associate them, the first way is just a regular type of association(I think this is aggregation) like this.
Regular association
The second way is to use an associative class, kind of like the one the ER diagram, but the Company class no longer has the responsibility to hire any Person.
My questions are:
Which one is correct? (It seems like the second one makes more sense, but the first one isn't wrong either)
If the first way is not wrong, but then wouldn't Company knows too much about Person?
In what situations do I consider using association class over regular association?
Your association is not an aggregation, an aggregation has an empty diamond (<>), so it is a simple association.
None of the association ends has a name even when navigable, so why are you using an association rather than may be a dependency if you do not want property ? Of course if it is not an association you cannot have an association-class.
In the class Company we can see the attribute Employees, are you sure you do not want :
or
You named the association as the operation (hire), of course you can but an association just represent a semantic relationship, so hire does not represent the operation.
As rightly said by #Axel Scheithauer in his answer in case of an association-class the name of the class and the name of the association are common properties and must not be duplicated so cannot be different, from formal/2017-12-05 ยง 11.5.3.2 Association Classes page 200 :
Both Association and Class are Classifiers and hence have a set of common properties, like being able to have Features,
having a name, etc. These properties are multiply inherited from the same construct (Classifier), and are not duplicated.
Therefore, an AssociationClass has only one name, and has the set of Features that are defined for Classes and
Associations.
About to use an association or an association-class it is a choice.
If you want to know the date the company hired an employee and the employee salary (when hired / current) for sure an association-class is a good choice clearly showing what you want.
But you can also have Onboarding as a third class out of an association class and having association between the 3 classes :
and you can also have date and salary as attributes of Person supposing a person is necessary an employee :
else you can have the class Employee inheriting Person and having these additional attributes :
You have Java and C# as tag, none of these language support association-class, so even you use an association-class in UML when implementing it in Java / C# you will probably use one of the two other solutions.
Because there is no bidirectional navigability a company knows his employees but an employee does not know the company or companies where he/her works, do you really want that ?
I agree with everything that bruno said in his answer. However, I would add a third possibility: a simple Class.
If the relationship between two classes has properties, you have two options: An association class or a simple class associated with the two classes. The only advantage of taking an association class is, that you then can specify, that each pair of instances of the two associated classes can only be linked once. That means, each person can only work once for the same company. This is not quite realistic. In order to allow multiple links, you would need to specify {non unique} for the association ends of the association class ({unique} is the default). So, only in the {unique} case an association class adds semantics. If that's not needed I would avoid it.
One additional note: The association class is one element, but it is shown twice in a diagram, once as a rectangle and a second time as a line. Since they denote the same element, the name must be the same.
I decided to use single table inheritance which results in having multiple classes and I can't access the child's fields through a parent object in the view part of the application. So far I didn't find a nice solution how to deal with it in Thymeleaf. What does it mean?
Before I split my classes to use single table inheritance I could easily pass 1 object class that contained all the information needed to create or display the object but it had too many fields that would be null. With multiple classes thymeleaf doesn't really allow you to cast objects to a different type(and from what I understand it wouldn't be a good practice to do that in a view part of the application). So what is really the best way to deal with this problem?
I can come up with ideas like:
Create a DTO that contains the fields from all the classes and transform the objects to this class, it would be great in a create-view (POSTing DTO and then creating an object from it and adding to the database). But if I used this method for displaying information then it would mean casting each of the objects to a DTO class which kind of misses the point of single table inheritance in my opinion. I feel like this is too similar to going back to no inheritance at all.
Passing multiple objects or a parent object + a different object that would hold the rest of the information that the parent class doesn't hold. This also seems kind of weird.
Adding one method to a parent class per sub-class additional field and overwrite them in the sub-classes to return actual values while parent would return null. Not sure if this would fix the problem of creating the objects from a view though.
Let's assume this example with three simple classes where Person is a parent class and Client and Employee are children of it. I will skip getters, setters and constructors for simplicity.
Person main class that holds shared fields
#Entity
#Inheritance
#DiscriminatorColumn(name = "person_type", discriminatorType = DiscriminatorType.STRING)
public abstract class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
int personId;
int age;
String name;
}
Client class that extends person with additional field favouriteProduct
#Entity
#DiscriminatorValue(value= "CLIENT")
public class Client extends Person {
String favouriteProduct;
}
Employee class that extends person with additional fields salary and position.
#Entity
#DiscriminatorValue(value= "EMPLOYEE")
public class Employee extends Person {
String position;
int salary;
}
Given this simple structure I would like to create Employee and Client objects through a single form via a POST request and also display them together in a different view with their fields that are unique to each subclass. Problem is that I would need to pass an object that holds all the fields to the view to actually make it work which comes back to the problem and solutions that I came up with. Is there any correct way or best practice how to deal with this? I thought DTOs should rather scale down from full objects to objects with less fields.
Conclusion: if the answer isn't really that simple then what is really the use of single table inheritance in this case and why isn't it a good idea to just go back to 1 table implementation? I already know about polymorphic queries and it is a nice bonus but so far I can't really deal with the problem I explained above. Thanks in advance!
I don't know about Thymeleaf (sorry!), but I do know about object-oriented programming a bit. Leaving frameworks aside and talking from a pure OO perspective, parent classes know nothing about their children (inheritors). Only the opposite can be true, and that's if you use the appropriate access modifiers. Given that said, I believe you can not do what you want unless there is some ugly framework black magic going under the hood haha.
In my java I have a generic class (could be abstract or non-abstract either way, but does NOT map to a table in the database). It has one or more variables that are common to every class. Example:
public class GenericThing {
private Date createDate;
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date dt) {
createDate = dt;
}
}
This is useful because literally every table in the database has the column CREATE_DATE.
In this case the right inheritance strategy to use in Hibernate is "table per concrete class". But, this is "bad", they say, because each table requires that identical column and if you change that column name (CREATE_DATE) you have to change every table's column name. Well, obviously this is true, but what is the alternative? Obviously I do want every table in the database to store the Create Date, but I don't want every object in the entire database to be in one table, so that precludes (as far as I know) all the other mapping strategies, right?
Actually for your usecase, nothing wrong in using Table per concrete class strategy
The problem you are trying to solve is not creating any redundancy at schema level(when tables are created). Even if we do the entity modelling in reverse mode, this is fine. In-fact, create_date is specific to each row for every table.
Table per concrete class is not recommended only when you are dealing normal inheritance for example User -> Customer -> Supplier where each extended class is a kind of parent class and the specific extra attributes added in the sub class need not be duplicated in the all the tables (Join Table strategy is recommended for such cases)
What's wrong with table pet subclass polymorphism? The parent table contains the commom columns, child tables the specifics.
What's the use of #Embedded and #Embeddable In Hibernate ? Because every example i found on internet is inserting data inside of a single table and to do that using two different class. My point is if I am using a single table then I can map all the columns inside of a single class then why should i use different class. and if We use two different table then there is one-to-one and one-to-many hibernate relationship.
There are two types of objects in Hibernate
1. Value Object
2. Entities
Value Objects are the objects which can not stand alone. Take Address, for example. If you say address, people will ask whose address is this. So it can not stand alone.
Entity Objects are those who can stand alone like College and Student.
So in case of value objects preferred way is to Embed them into an entity object.
To answer why we are creating two different classes: first of all, it's a OOPS concept that you should have loose coupling and high cohesion among classes. That means you should create classes for specialized purpose only. For example, your Student class should only have the info related to Student.
Second point is that by creating different classes you promote re-usability.
When we define the value object for the entity class we use #Embeddable.
When we use value type object in entity class we use #Embedded
suppose we have employee table annotated with #entity and employee has Address so here i dont want to create two tables i.e employee and address, i just want create only one table i.e employee not Address table then we need to declare Address instance in Employee and add #embedable annotation on top of Address class, so finally we get table employee with its record and address records as well in single employee table
One entity can be embedded in another entity. The attributes of an entity can be common attributes of more than one entity. In this case there can be one embeddable entity. And this embeddable entity can be embedded in more than one entity.
Let's consider an example. We have one Animal entity, which has name and location attributes. Now two different entities Lion and Elephant can have Animal attributes just by embedding the Animal entity. We can override the attributes. In Animal entity there is location attribute and in Elephant there is place attribute. So with the help of #AttributeOverrides we can do like below:
#AttributeOverrides({ #AttributeOverride(name = "location", column = #Column(name = "place")) })
What is the difference between #Embedded annotation technique and #OneToOne annotation technique because in Embedded the java class contain "Has a" relationship in class and with the help of #Embedded annotation we persist the has a object in database. and in OneToOne relationship we also persist the has a object in database.
#OneToOne is for mapping two DB tables that are related with a one to one relationship. For example a Customer might always have one record in a Name table.
Alternatively if those name fields are on the Customer table (not in a separate table) then you might want an #embedded. On the face of it you could just add the name fields as standard attributes to the Customer entity but it can be useful if those same columns appear on multiple tables (for example you might have the name columns on a Supplier table).
Its the difference between composition and aggregation. #Embedded objects are always managed within the lifecycle of their parents. If the parent is updated or deleted, they are updated or deleted as well. #OneToOne objects may mimic composition via the cascadeType option of their #Join annotation, but by default they are aggregated, aka their lifecycle is separate from that of their parent objects.
#Embedded is used with Value Objects (Objects which have a meaning only when attached to an Object) whereas one to one mapping is between two objects having their own existence and meaning.
For e.g.
Value Object and #Embedded: If we have a User class and this class has an address Object in it, it can be considered as a value object as the address alone does not have any significance until unless associated with a user. Here address object can be annotated with #Embedded.
One to One mapping and #OneToOne: If we have a User class and this class has a 'Father' Object or a 'Mother' object, we would want to annotate the 'Father' or 'Mother' instance as #OneToOne as 'Father' or 'Mother' have their own meaning and existence and are not Value objects to User class.
A closely related difference is between #OneToMany and #ElementCollection. Both are used to save instance variables of Collection type in Java class. The difference being, #ElementCollection is to be used when the elements of Collection being saved are Value Objects whereas #OneToMany is used when the elments and object have well defined meaning and existence.
Use #OneToOne, only if fields can be reused. Otherwise, go for #Embeddable.
A quote from Beginning Hibernte, 3rd Edition:
There is nothing intrinsically wrong with mapping a one-to-one association between two entities where one is not
a component of (i.e., embedded into) the other. The relationship is often somewhat suspect, however. You should
give some thought to using the embedded technique described previously before using the #OneToOne annotation.
#Embeddable:
If the fields in an entity (X) are contained within the same table as another entity (Y), then entity X is called "component" in hibernate terms or "embedded" in JPA terms. In any case, JPA or hibernate do not allow to use 2nd table to store such embedded entities.
Generally, we think of normalizing a table when data is being reused by more than one table. Example: A Customer (id, name, street, city, pin, landmark) can be normalized into Customer(id, name) and CustomerAddress(cust_id, street, city, pin, landmark). In this case, we can reuse CustomerAddress by linking the same using cust_id with other tables. But if this reuse is not required in your application, then we can just keep all columns in one table.
So, a thumb rule is,
If reuse -> #OneToOne,
If no reuse -> #Embeddable
#Embedded is typically to represent a composite primary key as an embeddable class:
#Entity
public class Project {
#EmbeddedId ProjectId id;
:
}
#Embeddable
Class ProjectId {
int departmentId;
long projectId;
}
The primary key fields are defined in an embeddable class. The entity contains a single primary key field that is annotated with #EmbeddedId and contains an instance of that embeddable class. When using this form a separate ID class is not defined because the embeddable class itself can represent complete primary key values.
#OneToOne is for mapping two DB tables that are related with a one to one relationship. #Id will be the primary key.