I have two classes, CarRentalCompany
#Entity
public class CarRentalCompany {
private static Logger logger = Logger.getLogger(CarRentalCompany.class.getName());
#Id
private String name;
#OneToMany(cascade = CascadeType.ALL)
private List<Car> cars;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<CarType> carTypes = new ArrayList<>(); //TODO: kan betere datastructuur zijn
/***************
* CONSTRUCTOR *
***************/
public CarRentalCompany()
{
// DEFAULT CONSTRUCTOR
}
public CarRentalCompany(String name, List<Car> cars) {
logger.log(Level.INFO, "<{0}> Car Rental Company {0} starting up...", name);
setName(name);
this.cars = cars;
for(Car car:cars)
carTypes.add(car.getType());
}
...
}
and CarType
#Entity
public class CarType {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
private String name;
private int nbOfSeats;
private boolean smokingAllowed;
private double rentalPricePerDay;
//trunk space in liters
private float trunkSpace;
/***************
* CONSTRUCTOR *
***************/
public CarType()
{
}
public CarType(String name, int nbOfSeats, float trunkSpace, double rentalPricePerDay, boolean smokingAllowed) {
this.name = name;
this.nbOfSeats = nbOfSeats;
this.trunkSpace = trunkSpace;
this.rentalPricePerDay = rentalPricePerDay;
this.smokingAllowed = smokingAllowed;
}
When running the application, it throws the following exception:
NucleusFatalUserException: Attempt to assign child with key
"CarType(6614661952700416)" to parent with key
"CarRentalCompany("Hertz")". Parent keys are immutable
What do I need to do to get the key of the CarType right?
You are not persisting your CarRentalCompany entity before adding CarType entity. See a
similar thread here. The persist operation must be used only for new entities. An entity is new when it has never been associated with a database row, meaning that there is no table record in the database to match the entity in question.
Related
I have two entity that have a relation,The relationship works fine, but how can I set value from one object to another in controller.
#Entity
#Table(name = "material_manu_calculator")
public class MaterialManuCalcu {
#Id
#GeneratedValue
#Column(name = "no")
private int no;
#ManyToOne
#JoinColumn(name = "order_id")
private OrderProductManu orderProductManu;
//.....getters and setters and constructors}
Below is the second Entity
#Entity
#Table(name = "orders_products_manu")
public class OrderProductManu {
#Id
#GeneratedValue
#Column(name = "order_id")
private int orderManuId;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "orderProductManu")
private List<MaterialManuCalcu> materialCalcu = new ArrayList<>();
//.....getters and setters and constructors}
below is the Repository
#Repository
#Transactional
public interface OrderProductManuRepository extends JpaRepository <OrderProductManu, Integer> {
#Query(value ="SELECT *FROM orders_products_manu WHERE orders_products_manu.order_id =?", nativeQuery = true)
public OrderProductManu getOrderProductById(int id);
}
I want to set the value of MaterilaManuCalcu in controller as below
#Controller
public class ProductsController {
#Autowired
private OrderProductManuRepository orderRepo;
OrderProductManu orderProduct = orderRepo.getOrderProductById(1);
MaterialManuCalcu manCalc = new MaterialManuCalcu();
manCalc.setOrderProductManu(orderProduct.getOrderManuId());
// I get the error says:
// The method setOrderProductManu(OrderProductManu) in
// the type MaterialManuCalcu is not applicable for the arguments (int)
Update: Constructors
public MaterialManuCalcu(int no, int amountOrdered, int amountAvailable, int amountWillRemain,
MaterialManu materialmanu, OrderProductManu orderProductManu) {
this.no = no;
this.amountOrdered = amountOrdered;
this.amountAvailable = amountAvailable;
this.amountWillRemain = amountWillRemain;
this.materialmanu = materialmanu;
this.orderProductManu = orderProductManu;
}
Another one
public OrderProductManu(int orderManuId, String customerName, int amountOrderedManu, String dateOrdered, Users users,
ProductsManu productsManu) {
this.orderManuId = orderManuId;
this.customerName = customerName;
this.amountOrderedManu = amountOrderedManu;
this.dateOrdered = dateOrdered;
this.users = users;
this.productsManu = productsManu;
}
Update:Showing how both entities are created
For : OrderProductManu
OrderProductManu orderProduct = new OrderProductManu();
orderProduct.setDateOrdered("2021-04-14");
orderProduct.setAmountOrderedManu(platenum);
orderProduct.setCustomerName("Wapili Mteja");
orderProduct.setUsers(userMoja.get(0));
orderProduct.setProductsManu(typeofProduct);
orderProductManus.setOrderManuId(007);//this is the value that I want to set inside
//MateriaManCalcu entity for property setOrderProductManu
//You can check the relationship above
For: MaterialManuCalcu
MaterialManuCalcu manCalc = new MaterialManuCalcu();
manCalc.setAmountAvailable(availableSheets);
manCalc.setAmountOrdered(sheetsNum);
manCalc.setAmountWillRemain(sheetWillRemain);
manCalc.setMaterialmanu(materialSheet);
manCalc.setOrderProductManu(orderProduct);//doing this the whole object of
//orderProduct entity goes inside a one column in our MatrialManuCalcuof entity
Table:material_manu_calculator
How should I do this correctly. Thanks in advance.
You are trying to set id of orderProduct which is returned by calling orderProduct.getOrderManuId() of type int to variable of type OrderProductManu.
Just pass your orderProduct like this manCalc.setOrderProductManu(orderProduct)
I have to map a composite PK with JPA in an Oracle DB.
I've followed other SO questions with relation to this tutorial but I'm still getting the following error:
java.sql.SQLSyntaxErrorException: ORA-00904: "COMPOSITEI0_"."NAME_1": Invalid Identifier (where NAME_1 relates to the name of one of the columns which are part of the PK)
This is my entity (real names not mentioned for data protection reasons):
#Entity
#Table(schema = "SCHEMA", name = "TABLE")
public class CompositeIdEntity {
#Column(name = "NAME1")
private String name1;
#Column(name = "NAME2")
private String name2;
#Column(name = "NAME3")
private String name3;
#EmbeddedId
CompositePrimaryKeyTableEmbeddable id;
public CompositePrimaryKeyTableEmbeddable getId() {
return this.id;
}
public void setId(CompositePrimaryKeyTableEmbeddable id) {
this.id = id;
}
// other getters and setters
My #Embeddable id class:
#Embeddable
public class CompositePrimaryKeyTableEmbeddable implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
#Column(name="name1")
private String name1;
#Column(name="name2")
private String name2;
public CompositePrimaryKeyTableEmbeddable() {
super();
}
public CompositePrimaryKeyTableEmbeddable(String name1, String name2) {
this.name1 = name1;
this.name2 = name2;
}
My #Repository:
#Repository
public interface CompositeIdDao extends JpaRepository<CompositeIdEntity, CompositePrimaryKeyTableEmbeddable> {
}
And finally call to the DB, which only returns null because it's just a test to see if it all works together:
public CompositeIdEto saveCompositeId() {
CompositeIdEntity compositeIdEto = new CompositeIdEntity();
compositeIdEto.setname3("New");
compositeIdEto.setId(new CompositePrimaryKeyTableEmbeddable("ERR", "ER"));
this.compositeIdDao.save(compositeIdEto);
return null;
}
It seems you are duplicating the name1 and name2 columns by declaring them once
in the entity itself and later in the embeddable.
You seem to only need the id embeddable and the name3 declaration in the entity:
#Entity
#Table(schema = "SCHEMA", name = "TABLE")
public class CompositeIdEntity {
#EmbeddedId
CompositePrimaryKeyTableEmbeddable id;
#Column(name = "NAME3")
private String name3;
I have an Employee class. A Worker class extends Employee, and Leader class extends Worker.
Every Leader has a list public List workersResponsibleFor = new ArrayList<>();. Which is a Join table, to illustrate if a Leader is responsible for one or many Workers.
#Entity
#Inheritance
#DiscriminatorColumn(name="EMP_TYPE")
#Table(name="EMPLOYEES")
public abstract class Employee implements Printable, Serializable {
#Id
#GeneratedValue
#Column(name = "employee_id", unique = true)
private int id;
#Column(name = "position")
#Enumerated(EnumType.STRING)
private Position position;
#Column(name = "name")
private String name;
#Column(name = "salary")
private Double salary;
#Transient
public List<Project> projectsWorkingOn = new ArrayList<>();
public Employee() {
}
}
Worker:
#Entity
public class Worker extends Employee {
#Id
#GeneratedValue
#Column(name = "worker_id", unique = true)
private int id;
public Worker() {
}
}
Leader:
#Entity
public abstract class Leader extends Worker {
public Leader() {
}
public Leader(Position position, String name, Double salary) {
super(position, name, salary);
}
#OneToMany
#JoinTable(name="WORKERS_RESPONSIBLE_FOR",
joinColumns = {#JoinColumn(name="RES_ID")},
inverseJoinColumns = {#JoinColumn(name="FOR_ID")})
public List<Worker> workersResponsibleFor = new ArrayList<>();
}
The problem is, every time I try to get a Worker back with the following method:
private static final EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("manager1");
private static final EntityManager entityManager = entityManagerFactory.createEntityManager();
public Worker exampleQuery() {
Worker w;
try {
Query query = entityManager.createQuery("select e1, e2 from Employee e1 join e1.workersResponsibleFor e2 WHERE e1.name LIKE 'James%'");
w = (Worker) query.getSingleResult();
} finally {
entityManager.close();
entityManagerFactory.close();
}
System.out.println(w.getName());
return w;
}
Error:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.company.employees.Worker
I get a java.lang.Object back, insted of a Worker. But all my other methods are able to return Workers, so could be the problem with the query I'm using? Thanks
JPQL of
select e1, e2 from Employee e1 join e1.workersResponsibleFor e2 WHERE ...
will always return rows of type Object[] (and the message tells you exactly that), since that is what the JPA spec defines it to do. And if you look at element 0 it will be of the type of e1, and element 1 will be of the type of e2. Suggest you look at the JPA spec or the documentation of whichever implementation you use.
If you had instead selected just the candidate alias then you get a row of type of e1. Again, defined in the JPA spec!
I've 2 tables Employee & Vehicle, where one employee can have multiple vehicles.
Below is the mapping that I've defined:
Employee.java
#Entity(name = "emp_details")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int empId;
#OneToMany(cascade = CascadeType.ALL, mappedBy="employee")
private List<Vehicle> vehicles = new ArrayList<>();
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public List<Vehicle> getVehicles() {
return vehicles;
}
public void setVehicles(List<Vehicle> vehicles) {
this.vehicles = vehicles;
}
}
Vehicle.java
#Entity
public class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int vehicleId;
#ManyToOne
#JoinColumn(name="empId")
private Employee employee;
private String name;
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public int getVehicleId() {
return vehicleId;
}
public void setVehicleId(int vehicleId) {
this.vehicleId = vehicleId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Main class
public class HibernateTest {
public static void main(String[] args) {
Employee emp = new Employee();
Vehicle vehicle = new Vehicle();
vehicle.setName("Honda");
emp.getVehicles().add(vehicle);
SessionFactory sFactory = new Configuration().configure().buildSessionFactory();
Session session = sFactory.openSession();
session.beginTransaction();
session.save(emp);
session.getTransaction().commit();
session.close();
StandardServiceRegistryBuilder.destroy(sFactory.getSessionFactoryOptions().getServiceRegistry());
}
}
But when I execute this, Vehicle.employee_id is empty. I was expecting that my foreign key will be inserted there.
What am I missing?
Thank You
You need to show us the code that persists your entities, but my guess is that you are not setting the employee to the vehicle.
You need to manage both sides of bidirectional entity relationship. Your code should look something like this
employee.getVehicles().add(vehicle);
vehicle.setEmployee(employee);
session.save(employee);
UPDATE:
In this case, Vehicle is the owning side of the relation because the foreign key is in its database table. You just added the new vehicle to the employee's list of vehicles. When you save the employee, there's nothing to change in Employees database, and the save operation cascades to Vehicle. Vehicle does not have its employee set, it is null, so it puts null in empId column
Bottom line, you have to make sure both sides of bidirectional relationship are wired up correctly.
If you have a bidirectional relationship you have to
set the relation on both sides.
That means you have to set the employee for your vehicle also.
You can do this by calling
vehicle.setEmployee(emp);
and then store or update your entity (if it's not attached to session already).
Usually to set a bidirectional relationship you provide special methods in your entities.
public class Vehicle {
...
public void setEmployee(Employee employee) {
this.employee = employee;
employee.addVehicle(this)
}
...
}
public class Employee {
...
public void addVehicle(Vehicle v) {
if(!vehicles.contains(v)) {
vehicles.add(v);
}
if(!this.equals(v.getEmployee()) {
v.setEmployee(this);
}
}
...
}
In your Employee entity class, you haven't used #Column annotation on empId. In Vehicle class you are referencing Employee using #JoinColumn(name="employee_id"),so column employee_id must exist in emp_details table. So you need to modify your Employee class to something with
#Id
#GeneratedValue
#Column(name="employee_id")
private int empId;
I think need to edit your code. you miss the entity jpa rule. you can some search jpa entity. you read description for you. link : enter link description here
(Modified your Employee.java)
#Entity(name = "employee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int idx;
#OneToMany(cascade = {CascadeType.ALL}, mappedBy = "employee")
private List<Vehicle> vehicle = new ArrayList<>();
...
}
(Modified your Vehicle.java)
#Entity
public class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int idx;
#ManyToOne
#JoinColumn(name="employee_id")
private Employee employee;
...
}
You only need to cascade onetoMany from Employee Entity
I've seen this question on here a few times, however none of the answers fix my issue.
I'm trying to deconstruct a many-to-many relationship down to seperate many-to-one and one-to-many entities so I can add additional columns. From what I have, the main entity saves to the database, but the intermediate does not. If anyone can figure out what's going on I would very much appreciate it. I tried doing this the other way with the primary key composite (aka: #AssociationOverride) but it also did not work. I've scowered the web but cannot find an answer to my issue here.
This is my main entity, MaintOrder:
#Entity
#Table(name="maint_orders")
public class MaintOrder extends PersistedObject implements java.io.Serializable {
...
#OneToMany(cascade = CascadeType.ALL, mappedBy="maintOrder")
private Set<ManPowerLine> manPower = new HashSet<ManPowerLine>() ;
public void addManPower(ManPower manPower, Integer quantity, Float price) {
ManPowerLine mpLine = new ManPowerLine();
mpLine.setManPower(manPower);
mpLine.setMaintOrder(this);
mpLine.setManPowerID(manPower.getManPowerID());
mpLine.setMaintOrderID(this.getMaintOrderID());
mpLine.setQuantity(quantity);
mpLine.setPrice(price);
this.manPower.add(mpLine);
// Also add the association object to the employee.
manPower.getMaintOrder().add(mpLine);
}
... getters and setters
}
Here is my secondary entity, ManPower:
#Entity
#Table(name="man_power")
public class ManPower extends PersistedObject implements java.io.Serializable {
...id's, etc
#OneToMany(mappedBy="manPower", fetch = FetchType.EAGER)
private Set<ManPowerLine> maintOrder = new HashSet<ManPowerLine>();
public Set<ManPowerLine> getMaintOrder(){
return maintOrder;
}
public void setMaintOrder(Set<ManPowerLine> maintOrder){
this.maintOrder = maintOrder;
}
... other getters and setters
}
Here is my intermediate entity, ManPowerLine:
#Entity
#Table(name = "man_power_line")
#IdClass(ManPowerLineID.class)
public class ManPowerLine extends PersistedObject implements java.io.Serializable {
#Id
private Long maintOrderID;
#Id
private Long manPowerID;
#Column(name="quantity")
private Integer quantity;
#Column(name="price")
private Float price;
#ManyToOne
#JoinColumn(name = "maintOrderID", updatable = false, insertable = false, referencedColumnName = "maint_order_id")
private MaintOrder maintOrder;
#ManyToOne
#JoinColumn(name = "manPowerID", updatable = false, insertable = false, referencedColumnName = "man_power_id")
private ManPower manPower;
... other getters and setters
}
And my ID entity, ManPowerLineID:
public class ManPowerLineID implements java.io.Serializable {
private Long maintOrderID;
private Long manPowerID;
public Long getMaintOrderID(){
return maintOrderID;
}
public Long getManPowerID(){
return manPowerID;
}
public void setMaintOrderID(Long maintOrderID){
this.maintOrderID = maintOrderID;
}
public void setManPowerID(Long manPowerID){
this.manPowerID = manPowerID;
}
#Override
public int hashCode(){
return (int)(maintOrderID + manPowerID);
}
#Override
public boolean equals(Object obj) {
if( obj instanceof ManPowerLine){
ManPowerLineID otherID = (ManPowerLineID)obj;
boolean hey = (otherID.maintOrderID == this.maintOrderID) && (otherID.manPowerID == this.manPowerID);
return hey;
}
return false;
}
}
Finally the code which utilizes this is as follows:
private void insertObject( ) {
ServiceLocator locator = new ServiceLocator();
SessionFactory sf = locator.getHibernateSessionFactory();
Session sess = sf.openSession();
Transaction tx = sess.beginTransaction();
MaintOrder m = new MaintOrder();
... various setters to m
Set manPowerSet = new HashSet();
for(int i = 0; i < manPowerSet.size(); i++){
ManPower mp = new ManPower();
mp = (ManPower) manPowerSet.iterator().next();
m.addManPower(mp, quantity, cost);
}
sess.saveOrUpdate(m);
tx.commit();
sess.close();
}
Is it possible that I need to use more then just m.addManPower to add to the line? I've tried adding m.setManPowerLine, but it does not change the result.
Anyways I know its a lot of code to look at, but thanks in advance.
Turns out I fixed my own issue on this one. The problem was that I didn't set cascade = CascadeType.ALL, in ALL the right places. Specifically Here:
#OneToMany(mappedBy="manPower", fetch = FetchType.EAGER)
private List<ManPowerLine> maintOrder = new ArrayList<ManPowerLine>();
Should be:
#OneToMany(mappedBy="manPower", cascade = CascadeType.All)
private List<ManPowerLine> maintOrder = new ArrayList<ManPowerLine>();