Spring Boot "Cannot add foreign key constraint" - spring-mvc

I have a spring boot rest service with the following model classes -
Report class -
#Entity
#Table (name = "report")
#EntityListeners(AuditingEntityListener.class)
public class Report {
#Id
#Column (name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "from_user_id", nullable = false)
private Long fromUserId;
#Column(name = "to_user_id", nullable = false)
private Long toUserId;
#Temporal(TemporalType.DATE)
#JsonFormat(pattern = "dd-MM-yyyy hh:mm:ss")
#CreatedDate
private Date createdAt;
#Column(nullable = false)
private String observation;
[ OTHER VARS AND GETTERS AND SETTERS .... ]
}
User class -
#Entity
#Table (name = "user")
#EntityListeners(AuditingEntityListener.class)
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class User {
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable = false)
private String firstName;
#Column(nullable = false)
private String lastName;
#Column(unique = true, nullable = false)
private String email;
#Column(nullable = false)
private String password;
#OneToMany(cascade = CascadeType.ALL, targetEntity = Report.class)
#JoinColumn(name = "to_user_id")
private List<Report> reportReceivedList;
#OneToMany(cascade = CascadeType.ALL, targetEntity = Report.class)
#JoinColumn(name = "from_user_id")
private List<Report> reportSentList;
[GETTERS AND SETTERS .....]
}
This is causing a
org.hibernate.tool.schema.spi.CommandAcceptanceException: Error executing DDL via JDBC Statement
which in turn is caused by
Caused by: java.sql.SQLException: Cannot add foreign key constraint
I want to create my mapping such that one user can have multiple sent reports and received reports, and once I delete a user, both sent and received reports should get deleted. I have explored loads of links for creating mappings and I am very confused because of different methods given everywhere.

Related

Use #RequestParam for DTO fields implicitly

Controller
#RequestMapping(method = RequestMethod.GET)
public ResponseEntity<PaginatedResponse<User>> getAllUsers(
#RequestParam(defaultValue = "") String q,
#RequestParam(defaultValue = "") String[] fields,
#RequestParam(defaultValue = "") String[] sort,
#RequestParam(defaultValue = "50") Integer limit,
#RequestParam(defaultValue = "0") Integer offset,
#RequestParam(defaultValue = "") String userField1,
#RequestParam(defaultValue = "") String userField2,
#RequestParam(defaultValue = "") Boolean userField3,
#RequestParam(defaultValue = "") ZonedDateTime userField4,
#RequestParam(defaultValue = "") String userRoleId5,
#RequestParam(defaultValue = "") Long userRoleId6,
#RequestParam(defaultValue = "") Long userRoleId7
) {
//call to service
}
UserDTO
public class UserDTO {
private String userField1;
private String userField2;
private boolean userField3;
ZonedDateTime userField4;
#JsonProperty("USERFIELD5")
private String userField5;
#JsonProperty("USERFIELD6")
private Long userField6;
#JsonProperty("USERFIELD7")
private Long userField7;
//getters and setters
}
user fields are used in GET /users parameter to filter the list of users in response. The current code works but I'm wondering if there is a better way to avoid this manual definition of the fields in the controller.
I considered using HahsMap to get all the request parameters but I opt out since I need to check if the passed parameter is valid.
Use #ResponseBody like
#ResponseBody
#RequestMapping(value = "your mapping here", method = RequestMethod.GET)
public List<User> getUsers() {
}
and serialize your User entity attributes with Jackson or GSON w/e
With gson you can serialize your fields like
#SerializedName("user_id")
private Integer id;

Entity Manager is not fetching child records after adding data

I am using entity manager to persist data into the database. Data is inserting successfully, but when try to fetch the data it doesn't fetch the child data.
Incident.java
#Entity
#Table(name = "Incident")
public class Incident {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "incidentID")
private Integer incidentID;
#Column(name = "incidentTitle")
private String incidentTitle;
#Column(name = "date")
#JsonFormat(pattern = "yyyy-MM-dd")
private Date incidentDate;
#Column(name = "incidentContent")
private String incidentContent;
#ManyToOne
#JoinColumn(name = "countryID")
private Country country;
// Getter and setters
}
Country.java
#Entity
#Table(name="Country")
public class Country {
#Id
#Column(name="id")
#GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
#NotNull
#Column(name = "name")
#Size(min = 8, max = 100)
private String name;
// getter and setters
}
DAO.java
public Incident addIncident(Incident incident) {
em.getTransaction().begin();
em.persist(incident);
em.flush();
em.getTransaction().commit();
return incident;
}
When i add data into incident table, countryId added successfully but when i try to fetch the same record, countryId comes but name doesn't come.
But when i try to update same record or bounce server or redeploy the application then all data comes successfully along with name.
Couldn't understand the issue.
Can you please help me.

Hibernate cannot simultaneously fetch multiple bags for Parent-Children-Grandchildren unidirectional association

Straightforward to the point. I am given Hibernate exception Caused by: org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags.
I have 3 entities in a Parent --(1-*)--> Child --(1-*)--> Grandchild unidirectional relationship:
NetworkElement -> NetworkElementInterface -> NetworkElementInterfaceCounters
Over both relationship I have defined FetchType.LAZY.
#Entity
#Table(name = "NETWORK_ELEMENTS")
public class NetworkElement extends Device {
#Id
#Column(name = "ID_DEVICE")
private Long id;
#ManyToOne(targetEntity = DeviceLocation.class, fetch = FetchType.LAZY)
#JoinColumn(name = "ID_DEVICE_LOCATION")
private DeviceLocation deviceLocation;
#Column(name = "MODEL", length = 30)
private String model;
#Column(name = "TYPE", length = 30)
private String type;
#Column(name = "IMAGE", length = 50)
private String image;
#OneToMany(orphanRemoval = true, fetch = FetchType.LAZY, targetEntity = NetworkElementInterface.class, cascade=CascadeType.ALL)
#Size(min = 0, max = 99)
private List<NetworkElementInterface> interfaces;
}
#Entity
#Table(name = "NETWORK_ELEMENT_INTERFACES")
public class NetworkElementInterface {
#Id
#Column(name = "ID_NETWORK_ELEMENT_INTERFACES")
protected Long id;
#Column(name = "NAME")
private String name;
#Column(name = "SPEED")
private Long speed;
#Column(name = "DUPLEX")
private String duplex;
#ElementCollection(fetch = FetchType.LAZY)
#CollectionTable(name = "NETWORK_ELEMENT_INTERFACE_COUNTERS", joinColumns = #JoinColumn(name = "ID_NETWORK_ELEMENT_INTERFACE"))
#Type(type = "com.netsuite.wind.entity.NetworkElementInterfaceCounters")
private List<NetworkElementInterfaceCounters> interfaceCountersHistory;
}
#Embeddable
public class NetworkElementInterfaceCounters {
private Long inputErrors;
private Long inputDrops;
private Long inputDiscards;
private Long inputCRCErrors;
private Long inputFifoErrors;
private Long outputErros;
private Long outputDrops;
private Long outputCRCErrors;
private Long outputFifoErrors;
}
What I am trying to achieve is:
1) in my DAO to create a method which will return Parent fully populated with its children and grandchildren. (NetworkElement -> NetworkElementInterface -> NetworkElementInterfaceCounters).
1b) (not really important here, just curious) Eventually I would also like to populate children of a different type, in my NetworkElement DeviceLocation object along with populated NetworkInterfaces.
My DAO Method of NetworkElement:
#Transactional()
#SuppressWarnings("unchecked")
public NetworkElement getByIdWithInterfaces(Long id) {
final Session session = sessionFactory.getCurrentSession();
------------------------------------------------------
// This works well when I only want children to by populated
Query query = session.createQuery("SELECT ne FROM NetworkElement ne JOIN FETCH ne.interfaces WHERE ne.id = :id");
------------------------------------------------------
// This doesn't work when I also try to fetch grandchildren. I am given Hibernate exception: "cannot simultaneously fetch multiple bags"
Query query = session.createQuery("SELECT ne FROM NetworkElement ne JOIN FETCH ne.interfaces nei JOIN FETCH nei.interfaceCountersHistory WHERE ne.id = :id");
------------------------------------------------------
// Eventually I tried "FETCH ALL PROPERTIES" which also doesn't work.
Query query = session.createQuery("FROM NetworkElement ne FETCH ALL PROPERTIES WHERE ne.id = :id");
------------------------------------------------------
query.setParameter("id", id);
NetworkElement result = null;
try {
result = (NetworkElement) query.uniqueResult();
} catch (NoResultException e) {
e.printStackTrace();
}
return result;
}
So for:
1) Query query = session.createQuery("SELECT ne FROM NetworkElement ne JOIN FETCH ne.interfaces nei JOIN FETCH nei.interfaceCountersHistory WHERE ne.id = :id");
Try to make it work.
I think I am missing somewhere some annotation in order to avoid this kind of exception. I noticed in some examples they were using #IndexColumn but this annotation is deprecated.. Appreciate any directions for this.

Try to show data from db using JPA and EJB

I try to display data from my database, but I get 500 error page: javax.ejb.EJBException. I don't understand why it's not working. Maybe my Bean is wrong? Please help me.
Warning in Glassfish log: WARNING: WARNING: EJB5184:A system exception occurred during an invocation on EJB SearchBean, method: public java.util.Collection com.stark.logic.SearchBean.searchByNumber(int)
#Entity
#Table(name = "buy")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Buy.findAll", query = "SELECT b FROM Buy b"),
#NamedQuery(name = "Buy.findByIdBuy", query = "SELECT b FROM Buy b WHERE b.idBuy = :idBuy"),
#NamedQuery(name = "Buy.findByNumberBuy", query = "SELECT b FROM Buy b WHERE b.numberBuy = :numberBuy")})
public class Buy implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id_buy")
private Integer idBuy;
#Basic(optional = false)
#NotNull
#Column(name = "number_buy")
private int numberBuy;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "buy")
private Product product;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "buy")
private Client client;
//getters & setters
EJB BEAN:
#Stateless
#LocalBean
public class SearchBean {
#PersistenceUnit
EntityManagerFactory emf;
EntityManager em;
public Collection searchByNumber(int number){
em = emf.createEntityManager();
Query searchQuery = em.createNamedQuery("Buy.findByNumberBuy");
searchQuery.setParameter("number_buy", number);
List list = new ArrayList();
list = searchQuery.getResultList();
return list;
}
}
Servlet:
#EJB
private SearchBean searchBean;
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
response.setContentType("text/html;charset=UTF-8");
String num = request.getParameter("number");
int number = Integer.parseInt(num);
List list = new ArrayList();
list = (List) searchBean.searchByNumber(number);
Iterator it = list.iterator();
while(it.hasNext()){
Buy buy = (Buy) it.next();
out.println(buy.getProduct());
}
}
Parameter name in #NamedQuery and in setParameter() method must be equal:
searchQuery.setParameter("numberBuy", number);

one-to-many detached Criteria parent table fetch based on child table

i have one problem in one-to-many mapping using hibernate.
i have 2 classes, Person and Address. Person is mapped by Address ( one-to-many)
i want get all Person where Address = "xxxx";. how to prepare this query using DetachedCriteria . below i have added a piece of code from my dao class. please help me to complete it.
Person.java
#Entity
#Table(name="PERSON")
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="personId")
private int id;
#Column(name="personName")
private String name;
#OneToMany(cascade =CascadeType.ALL,fetch = FetchType.LAZY)
#JoinColumn(name="personId")
private Set <Address> addresses;
}
Address.java
#Entity
#Table(name = "ADDRESS")
public class Address {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "addressId")
private int id;
#Column(name = "address",nullable=false)
private String address;
#ManyToOne(cascade =CascadeType.ALL)
#JoinColumn(name="personId",nullable=false)
private Person person;
}
My DAO
DetachedCriteria c = DetachedCriteria.forClass(Person.class);
List<Person> persnList =null;
/*here i want add some restriction for
fetch all person whose address = "abcd"
here address is collection. how to set restriction in it ?.
*/
persnList = getHibernateTemplate().findByCriteria(c);
System.out.println(persnList.size());
select * from person where Address.address = "xxxx"; how to implement this using DetachedCriteria ?
DetachedCriteria c = DetachedCriteria.forClass(Person.class);
List<Person> persnList =null;
DetachedCriteria addrCrit = c.createCriteria("addresses").addRestriction(Restrictions.eq("address","abcd"));
addrCrit.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
persnList = getHibernateTemplate().findByCriteria(c);
System.out.println(persnList.size());
Creating inner criteria on main criteria which will do an equivalent inner join.

Resources