JPA Why only this #ManyToOne returns null? - spring

UPDATE
I find something interesting
When I run JPQL like this
SELECT s FROM STUDENTS s WHERE s.community=:community
then this issue happens, but this query runs fine and returns all necessary fields
SELECT s FROM STUDENTS s WHERE s.id=:id
meaning if there is an inner join with its child field, then somehow the value of the other field get missing. I got both native query and both returns all necessary field values. Must be openjpa dismiss the school fields some how when native query returns
Yes, Community and School both may map to another entity, but how come that could cause this strange behavior? I am kind of mad with OpenJPA
I have spent hours to fix this strange issue
there is a class contains several #ManyToOne relation
public class Student{
// Relationships
#NotNull
#ManyToOne(fetch=FetchType.EAGER)
private Teacher teacher;
#ManyToOne(fetch=FetchType.EAGER)
#Column(name = "SCHOOL_ID")
private School school;
#ManyToOne(fetch=FetchType.EAGER)
private Club club;
#ManyToOne(fetch=FetchType.EAGER)
private Bus bus;
....
}
Each of the many side has a definition like this(Only give the School entity as it has the issue):
public class School implements Institution{
// Relationships
#OneToMany(mappedBy="school")
private List<Student> students= new ArrayList<Student>();
....
}
The problem here is when I try to get All students for a certain age:
SELECT s FROM STUDENTS s WHERE s.age=:age
I can clearly see the all other #ManyToOne fields' value ONLY EXCEPT school, and in Oracle database the school_id field clearly stored with correct data which map to the correct entry in School table
So what could be the possible reason for this situation?
I am using Spring MVC3 + Openjpa + Roo

Your school mapping should use a #JoinColumn annotation (not a #Column annotation):
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name = "SCHOOL_ID")
private School school;

Related

Spring Boot: How to create a new entity that references exisiting ones (by Id) [duplicate]

I have been playing around with JPA and came across this scenario and wanted to know how to solve this.
I have 2 tables namely Company and Employee.
So here an employee can work for only 1 company, therefore #OneToOne uni-directional mapping is done in Employee class. And the company details in the Company table would already exist.
So when I try to insert a record into Employee table, I even create a reference to the company, add it to the Employee class and save it using my EmployeeRepository's save method. Since the company_id would already exist in Company table, it should just refer it instead of creating a new company. But this is not happening.
I get an exception saying company object is still in the transient state. I can solve this by adding CascadeType.All but I don't need to insert the company rather I have to just link the company to the employee.
Here are the code snippets.
Employee Class
#Entity
#Table(name = "employee")
#Setter
#Getter
public class Employee
{
#Id
#GeneratedValue
private Long id;
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "employee_name")
private String employee_name;
#OneToOne
#JoinColumn(name = "company_id")
private Company company;
}
Company class
#Entity
#Table(name = "company")
#Setter
#Getter
public class Company
{
#Id
#GeneratedValue
#Column(name = "company_id")
private Long id;
#Column(name = "company_name")
private String companyName;
}
Company Table
company_id company_name
1 Dell
2 Apple
3 Microsoft
Here is how I am creating the Employee object
Employee emp = new Employee();
emp.setEmployeeId(10);
emp.setEmployeeName("Michael");
Company company = new Company();
company.setId(1);
emp.setCompany(company);
employeeRepository.save(emp);
Please, someone, let me know how to link the company class to an employee class rather than saving one more company.
The best solution for me is to lazy load your company with a proxy. To do it with Spring Data JPA, you need to make your company repository extends JpaRepository. That give you access to the method getReferenceById :
Employee emp = new Employee();
emp.setEmployeeId(10);
emp.setEmployeeName("Michael");
emp.setCompany(companyRepository.getReferenceById(1))
employeeRepository.save(emp);
If there is no company for the given id, an EntityNotFoundException is throw.
With a proxy, you avoid the request to the database in most case because Hibernate use its cache for check the existence of the company. But if my memory serves me correctly, Hibernate gonna make a request to the database at each call to a getter of the proxy, except for getId(). So, in your case it's a good solution, but don't use it all the time.
Assuming the Company may have more than one Employee the relation is a ManyToOne, not a OneToOne.
If you want to reference an existing entity, load it instead of creating a new one:
Employee emp = new Employee();
// ...
emp.setCompany(companyRepository.findById(1));
employeeRepository.save(emp);

Many to one mapping Hibernate

I am doing many to one mapping in hibernate. I am using the existing tables which I created earlier for one to many mapping (customer and order) but when I am trying to map and update those table I couldn't able to I don't know how should I processed? and I would like to insert the data meaning I would like to create some more orders using command line runner for that customer.
Could you please help me with this
Appreciate your help.
Mapping one-to-many and many-to-one association
Both associations are the same association seen from the perspective of the owing and subordinate entities and respectively.
Student one-to-many Address
Address many-to-one Student
#OneToMany annotation can be applied to a field or property value of "one" end entity class for a collection or an array representing the mapped "many" end of the association.
#ManyToONe relationship between two entities is by managing the FK(Foreign key) of the "one" end entity, as a column in the "many" entity table.
> **Bidirectional one-to-many using ```#JoinColumn```**
#Entity
public class Student{
#OneToMany(cascade = CasecadeType.ALL)
#JoinTable(name="Student_FK")
public set<Address> getAddress(){
return address;
}
}
One-to-Many side as the owing side, You have to remove the mappedBy element and set the #ManyToOne #JoinColumn as insertable and updatable to false. This Solution is not optimized and will produce some additional UPDATE Statement.
#Entity
public class Address{
#ManyToOne(cascade = CasecadeType.ALL)
#JoinColumn(name="STUDENT_FK", insertable = false, updatable = false)
public Student student;
}
For more details look at this link Link

Spring data JPA self join on an entity. How do I specify the depth of recursion?

Using Spring Boot JPA, I am doing a self join on a table of "Person" with attributes id, name and parent_id. parent_id is a foreign key referencing Person.id. So, a Person will have zero or one parent. A sample of my domain class is below.
#Entity(name="person")
public class Person {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
#Column(name="id")
private Integer id;
#Column(name="name")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="parent_person_id")
private Person parent;
// constructors, getters, setters, etc
}
This actually works just fine; when I query with CrudRepository.findById() for example, I get a Person object with an embedded Person object (parent), which may have another embedded Person object (grandparent), etc until I get to a Person without a parent.
My question is, how may I retrieve only a Person and their immediate parent without recursing any further (no grandparents, great-grandparents, etc)?
I imagine I could simply avoid the join, and make parent_id a plain #Column, then in the service layer do an additional query to find the parent, but I'm wondering if there is some Jpa magic that could make it easier than that.
Actually, this was not as hard as it seemed. Converting my Person entity to a dto provided me with the opportunity to simply STOP at the parent, and not recurse through the whole tree!

Save object in database if it does not already exist (Hibernate & Spring)

I'm working on a Hibernate/Spring application to manage some movies.
The class movie has a many to many relationship with the class genre.
Both of these classes have generated id's using the GeneratedValue annotation.
The genre is saved through the movie object by using #Cascade(CascadeType.SAVE_UPDATE)
I have placed a unique constraint on the genre's type attribute (which is it's name; "Fantasy" for example).
What I would like to do now is have Hibernate check if there is already a genre with type "Fantasy" and if there is, use that genre's id instead of trying to insert a new record.
(The latter would obviously throw an error)
Finally what I need is something like select-before-update but more like select-before-save.
Is there such a function in Hibernate?
Some code:
Movie class
#Entity
public class Movie {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
#Lob
private String description;
#Temporal(TemporalType.TIME)
private Date releaseDate;
#ManyToMany
#Cascade(CascadeType.SAVE_UPDATE)
private Set<Genre> genres = new HashSet<Genre>();
.... //other methods
Genre class
#Entity
public class Genre {
#Column(unique=true)
private String type;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int id
....//other methods
You may be over-thinking this. Any select-before-update/select-before-save option is going to result in 2 DB round trips, the first for the select, and the second for the insert if necessary.
If you know you won't have a lot of genres from the outset, you do have a couple of options for doing this in 1 RT most of the time:
The Hibernate second-level cache can hold many if not all of your Genres, resulting in a simple hashtable lookup (assuming a single node) when you check for existence.
You can assume all of your genres are already existing, use session.load(), and handle the new insert as a result of the row not found exception that gets thrown when you reference a genre that doesn't already exist.
Realistically, though, unless you're talking about a LOT of transactions, a simple pre-query before save/update is not going to kill your performance.
I haven't heard of such a function in Hibernate select-before-update/select-before-save
In situations like these you should treat Hibernate as if it was JDBC.
First if you want to know if you even have such a Genre you should query for it.
if you do. then the SAVE_UPDATE will not create a new one when you add it to a movie.
if you don't, Hibernate will create a new Genre row in the database and add the connection to the many_to_many table for you.

Multiple Relationship classes with the same type

Using spring-data-neo4j, I want to create two classes using #RelationshipEntity(type="OWNS") to link a Person class to both a Pet and Car.
#RelationshipEntity(type="OWNS")
public class OwnsCar {
#Indexed
private String name;
#StartNode
private Person person;
#EndNode
private Car car;
}
#RelationshipEntity(type="OWNS")
public class OwnsPet {
#Indexed
private String name;
#EndNode
private Person person;
#StartNode
private Pet pet;
}
This saves to the Graph Database properly with no problems, as I can query the actual Node and Relationship and see they type, etc.
But when I attempt to use #RelatedTo(type="OWNS", elementClass=Pet.class) I either get a class cast exception, or when using lazy-initialization I get incorrect results.
#NodeEntity
public class Person {
#Indexed
private String name;
#RelatedTo(type="OWNS", direction=Direction.OUTGOING, elementClass=Pet.class)
private Set<Pet> pets;
#RelatedTo(type="OWNS", direction=Direction.OUTGOING, elementClass=Car.class)
private Set<Car> cars;
}
The result I get when I attempt to print our my person(my toString() has been omitted, but it simply calls the toString() for each field) is this:
Person [nodeId=1, name=Nick, pets=[Car [nodeId=3, name=Thunderbird]], cars=[Car [nodeId=3, name=Thunderbird]]]
Does anyone know if this can be done, should be done, is just a bug or a feature that is missing?
It seems like the problem is, that the annotation causes springDataNeo4j to priorize the relationship name. I tried the same on another sample I created. If both annotations contain
type="OWNS" it mixes both 'objects'. When I omit this information, and only use direction and type, it works for me.
Unfortunately this will lead to a problem if you are using another #RelatedTo annotation with more Pets or Cars related with another annotation. As it would not differ between "OWNS" and any other relation to a Pet-Type, the set returns all related pets (example: peter ->(HATES-Relationsip)->dogs).
If it's a bug or not, I can't tell... But for the database: There are only nodes and relations. Both are not typed, so neo4j does not know anything about your 'Pet'- or 'Car'-Class. Spring data neo4j handles this, either by indexing all nodes per type and setting a type-attribute, or using a specific graph-layout (with subreferences). Even if you would want to fetch all pets of a person with a traversal description, you would have so much more code to write, since the outgoing relations with name 'OWNS' contains two types of objects.
I would recommend using two different names. It's easier to write your custom traversals/queries later on, and its probably even faster as well, because no class-type comparison will be needed. Is there any reason, why you would need these specific names?
PS: It is possible, that not everything is 100% accurate. I don't know springdataneo4j in detail, but that's what I figured out so far.

Resources