There are 3 entities (which matches tables):
public class Enterprise{
private long id;
private String name;
private List<Department> departments;
//getters()/setters()
}
public class Department{
private long id;
private String name;
private List<Employee> employees;
//getters()/setters()
}
public class Employee{
private long id;
private String name;
private List<Department> departments;
//getters()/setters()
}
ENTERPRISE---|OneToMany|---DEPARTMENT---|ManyToMany|---EMPLOYEE
Can someone write method on JDBC :
List<Enterprise> findAll();
The connection, statements, queries, etc. can be ignored. The main difficulty is to set all references on the correct objects (for example, to avoid:
enterprise.getDepartments().get(1).getEmployees().get(1).getDepartments() == NULL) .
EXAMPLE (The beginning of method):
List<Enterprise> findAll(){
ResultSet rs = executeQuery(SELECT_ALL_ENTERPRISES);
List<Enterprise> ents = createEnterprises(rs);
.........
Mapping objects to relations is not as easy as it would seem. They have been working on it for decades now, with decent results only in some scenarios. The good news is that the scenarios that work can accommodate most programs.
I suggest that you take a different approach, but first I'll give you an example that will help you understand why I suggest the different approach.
Imagine a person who wants to look up all Departments, which will require a look up of all Employees (as they are part of a Department object). Which will require that for each employee, a list of departments would need to be looked up, which would require that those departments would need a list of employees, which would ....
Perhaps now you get the idea.
So many systems that are structured like yours don't actually return full Employees when looking up departments. They return "Employee identifiers". This allows one to look up all the Departments, but it guarantees that no Employees are going to be returned, preventing an infinite loop. Then, if a person is interested enough, they can use the employee identifiers to look up individual employees, which would of course contain department identifiers.
In short, I recommend that you don't really rebuild the association at this level. I suggest that you build disconnected graphs of the object mesh, such that one can easily navigate the disconnected graph at a later time. Then, if you really must connect them, you will at least have all the data loaded without recursion before you start knitting together references.
Many ORM libraries enable you to define one to many relationships as you described. Sormula can do this. See one to many example.
What I like about Sormula is that if you name the foreign key field on the "many side" the same as the field "one side", then Sormula will deduce the relationship and no annotations are necessary.
Related
I am making a small restful service for user management. By assignment, the User is defined by the following values:
◦ First name
◦ Last name
◦ Date of birth
◦ Login
◦ Password
◦ Input field “About me”
◦ Address of residence (country, city, street, house, flat)
When designing, I paid attention to the address and thought that it would be wrong to write everything together in one address field and make a similar attribute in the database table, because then different filtering by addresses would become very inconvenient. Then I delimited the address field into 5 fields (those in brackets). However, having done so, I realized that my class, given the id field, has 13 fields, what, in my understanding, makes the class too overloaded and "wrong". Then I decided to make a separate class for the address and use it as a field for the user, namely:
#Entity
public class UserAddress {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
private String country;
private String city;
private String street;
private int house;
private int flat;
}
And having done so, I'm not entirely sure how to proceed, as a result of which I have the following questions:
Should I move 5 address fields into a separate class in UserAddres?
If so, is it worth to make this class Entity and creating table in the database for it?
Should I consider it like a complete class (create getters / setters, equals and hashcode, service layer, controller and repository layers)?
Will filtering users by address become even more complicated than it was originally?
What is the best way to deal with such a situation?
Moving them into an extra table allows you to store more than 1 Address per user without redundancy of user data (like name).
Yes, because JPA / Hibernate will take care of PK/FK-Relationship using #OneToMany and #ManyToOne annotations.
Equals/Hashcode yes. Getters and Setters probably yes, depends on the way you handle this data. If you've got user input, e.g. via a GUI, you will need getters and setters. Somewhere you probably have to "fuse" address and user data to your Service's User data (the one going out).
Edit: If an Address object is invalid without belonging to a User, then only being able to manipulate the Address-Object via its User-object can help your data consistency.
No. JPA offers convenient ways to join tables.
The best-practice regarding your Restful Service would be to have a mapper between your Entities (User + Address between DB and App) and your DTOs (User + Address, between App and 3rd Party).
I have an entity that has a relation to a very large table ( > 100k Rows ). Now I am asking myself if I should express that relation really in my channel entity because would never call getProducts directly to load all products into memory. I would rather go through a product repositiory and query for a very specific subset for that channel.
I have only put it there so it's more readable from a client perspective.
#Entity
#Table(name = "Channel")
public class Channel {
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "product_id")
private List<Product> products;
public void setProducts(List<Product> products) {
this.products= products;
}
public List<Product> getProducts() {
return this.products;
}
}
Don't put that in a entity definition at all. You see what is often missed is that name #OneToMany is very misleading. As there is no possibility to limit the number of items you are loading. It can practically be used only when Many means Few :). The Hibernate Guru explains it better then me
Of course the join is executed lazily meaning that as long as it is not used it will do no harm. But why tempt faith. Writing query in a repo gives you ability for pagination and you can narrow the results to the one you will truly need.
The other side of the equation is more useful. So if you have on the child entity annotation #ManyToOne leave it there. It is good if you update parent from context of a child.
In short : no.
I think what you are asking may be opinion-based, but here is what I tend to do : remove all "non-navigable" relationships.
If you are using some generator to get JPA entities from a database model, the generator will create only bi-directional relationships. You need to remove all the relationships you will not used through the ORM mechanisms (for readability, maintainability and performance (in case someone would have the idea to remove the "lazy" indication or to call a getter on the collection in a transaction)).
For example, a User will be linked to a Language (many-to-one), but you don't want the (one-to-many) relationship between Language and User, even if at some point you will need to know in a report screen how many user speak which language.
I'm working in this movie db project for college where I need to create a website based on java to do advanced searches in a huge postgresql database. I'm not using hibernate or similar tools. Here's part of the ER diagram for the database:
As you can see, the associative entity actormovie links the entities actor and movie while also listing the character portrayed. I have created two simple beans, Actor and Movie, with attributes, getters and setters.
This is my first java web project with focus on MVC, so I'm more than a little lost. My question is: Should I create a bean mapping the associative table? If not, what do I do with the as_character attribute?
The answer is yes.
This is because the relation Actor->Movie has a property as_character, you can also find a way to not do a class, but in the long time it will cause problems (maybe some stupid bug created because you forgot it, or someone else didn't know it, something you don't want to deal with).
If this is your first approach I think what can make you confused is how to represents the relationship.
The first approach that come in mind, most of the time, is to have an ActorMovie class like:
public class ActorMovie {
Integer actor_id;
Integer movieid;
String as_character;
//getters, setters, equals, hashCode, toString
}
But you can also think at it as a value of Actor (or Movie) and have it like:
public class ActorMovie {
Integer movieid;
String as_character;
//getters, setters, equals, hashCode, toString
}
and a Actor class:
public class Actor {
Integer actor_id;
String name;
String sex;
Set<ActorMovie> movies;
//getters, setters, equals, hashCode, toString
}
Both of them solve the problems, they just change how you will interact with these data through the code, to learn when is better to use one or the other you have to try both and see what change, so choose what you feel more "natural" and see the results.
No, you don't need. The class Actor will have a list of Movie, and the Movie class, a list of Actor. Just map like this.
To the character attribute, you could create a map in the Actor class, where the key, is the movie, and the value, the character (Or a list of character, because an actor can have many characters in the same movie):
Map<Movie, List<String>> characters = new HashMap<>()
It depends how your project will develop. You should create bean mapping for the associative table, if you are not using Object Relational Mapping(as you stated in the question). If you will introduce Object Relational Mapping later on, then Actor can own as_character property, then you should not create bean mapping for the associative table .
I have a table "class" which is linked to tables "student" and "teachers".
A "class" is linked to multiple students and teachers via foriegn key relationship.
When I use hibernate associations and fetch large number of entities(tried for 5000) i am seeing that it is taking 4 times more memory than if i just use foreign key place holders.
Is there something wrong in hibernate association?
Can i use any memory profiler to figure out what's using too much memory?
This is how the schema is:
class(id,className)
student(id,studentName,class_id)
teacher(id,teacherName,class_id)
class_id is foreign key..
Case #1 - Hibernate Associations
1)in Class Entity , mapped students and teachers as :
#Entity
#Table(name="class")
public class Class {
private Integer id;
private String className;
private Set<Student> students = new HashSet<Student>();
private Set<Teacher> teachers = new HashSet<Teacher>();
#OneToMany(fetch = FetchType.EAGER, mappedBy = "classRef")
#Cascade({ CascadeType.ALL })
#Fetch(FetchMode.SELECT)
#BatchSize(size=500)
public Set<Student> getStudents() {
return students;
}
2)in students and teachers , mapped class as:
#Entity
#Table(name="student")
public class Student {
private Integer id;
private String studentName;
private Class classRef;
#ManyToOne
#JoinColumn(name = "class_id")
public Class getClassRef() {
return classRef;
}
Query used :
sessionFactory.openSession().createQuery("from Class where id<5000");
This however was taking a Huge amount of memory.
Case #2- Remove associations and fetch seperately
1)No Mapping in class entity
#Entity
#Table(name="class")
public class Class {
private Integer id;
private String className;
2)Only a placeholder for Foreign key in student, teachers
#Entity
#Table(name="student")
public class Student {
private Integer id;
private String studentName;
private Integer class_id;
Queries used :
sessionFactory.openSession().createQuery("from Class where id<5000");
sessionFactory.openSession().createQuery("from Student where class_id = :classId");
sessionFactory.openSession().createQuery("from Teacher where class_id = :classId");
Note - Shown only imp. part of the code. I am measuring memory usage of the fetched entities via JAMM library.
I also tried marking the query as readOnly in case #1 as below, which does not improve memory usage very much ; just a very little. So that's not the solve.
Query query = sessionFactory.openSession().
createQuery("from Class where id<5000");
query.setReadOnly(true);
List<Class> classList = query.list();
sessionFactory.getCurrentSession().close();
Below are the heapdump snapshots sorted by sizes. Looks like the Entity maintained by hibernate is creating the problem..
Snapshot of Heapdump for hibernate associations program
Snapshot of heapdump for fetching using separate entities
You are doing a EAGER fetch with the below annotation. This will in turn fetch all the students without even you accessing the getStudents(). Make it lazy and it will fetch only when needed.
From
#OneToMany(fetch = FetchType.EAGER, mappedBy = "classRef")
To
#OneToMany(fetch = FetchType.LAZY, mappedBy = "classRef")
When Hibernate loads a Class entity containing OneToMany relationships, it replaces the collections with its own custom version of them. In the case of a Set, it uses a PersistentSet. As can be seen on grepcode, this PersistentSet object contains quite a bit of stuff, much of it inherited from AbstractPersistentCollection, to help Hibernate manage and track things, particularly dirty checking.
Among other things, the PersistentSet contains a reference to the session, a boolean to track whether it's initialized, a list of queued operations, a reference to the Class object that owns it, a string describing its role (not sure what exactly that's for, just going by the variable name here), the string uuid of the session factory, and more. The biggest memory hog among the lot is probably the snapshot of the unmodified state of the set, which I would expect to approximately double memory consumption by itself.
There's nothing wrong here, Hibernate is just doing more than you realized, and in more complex ways. It shouldn't be a problem unless you are severely short on memory.
Note, incidentally, that when you save a new Class object that Hibernate previously was unaware of, Hibernate will replace the simple HashSet objects you created with new PersistentSet objects, storing the original HashSet wrapped inside the PersistentSet in its set field. All Set operations will be forwarded to the wrapped HashSet, while also triggering PersistentSet dirty tracking and queuing logic, etc. With that in mind, you should not keep and use any external references to the Set from before saving, and should instead fetch a new reference to Hibernate's PersistentSet instance and use that if you need to make any changes (to the set, not to the students or teachers within it) after the initial save.
Regarding the huge memory consumption you are noticing, one potential reason is Hibernate Session has to maintain the state of each entity it has loaded the form of EntityEntry object i.e., one extra object, EntityEntry, for each loaded entity. This is needed for hibernate automatic dirty checking mechanism during the flush stage to compare the current state of entity with its original state (one that is stored as EntityEntry).
Note that this EntityEntry is different from the object that we get to access in our application code when we call session.load/get/createQuery/createCriteria. This is internal to hibernate and stored in the first level cache.
Quoting form the javadocs for EntityEntry :
We need an entry to tell us all about the current state of an object
with respect to its persistent state Implementation Warning: Hibernate
needs to instantiate a high amount of instances of this class,
therefore we need to take care of its impact on memory consumption.
One option, assuming the intent is only to read and iterate through the data and not perform any changes to those entities, you can consider using StatelessSession instead of Session.
The advantage as quoted from Javadocs for Stateless Session:
A stateless session does not implement a first-level cache nor
interact with any second-level cache, nor does it implement
transactional write-behind or automatic dirty checking
With no automatic dirty checking there is no need for Hibernate to create EntityEntry for each entity of loaded entity as it did in the earlier case with Session. This should reduce pressure on memory utilization.
Said that, it does have its own set of limitations as mentioned in the StatelessSession javadoc documentation.
One limitation that is worth highlighting is, it doesn't lazy loading the collections. If we are using StatelessSession and want to load the associated collections we should either join fetch them using HQL or EAGER fetch using Criteria.
Another one is related to second level cache where it doesn't interact with any second-level cache, if any.
So given that it doesn't have any overhead of first-level cache, you may want to try with Stateless Session and see if that fits your requirement and helps in reducing the memory consumption as well.
Yes, you can use a memory profiler, like visualvm or yourkit, to see what takes so much memory. One way is to get a heap dump and then load it in one of these tools.
However, you also need to make sure that you compare apples to apples. Your queries in case#2 sessionFactory.openSession().createQuery("from Student where class_id = :classId");
sessionFactory.openSession().createQuery("from Teacher where class_id = :classId");
select students and teachers only for one class, while in case #1 you select way more. You need to use <= :classId instead.
In addition, it is a little strange that you need one student and one teacher record per one class. A teacher can teach more than one class and a student can be in more than one class. I do not know what exact problem you're solving but if indeed a student can participate in many classes and a teacher can teach more than one class, you will probably need to design your tables differently.
Try #Fetch(FetchMode.JOIN), This generates only one query instead of multiple select queries. Also review the generated queries. I prefer using Criteria over HQL(just a thought).
For profiling, use freewares like visualvm or jconsole. yourkit is good for advanced profiling, but it is not for free. I guess there is a trail version of it.
You can take the heapdump of your application and analyze it with any memory analyzer tools to check for any memory leaks.
BTW, I am not exactly sure about the memory usage for current scenario.
Its likely the reason is the bi-directional link from Student to Class and Class to Students. When you fetch Class A (id 4500), The Class object must be hydrated, in turn this must go and pull all the Student objects (and teachers presumably) associated with this class. When this happens each Student Object must be hydrated. Which causes the fetch of every class the Student is a part of. So although you only wanted class A, you end up with:
Fetch Class A (id 4900)
Returns Class A with reference to 3 students, Student A, B, C.
Student A has ref to Class A, B (id 5500)
Class B needs hydrating
Class B has reference to Students C,D
Student C needs hydrating
Student C only has reference to Class A and B
Student C hydration complete.
Student D needs hydrating
Student D only has reference to Class B
Student B hydration complete
Class B hydration complete
Student B needs hydrating (from original class load class A)
etc... With eager fetching, this continues until all links are hydrated. The point being that its possible you end up with Classes in memory that you didn't actually want. Or whose id is not less than 5000.
This could get worse fast.
Also, you should make sure you are overriding the hashcode and equals methods. Otherwise you may be getting redundant objects, both in memory and in your set.
One way to improve is either change to LAZY loading as other have mentioned or break the bidirectional links. If you know you will only ever access students per class, then don't have the link from student back to class. For student/class example it makes sense to have the bidirectional link, but maybe it can be avoided.
as you say you "I want "all" the collections". so lazy-loading won't help.
Do you need every field of every entity? In which case use a projection to get just the bits you want. See when to use Hibernate Projections.
Alternatively consider having minimalist Teacher-Lite and Student-Lite entity that the full-fat versions extend.
I am trying to decide which annotation to use. Can you offer your opinion?
What I have now:
#Entity
public class Balance {
#Embedded
private Amount amountAtm;
#Embedded
private Amount amountBranch;
#Embedded
private Amount amountVault;
}
#Embeddable
public Amount {
private BigDecimal debit;
private BigDecimal credit;
}
What I want to change it to:
#Entity
public class Balance {
#ElementCollection
private Map<AmountType, Amount> amounts;
}
public enum AmountType {
ATM, BRANCH, VAULT;
}
The Amount would stay the same.
The reason for this change, is because the amounts inside the balance are conceptually a collection. I either display/change all of them at the same time, or none at all. So, I treat them as a group.
Questions:
Right now the amounts are stored in the same table as the balances (I override column names, this is not shown in the code). However, if I make this change there is NO WAY I can store all this data in one table. I would have to store amounts in a separate table. Is this correct?
Considering that now I will have to make JOINs in SQL, etc. How will this affect the performance? Let's say I am using Oracle 11g and I have 100,000 balance records (and therefore 300,000 amounts). Will I notice the slowdown in the application after the change?
Yes, it's correct.
Impossible to say without testing. I don't see how it could be faster than storing the six fields in the table directly.
What I don't understand is why you're not satisfied with your three fields. If you want to be able to have a Map<AmountType, Amount> getAmounts() method (and the corresponding setter) in your entity, nothing prevents you from adding it and implementing it yourself:
public Map<AmountType, Amount> getAmounts() {
Map<AmountType, Amount> result = new HashMap<AmountType, Amount>(3);
result.put(AmountType.ATM, amountAtm);
result.put(AmountType.BRANCH, amountBranch);
result.put(AmountType.VAULT, amountVault);
return result;
}