I have the entity following entities:
Employee extends Person
Company has List<Employee> (lazy load).
When I try to initialize the employee list with Hibernate.initialize(company.getEmployees()); I receive an error since hibernate doesn't understand that Employee is a Person.
Person.java
#Entity
#Table(name = "person")
#Inheritance(strategy = InheritanceType.JOINED)
public abstract class Person implements java.io.Serializable {
#Column(name = "person_id")
protected Long personId;
#Column(name = "name")
protected String name;
#Column(name = "age")
protected String age;
}
Employee.java
#Entity
#Table(name = "employee")
#PrimaryKeyJoinColumn(name = "person_id")
public class Employee extends Person {
#Column(name = "employee_number")
private String number;
#ManyToOne
#JoinColumn(name = "company_id")
private Company company;
}
Company.java
#Entity
#Table(name = "company")
public class Company implements java.io.Serializable {
#Column(name = "company_id")
protected String id;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "company", cascade = CascadeType.ALL)
#OrderBy(clause = "name desc")
protected List<Employee> employees = new ArrayList<Employee>();
}
Hibernate.initialize(company.getEmployees());
Exception:
org.postgresql.util.PSQLException: ERROR: column employee0_.name does not exist
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2102)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1835)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:257)
Is there any solution with lazy load for this case?
There is certainly one to one relationship between Employee and Person. It makes sense by splitting the objects in Java but not in terms of table. I think Employee table should have a name and other columns defined in person table to simplify the design.
Related
Hello I saw some similar questions from 2018 but without much information
I have the following classes
Employee
#Entity
#Getter
#Setter
#NoArgsConstructor
#NamedEntityGraph(name = "employee.complete", attributeNodes = {
#NamedAttributeNode(
value = "addresses",
subgraph = "address_city"
)},
subgraphs = {
#NamedSubgraph(
name = "address_city",
attributeNodes = {
#NamedAttributeNode("city")
})
},
subclassSubgraphs = {
#NamedSubgraph(
name = "noUse",
type = Engineer.class,
attributeNodes = {
#NamedAttributeNode("laptop")
})
}
)
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "profession")
public class Employee {
#Id
String id;
String name;
String email;
#OneToMany
#JoinColumn(name = "employee_id", updatable = false)
List<Address> addresses;
}
Address
#Entity
#Getter
#Setter
#ToString
#NoArgsConstructor
public class Address {
#Id
private String addressId;
private String streetName;
private String streetNumber;
#OneToOne
#JoinColumn(name = "city_id")
private City city;
}
City
#Entity
#Setter
#Getter
public class City {
#Id
String id;
String name;
}
Engineer
#Entity
#Getter
#Setter
#DiscriminatorValue("engineer")
public class Engineer extends Employee {
private String seniority;
#OneToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "id")
Laptop laptop;
}
Laptop
#Entity
#Getter
#Setter
public class Laptop {
#Id
#Column(name = "employee_id")
String employeeId;
String brand;
}
With the NamedEntityGraph I want to achieve in a single query to retrieve all the information of the employee.
The attributeNodes and the subgraph for city are working correctly but the subclassSubgraphs is not working for this example..
my expectation was that I will retrieve the laptop information in one query with a join clause
but actually there are two select statements
select employee0_.id as id2_3_0_, addresses1_.address_id as address_2_0_1_, city2_.id as id1_1_2_, employee0_.email as email3_3_0_, employee0_.name as name4_3_0_, employee0_.seniority as seniorit5_3_0_, employee0_.profession as professi1_3_0_, addresses1_.city_id as city_id5_0_1_, addresses1_.street_name as street_n3_0_1_, addresses1_.street_number as street_n4_0_1_, addresses1_.address_type as address_1_0_1_, addresses1_.employee_id as employee6_0_0__, addresses1_.address_id as address_2_0_0__, city2_.name as name2_1_2_ from employee employee0_ left outer join address addresses1_ on employee0_.id=addresses1_.employee_id left outer join city city2_ on addresses1_.city_id=city2_.id where employee0_.id=? and (employee0_.id is not null)
select laptop0_.employee_id as employee1_4_0_, laptop0_.brand as brand2_4_0_ from laptop laptop0_ where laptop0_.employee_id=?
I cannot find any page that reports a bug about this, am I doing something wrong?
code repo -> https://github.com/dkasiaras/pocs/tree/main/jpa-graph-entity
Could you please advise how to write query in Spring Data JPA repository? Here is the situation:
I have 2 Entities: Customer and Product with relationship 'OneToMany' - means one Customer may have many products. In code it looks like Customer entity has Set products and Product has reference to Customer customer, very simple. If I retrieve Customer from DB JSON would look like this: {"id":10, "name":'John Smith',"personalCode":12345678,"products":[ {"id":15,"type":"productType1"}, {"id":20,"type":"productType2"}] }
The question is how can I write query to DB to find all customers whose products match passed products collection? For example I want to find all customers who owns products with type1 and type2. THANKS!
#Entity
#Table(name = "customer")
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int age;
private String personalCode;
#Enumerated(EnumType.STRING)
private Country country;
private String internetBankUserId;
#Enumerated(EnumType.STRING)
private CustomerType type;
#JsonManagedReference
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL)
#SortNatural
private SortedSet<Product> products = new TreeSet<>();
#Entity
#Table(name = "product")
public class Product implements Comparable<Product>{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Enumerated(EnumType.STRING)
private ProductType type;
#JsonBackReference
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "customer_id")
private Customer customer;
This solution worked for me:
#Query("SELECT c FROM Customer c join c.products p where p.type in :products
and SIZE(c.products) >= :count")
Set<Customer> findAllByProductType (#Param("products")Set<ProductType> products,
#Param("count") Integer count );
I have a class User which has a parameter of another class type ShoppingList.
As this...
#Entity
public class Employee implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(nullable = false, updatable = false)
private Long id;
private String Name;
#?????
private ShoppingList[] shoppingList;
}
How can i make this ManyToOne relationship while the variable being an array?
The idea is to have a User table and another ShoppingList table, so the user can have multiple lists at the same time.
This would be the correct way:
One Employee has many ShoppingLists.
One ShoppingList has only one Employee.
#Entity
public class Employee implements Serializable {
....
#OneToMany(mappedBy = "employee", fetch = FetchType.LAZY,
cascade = CascadeType.ALL)
private List<ShoppingList> shoppingList;
....
}
#Entity
public class ShoppingList implements Serializable {
....
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
....
}
You can fine-tune your entities as per your need.
For more info, I would refer to this tutorial, it has helped me a lot.
I have an entity:
#Entity
#Table(name = "person")
public class Person {
#EmbeddedId
private PersonId id;
#OnDelete(action = OnDeleteAction.CASCADE)
#MapsId("a_phoneNumberId")
#ManyToOne
private PhoneNumber phoneNumber;
#OnDelete(action = OnDeleteAction.CASCADE)
#MapsId("b_addressId")
#ManyToOne
private Address address;
...
with embedded id:
#Embeddable
public class PersonId implements Serializable {
private int a_phoneNumberId;
private int b_addressId;
...
Note: a_ and b_ prefixes are used to order columns in primary key.
Everything works as expected and hibernate generates a table with columns: phoneNumber_id and address_id.
Is it possible to rename those columns, as I want to have a snake_case name - phone_number_id?
So far I tried
#AttributeOverride annotation:
#Entity
#Table(name = "person")
public class Person {
#EmbeddedId
#AttributeOverrides({
#AttributeOverride(name = "a_phoneNumberId", column = #Column(name = "phone_number_id"))
})
private PersonId id;
#Column annotation for the id:
#Embeddable
public class PersonId implements Serializable {
#Column(name = "phone_number_id")
private int a_phoneNumberId;
but it changed nothing.
I need to create a table EMPLOYEE_REMARK from a table EMPLOYEE.
And need to do it with Annotation Hibernate.
EMPLOYEE
EMP_ID, EMP_FNAME, EMP_LNAME
EMPLOYEE_REMARK
EMP_REMARK_ID, EMP_ID, REMARK
it will be a OnetoOne relationship i.e, for each EMP_ID there will be one REMARK. REMARK could be null.
please help me with the solution...
Can it be done by creating one class from employee and populate the EMPLOYEE_REMARK from it???
Basically here is the way of doing what you want.
Employee
#Entity
#Table(name = "EMPLOYEE")
public class Employee implements Serializable {
#Id
#Column(name = "EMP_ID")
private Long id;
#Column(name = "EMP_FNAME")
private String firstName;
#Column(name = "EMP_LNAME")
private String lastName;
#OneToOne(mappedBy = "employee", cascade = CascadeType.ALL,
orphanRemoval = true)
private EmployeeRemark employeeRemark;
public void setRemark(String remark) {
this.employeeRemark = new EmployeeRemark();
this.employeeRemark.setRemark(remark);
this.employeeRemark.setEmployee(this);
}
public String getRemark() {
return employeeRemark == null ? null : employeeRemark.getRemark();
}
//getters and setters
}
Employee Remark
#Entity
#Table(name = "EMPLOYEE_REMARK")
public class EmployeeRemark implements Serializable {
#Id
#Column(name = "EMP_REMARK_ID")
private Long id;
#OneToOne
#JoinColumn(name = "EMP_ID")
private Employee employee;
#Column(name = "REMARK")
private String remark;
//getters and setters
}
When saving employee, just call save on employee. EmployeeRemark will cascade to all operations and will be removed along with employee or if it become an orphan in other way.