Hibernate Self reference - java

I'm trying to map with Hibernate an entity Product with self reference to other products.
The JSON sent to create a project is like this:
{"name":"chair", "description":"red chair",
"parent": {"name":"table","description":"red table"}
}
When I receive this json, I need to persist on DB the child product and set PARENT_PRODUCT_ID with the productId from parent attribute.
Some help, please?
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer productId;
#Column(name = "NAME")
private String name;
#Column(name = "DESCRIPTION")
private String description;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="PRODUCT_ID")
private List<Image> images;
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="PRODUCT_ID")
private List<Product> children;
#ManyToOne
#JoinColumn(name = "PARENT_PRODUCT_ID")
private Product parent;
Image.java:
#Entity
#Table
public class Image implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer imageId;
#Column(name = "TYPE")
private String type;
#ManyToOne
#JoinColumn(name = "PRODUCT_ID", nullable = false)
private Product product;

In the oneToMany relationships, I think it should be like:
#OneToMany(cascade=CascadeType.ALL, mappedBy="parent")
private List<Product> children;

Related

JPA : How to handle mapping with a table that has relationship with two other tables?

I have three tables, table A (product), table B (invoice) and table C (invoices_info) which contains two columns referencing invoice_id and product_id. How can i insert a new entry (a new invoice) while inserting the products to the appropriate table and inserting the invoice info to its table also ?
Here are the entity classes :
Product
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "family_id")
private long familyId;
#Column(name = "product_name")
private String productName;
#Column(name = "product_category")
private String productCategory;
#Column(name = "product_quantity")
private int productQuantity;
//getters and setters
}
Invoice
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "invoice_id")
private Long id;
#Column(name = "provider_id")
private Long providerId;
#Column(name = "total")
private int invoiceTotal;
#Column(name = "date")
private Date invoiceDate;
//getters and setters
}
InvoiceInfo
#Entity
#Table(name = "invoice_info")
public class InvoiceInfo {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "item_id")
private long id;
#Column(name = "product_id")
private long productId;
#Column(name = "invoice_id")
private long invoiceId;
//getters and setters
}
InvoiceInfo should be join table, Define relationship on entities Product & Invoice using annotations #OneToMany, #ManyToOne based on your requirement.
You have to create relationships between your entities by using a set of annotations like: #ManyToOne, #OneToMany, #ManyToMany or #OneToOne... and other annotations if needed.
In your case I am not really sure you need an InvoiceInfo table, as the Invoice table can (or should) already contains the list of products.
I would suggest you the following relationships:
Product
#Entity
#Table(name = "product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "family_id")
private long familyId;
#Column(name = "product_name")
private String productName;
#Column(name = "product_category")
private String productCategory;
#Column(name = "product_quantity")
private int productQuantity;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "invoice_id", referencedColumnName = "id")
private Invoice invoice;
//getters and setters
}
Invoice
#Entity
#Table(name = "invoice")
public class Invoice {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "invoice_id")
private Long id;
#Column(name = "provider_id")
private Long providerId;
#Column(name = "total")
private int invoiceTotal;
#Column(name = "date")
private Date invoiceDate;
#OneToMany(mappedBy = "product")
private List<Product> products;
//getters and setters
}
As your table InvoiceInfo no longer exists, you just have to insert you data in two table like this:
Invoice invoice = invoiceRepository.save(invoice);
Product product = new Product();
// Set the other properties
product.setInvoice(invoice);
productRepository.save(product);

Empty List between ManyToMany relationship

I have two entities,Client and Product ,and they have a relation #ManyToMany, when I do a POST to create a Client with a Product, I recive a empty list of Produtcs.
public class Produto implements Serializable {
private static final long serialVersionUID = -6381222920639794489L;
#Id
#Column(name = "id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "descricao")
private String descricao;
#Column(name = "preco")
private Float preco;
#ManyToMany
#JoinTable(name = "produto_cliente",
joinColumns = #JoinColumn(name = "cliente_fk"),
inverseJoinColumns = #JoinColumn(name = "produto_fk"))
private List<Cliente> clientId;
}
public class Cliente implements Serializable {
private static final long serialVersionUID = -1195126015856369746L;
#Id
#Column(name = "id", nullable = false)
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "nome")
private String nome;
#Column(name = "cpf")
private String cpf;
#ManyToMany(mappedBy = "clientId")
private List<Produto> produtos;
}
The list of products
The list os clients after I created and added the product

How to maintain foreign key relationship in hibernate

I have two classes and I want to have a one to many relation between them, for e.g.:
Home(id<int>, rooms<string>)
Vehicle(id<int>, home_id<int>, name<string>)
I need to have a relation between Home and Vehicle class using Home.id and vehicle.home_id.
Please suggest any example which I can use here for CURD operation to implement REST service.
I need to have a relation between Home and Vehicle class using Home.id
and vehicle.home_id.
Your entities should look like this :
Vehicle Entity
#Entity
#Table(name = "vehicle", catalog = "bd_name", schema = "schema_name")
#XmlRootElement
public class Vehicle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "name")
private String name;
#JoinColumn(name = "home_id", referencedColumnName = "id")
#ManyToOne
private Home homeId;
//constructor getter & setters
}
Home Entity
#Entity
#Table(name = "home", catalog = "bd_name", schema = "schema_name")
#XmlRootElement
public class Home implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "room")
private Character room;
#OneToMany(mappedBy = "homeId")
private List<Vehicle> vehicleList;
//constructor getter & setters
}

how to resolve the 'save transient instance before saving' error on one to many relationship in hibernate jpa

this is the parent entity this is the child entityi have tried the suggested solution to similar error above but my application still spits out the same exception. please i need help
below is the exception
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: com.domkat.springmvcjpa.model.Cpfaceleft1angle.cpftid -> com.domkat.springmvcjpa.model.Fromtocp
at org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:380)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:177)
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:162)
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:153)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:89)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy626.save(Unknown Source)
#Entity
#Table(name = "cpobservedhorizontalangles")
public class Cpobservedhorizontalangles implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "degree")
private Integer degree;
#Column(name = "minute")
private Integer minute;
#Column(name = "second")
private Integer second;
#Column(name = "degminsec")
private String degminsec;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ohaid")
private Integer ohaid;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceleft2angle> cpfaceleft2angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceright2angle> cpfaceright2angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceleft1angle> cpfaceleft1angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceright1angle> cpfaceright1angleList;
...getters and setters... this is the child entity
#Entity
#Table(name = "cpfaceleft1angle")
public class Cpfaceleft1angle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#OneToMany(cascade={CascadeType.PERSIST},mappedBy = "cpfl1id")
private List<Fromtocp> fromtocpList;
#JoinColumn(name = "ohaid", referencedColumnName = "ohaid")
#ManyToOne
private Cpobservedhorizontalangles ohaid;
#JoinColumn(name = "faceid", referencedColumnName = "faceid")
#ManyToOne
private Faceleft faceid;
...getters and setters... this is the parent class but it contains other
entities
public class Fromtocp implements Serializable {
private static final long serialVersionUID = 1L;
// #Max(value=?) #Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
#Column(name = "distance")
private Double distance;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ftcpid")
private Integer ftcpid;
#Column(name = "diffleft")
private String diffleft;
#Column(name = "diffright")
private String diffright;
#Column(name = "meandiff")
private String meandiff;
#Column(name = "oadegdec")
private Double oadegdec;
#Column(name = "fb")
private Double fb;
#Column(name = "bb")
private Double bb;
#JoinColumn(name = "fromcp", referencedColumnName = "cpid")
#ManyToOne
private Controlpoints fromcp;
#JoinColumn(name = "cpfl1id", referencedColumnName = "id")
#ManyToOne
private Cpfaceleft1angle cpfl1id;
#JoinColumn(name = "cpfl2id", referencedColumnName = "id")
#ManyToOne
private Cpfaceleft2angle cpfl2id;
#JoinColumn(name = "cpfr1id", referencedColumnName = "id")
#ManyToOne
private Cpfaceright1angle cpfr1id;
#JoinColumn(name = "cpfr2id", referencedColumnName = "id")
#ManyToOne
private Cpfaceright2angle cpfr2id;
#JoinColumn(name = "tocp", referencedColumnName = "cpid")
#ManyToOne
private Controlpoints tocp;
...this is the other entity the parent class contains.
#Controller
public class SurveyController {
#Autowired
private SurveyService ss;
#Autowired
private ControlPointService cps;
#Autowired
private ScpService sps;
#Autowired
private CpobservedhorizontalanglesService cpos;
#Autowired
private Cpfaceleft1angleService cpfl1;
#Autowired
private Cpfaceleft2angleService cpfl2;
#Autowired
private Cpfaceright1angleService cpfr1;
#Autowired
private Cpfaceright2angleService cpfr2;
#Autowired
private FromTocpService ftcps;
#Autowired
private FaceleftService fls;
#Autowired
private FacerightService frs;
private Processor processor = new Processor();
HttpSession session;
#RequestMapping(value = "/surveydetails")
public String showSurveyDetailsPage(Model model) {
Surveys survey = new Surveys();
model.addAttribute("survey", survey);
return "SurveyDetails";
}
#RequestMapping(value = "/stations", method = RequestMethod.POST)
public String createSurvey(#RequestParam("surveyTitle") String title,
#RequestParam("cp1Label") String cp1Label, #RequestParam("cp1Northings") double northingsCp1,
#RequestParam("cp1Eastings") double eastingsCp1, #RequestParam("cp2Label") String cp2Label,
#RequestParam("cp2Northings") double northingsCp2, #RequestParam("cp2Eastings") double eastingsCp2,
#RequestParam("distance") double distance, #RequestParam("fl1Deg") int fl1Deg,
#RequestParam("fl1Min") int fl1Min, #RequestParam("fl1Sec") int fl1Sec,
#RequestParam("fl2Deg") int fl2Deg, #RequestParam("fl2Min") int fl2Min, #RequestParam("fl2Sec") int fl2Sec,
#RequestParam("fr1Deg") int fr1Deg, #RequestParam("fr1Min") int fr1Min, #RequestParam("fr1Sec") int fr1Sec,
#RequestParam("fr2Deg") int fr2Deg, #RequestParam("fr2Min") int fr2Min, #RequestParam("fr2Sec") int fr2Sec) {
Surveys survey = new Surveys();
Scp scp = new Scp();
Signups su = null;
Cpobservedhorizontalangles o1 = new Cpobservedhorizontalangles();
o1.setDegree(fl1Deg);
o1.setMinute(fl1Min);
o1.setSecond(fl1Sec);
o1.setDegminsec(processor.degToString(fl1Deg, fl1Min, fl1Sec));
Cpfaceleft1angle fl1 = new Cpfaceleft1angle();
fl1.setOhaid(o1);
fl1.setFaceid(faceleft1);
cpos.save(o1);
cpfl1.save(fl1);
please help. thanks
i have resolved the problem. And in addition i found out how i can actually save just the parent class by calling the save method on the parent and then it saves the child entities as well. jpa makes it quite easy.
i will use an illustration of employee and address. lets say an employee can have more than one address it means we will have two tables in the database and two entity classes, one for each of these tables right?. it also means that the employee table becomes the parent table while the address becomes the child table right? the code below just shows how you can save the parent class and by the saving the parent class the child entities get saved as well! all you do is set the parent object(in this case the employee) on the child object(in this case the address), then set the List(the list of child in this case is address. so it becomes List) on the parent entity. then call the save method on the parent.
...necessary imports...
#Entity
#Table(name = "address")
#NamedQueries({
#NamedQuery(name = "Address.findAll", query = "SELECT a FROM Address a")})
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "address_id")
private Integer addressId;
#Column(name = "employee_address")
private String employeeAddress;
#JoinColumn(name = "employee_id", referencedColumnName = "employee_id")
#ManyToOne
private Employee employeeId;
public Address() {
}
...getters and setters for this entity...
#Entity
#Table(name = "employee")
#NamedQueries({
#NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e")})
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#OneToMany(cascade=CascadeType.ALL,mappedBy = "employeeId")
private List<Address> addressList;
public Employee() {
}
...getters and setters for this class...
...below is the class that makes use of the entities...
public class SaveExample {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPAJoinTableTutorialsPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Employee employee = new Employee();// employee object
Address address = new Address(); // Address Object
address.setEmployeeAddress("set the value");
address.setEmployeeId(employee);
List<Address>addressList=new ArrayList<>();
addressList.add(address);
employee.setEmail("set the value");
employee.setName("set the value for name");
employee.setPhone("set the value");
employee.setAddressList(addressList);
em.persist(employee);
em.getTransaction().commit();
}
}
i hope that helps some people..thanks

How to use a child association property as a Map key in JPA parent entity

I'm having two entities Car and CarDescription where CarDescription is depending on another foreign key from the table Language.
What I' trying to accomplish is to have a HashMap in Car such that whenever I'm having a Car entity-object I am able to access all descriptions from the language id.
Entity Car.java
#Entity
#Table(name = "Car")
public class Car extends AbstractTimestampEntity implements Serializable {
private static final long serialVersionUID = -5041816842632017838L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#OneToMany(mappedBy="car")
#MapKeyColumn(name = "language_ID")
// #MapKey(name = "language") // does not work either
private Map<Long, CarDescription> carDescription = new HashMap<>(0);
}
Entity CarDescription.java
#Entity
#Table( name="car_description",
uniqueConstraints = {
#UniqueConstraint(columnNames={"language_id", "name"})
}
)
public class CarDescription extends AbstractTimestampEntity implements Serializable {
private static final long serialVersionUID = 2840651722666001938L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
private Long id;
#NotNull
#ManyToOne
private Car car;
#NotNull
#OneToOne
private Language language;
// ..
}
Entity Language.java
#Entity
public class Language implements Serializable {
private static final long serialVersionUID = 3968717758435500381L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="ID")
private Long id;
// ..
}
The problem I am having is that the mapping gives me a map from each CarDescription.id to CarDescription.
How can I accomplish a correct mapping?
In CarDescription you need to add the languageId property:
#Column(name = "language_id", insertable = false, updatable = false)
private Long languageId;
#NotNull
#OneToOne
#JoinColumn(name = "language_id")
private Language language;
public void setLanguage(Language language) {
this.languageId = language.getId();
this.language = language;
}
Then you can use it in the Car entity like this:
#OneToMany(mappedBy="car")
#MapKey(name = "languageId")
private Map<Long, CarDescription> carDescription = new HashMap<>(0);

Categories