I am having some issues according Hibernate.
I have a more or less complex object structure that I want to save / load using the Hibernate EntityManager (version 4.3.5.Final). I managed to save it, but if I attempt to read the obejct, only the PK will be read. The EntityManager's find method returns null even with the correct PK so I am using its getReference method.
I still have troubles using the correct relationship (ManyToOne and such) so I most likely made a mistake there and I guess that is causing the problem.
Anyways.
My question is: How do i persist an object structure like this using Hibernate?
Here are the POJOs i am using:
EDIT: Updated the Code
CalculationList:
#Entity(name = "calculation")
public class CalculationList implements EntityList {
#Id
private Date created;
#OneToMany(mappedBy = "", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<Product> products;
public CalculationList(Date created) {
this.created = created;
this.products = new LinkedList<>();
}
public CalculationList(Date created, List<Product> products) {
this.created = created;
this.products = products;
}
public CalculationList() {
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> entities) {
this.products = entities;
}
#Override
public String toString() {
return "CalculationList{" +
"created=" + created +
", products=" + products +
'}';
}
}
CalulatorEntity:
#Entity(name = "calculator_entity")
public class CalculatorEntity implements Serializable {
#Id
private int id;
private CalculatorEntityType type;
private String name;
private int number;
#ManyToOne(cascade = CascadeType.ALL)
private Product product;
public CalculatorEntity(CalculatorEntityType type) {
this.type = type;
}
protected CalculatorEntity() {
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public Product getProduct() {
return product;
}
public void setProduct(Product product) {
this.product = product;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public CalculatorEntityType getType() {
return type;
}
public void setType(CalculatorEntityType type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public enum CalculatorEntityType {
GAS_PUMP, DELIVERY_BILL;
}
#Override
public String toString() {
return "CalculatorEntity{" +
"id=" + id +
", type=" + type +
", name='" + name + '\'' +
", product=" + product +
", number=" + number +
'}';
}
}
Product:
#Entity(name = "product")
public class Product implements Serializable {
#Id
private int id;
private String name;
private ProductType type;
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<CalculatorEntity> entities;
public Product(String name, ProductType type) {
this.name = name;
this.type = type;
this.entities = new LinkedList<>();
}
/**
* JPA - Konstruktor
*/
public Product() {
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ProductType getType() {
return type;
}
public void setType(ProductType type) {
this.type = type;
}
public List<CalculatorEntity> getEntities() {
return entities;
}
public void setEntities(List<CalculatorEntity> entities) {
this.entities = entities;
}
#Override
public String toString() {
return "Product{" +
"id=" + id +
", name='" + name + '\'' +
", type=" + type +
", entities=" + entities +
'}';
}
public enum ProductType {
FUEL("Treibstoff"), OIL("Öl"), OTHER("Verschiedenes");
private String name;
private ProductType(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}
}
You are using the #OneToMany mapping with the wrong entity, instead of mapping Product class you are mapping CalculationList class, move the following configuration:
#OneToMany(mappedBy = "product", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private List<CalculatorEntity> entities;
to the Product class.
Related
I using #MockMvc test in spring controller but i have a question.
How to handle message error when MockMvc test not pass method.
Entity:
#Entity
#ApiModel(description = "All details about the Product")
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.AUTO,generator = "system-uuid")
#GenericGenerator(name = "system-uuid",strategy = "uuid2")
private String id;
#NotNull(message = "name can not null")
#ApiModelProperty(notes = "The name is product")
private String name;
#ApiModelProperty(notes = "The type is product")
private String type;
#NotNull(message = "category can not null")
private String category;
private String description;
private Double prince;
public Product() {
}
public Product(String name, String type, String category, String description, Double prince) {
this.name = name;
this.type = type;
this.category = category;
this.description = description;
this.prince = prince;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Double getPrince() {
return prince;
}
public void setPrince(Double prince) {
this.prince = prince;
}
#Override
public String toString() {
return "Product{" +
"id='" + id + '\'' +
", name='" + name + '\'' +
", type='" + type + '\'' +
", category='" + category + '\'' +
", description='" + description + '\'' +
", prince=" + prince +
'}';
}
}
StudentController:
#RestController
#RequestMapping("/products")
public class ProductController {
#PostMapping
public ResponseEntity<ProductDto> createProduct(#RequestBody Product product) {
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(product.getId()).toUri();
return ResponseEntity.created(location).body(productService.createProduct(product));
}
}
In above entity, I want using #MockMvc test createProduct. If name in product is null, i want show message in #MockMvc . It look like: "name can not null" . If pass, i don't want show it. Bellow my test:
#Test
public void givenProductURIWithPost_whenMockMVC_thenVerifyResponse() {
this.mockMvc.perform(post("/products")).andDo(print())
.andExpect(status().isOk()).andExpect(content()
.contentType("application/json;charset=UTF-8"))
}
I have two question:
1.How to show message "name can not null" if name in product is
null in #mockmvc.
2. If my project in 20 field in Products entity : Example: name,category.. I can test sequence field in Products or only test
one time contain all field.
I have this error in spring boot:
attempted to assign id from null one-to-one property [com.endoorment.models.entity.ActionLang.action]
My code:
#Embeddable
public class ActionLangId implements Serializable {
private static final long serialVersionUID = 1 L;
#NotNull
#Column(name = "actions_id")
private Integer actionId;
#NotNull
#Column(name = "langs_id")
private Integer langId;
public ActionLangId() {}
public ActionLangId(Integer actionId, Integer langId) {
super();
this.actionId = actionId;
this.langId = langId;
}
public Integer getActionId() {
return actionId;
}
public void setActionId(Integer actionId) {
this.actionId = actionId;
}
public Integer getLangId() {
return langId;
}
public void setLangId(Integer langId) {
this.langId = langId;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass())
return false;
ActionLangId that = (ActionLangId) o;
return Objects.equals(actionId, that.actionId) &&
Objects.equals(langId, that.langId);
}
#Override
public int hashCode() {
return Objects.hash(actionId, langId);
}
}
#Entity
#Table(name = "actions_langs")
public class ActionLang {
#EmbeddedId
private ActionLangId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("actionId")
#JoinColumn(name = "actions_id")
private Action action;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("langId")
#JoinColumn(name = "langs_id")
private Lang lang;
#NotNull(message = "null")
#Size(max = 45, message = "short")
private String name;
public ActionLang() {}
public ActionLang(ActionLangId actionlangid, String name) {
this.id = actionlangid;
this.name = name;
}
public ActionLangId getId() {
return id;
}
public void setId(ActionLangId id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "ActionLang [id=" + id + ", name=" + name + "]";
}
}
Service:
#Transactional
public ActionLang saveAction(Integer idlang, String name) {
Integer id = actionRepository.findActionId();
Action action = new Action(id);
actionRepository.save(action);
ActionLang actionlang = new ActionLang(new ActionLangId(id, idlang), name);
actionlangRepository.save(actionlang);
return actionlang;
}
Structure actionlang: {
"id": {
"actionId": 2,
"langId": 1
},
"name": "hkjhlhklhkllñkñl"
Thanks
My solution,
Entity Action:
#Entity
#Table(name = "actions")
public class Action {
#Id
private Integer id;
#OneToMany(mappedBy = "action")
private List<ActionLang> actionlang = new ArrayList<>();
public Action() { }
public Action(Integer id) {this.id = id;}
public Integer getId() {return id;}
public void setId(Integer id) {this.id = id;}
public List<ActionLang> getActionLang() {return actionlang;}
public void addActionLang(ActionLang actionlang) {
this.actionlang.add(actionlang);
}
public void removeActionLang(ActionLang actionlang) {
this.actionlang.remove(actionlang);
}
#Override
public String toString() {return "id: " + id ;}
}
Entity ActionLang,
#Entity
#Table(name = "actions_langs")
public class ActionLang {
#EmbeddedId
private ActionLangId id;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("actionId")
#JoinColumn(name = "actions_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Action action;
#ManyToOne(fetch = FetchType.LAZY)
#MapsId("langId")
#JoinColumn(name = "langs_id", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Lang lang;
#NotNull(message="null")
#Size(max = 45, message="short")
private String name;
public ActionLang() {}
public ActionLang(ActionLangId actionlangid, String name) {
this.id = actionlangid;
this.name = name;
}
public ActionLangId getId() {return id;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public void setId(ActionLangId id) {this.id = id;}
public Action getAction() {return action;}
public void setAction(Action action) {this.action = action;}
public Lang getLang() {return lang;}
public void setLang(Lang lang) { this.lang = lang; }
#Override
public String toString() {return "ActionLang [id=" + id + ", name=" + name + "]"; }
}
Service
#Component
public class ActionDAOService {
#Autowired
private IActionDao actionRepository;
#Autowired
private IActionLangDao actionlangRepository;
#Transactional
public Action saveAction(Integer idlang, String name){
Lang lang = new Lang();
lang.setId(idlang);
Integer id = actionRepository.findActionId();
if(id == null) {
id=(Integer) 1;
}
Action action = new Action(id);
actionRepository.save(action);
ActionLang actionlang = new ActionLang(new ActionLangId(id, idlang),name);
action.addActionLang(actionlang);
actionlang.setAction(action);
actionlang.setLang(lang);
actionlangRepository.save(actionlang);
return action;
}
}
I have modified service and I have the same error
#Transactional
public Action saveAction(Integer idlang, String name){
Integer id = actionRepository.findActionId();
if(id == null) {id=(Integer) 1;}
Action action = new Action(id);
ActionLang actionlang = new ActionLang(new ActionLangId(id, idlang),name);
action.getActionlang().add(actionlang);
actionRepository.save(action);
return action;
}
And the structure of action is this:
{
"id": 2,
"actionlang": [
{
"id": {
"actionId": 2,
"langId": 1
},
"name": "hkjhlhklhkllñkñl"
}
]
}
Entity action
#Entity
#Table(name = "actions")
public class Action {
#Id
private Integer id;
#OneToMany(mappedBy = "action", cascade = CascadeType.ALL, orphanRemoval = true)
private List<ActionLang> actionlang = new ArrayList<>();
public Action() {
}
public Action(Integer id) {
super();
this.id = id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public List<ActionLang> getActionlang() {
return actionlang;
}
#Override
public String toString() {
return "Action [id=" + id + ", actionlang=" + actionlang + ", getId()=" + getId() + ", getActionlang()="
+ getActionlang() + ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()="
+ super.toString() + "]";
}
}
I have a RESTcontroller that has a delete mapping like so:
#DeleteMapping("/deleterequest/{custId}")
//#Transactional
public ResponseEntity<?> delete(#PathVariable long custId) {
log.info("entering deleterequest");
LeaveQuery deleteLeaveQuery = leaveQueryRepository.findOne(custId);
log.info("condition" + deleteLeaveQuery.getStatus().equals("Onbehandeld"));
// if (!deleteLeaveQuery.getStatus().equals("Onbehandeld"))
// return ResponseEntity.badRequest().build();
//deleteLeaveQuery.setAccount(null);
//leaveQueryRepository.save(deleteLeaveQuery);
log.info("is deleteLeaveQuery null? " + (deleteLeaveQuery == null));
//leaveQueryRepository.delete(deleteLeaveQuery);
//leaveQueryRepository.delete(deleteLeaveQuery.getId());
leaveQueryRepository.deleteById(deleteLeaveQuery.getId());
accountService.sendLeaveRequestCanceledNotification(deleteLeaveQuery);
return ResponseEntity.ok().build();
}
When I use the regular (built-in) delete function of my leaveQueryRepository, I get no error, not during log INFO mode nor with log DEBUG mode on. However the object doesn't get deleted either. Its still in the database after the delete method was called. When I make a custom spring repository method called deleteById I get the following error:
org.springframework.dao.InvalidDataAccessApiUsageException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call; nested exception is javax.persistence.TransactionRequiredException: No EntityManager with actual transaction available for current thread - cannot reliably process 'remove' call
at
I have no idea what is causing this error. The jparepository looks like this:
#Repository
public interface LeaveQueryRepository extends JpaRepository<LeaveQuery, Long> {
//#Modifying
public void deleteById(long id);
}
The LeaveRequest object looks like this:
#Entity
#JsonIdentityInfo(
generator = ObjectIdGenerators.PropertyGenerator.class,
property = "id",
scope = LeaveQuery.class)
public class LeaveQuery implements Serializable {
#Id
#GeneratedValue
private Long id;
private Date startDate;
private Date endDate;
private String status = "Onbehandeld";
private String reason ="";
private int totalHours;
private String processedBy;
#ManyToOne(fetch = FetchType.EAGER) //, cascade = CascadeType.PERSIST
#JoinColumn(name = "FK_account", nullable = true)
private Account account;
public String getProcessedBy() {
return processedBy;
}
public void setProcessedBy(String processedBy) {
this.processedBy = processedBy;
}
public int getTotalHours() {
return totalHours;
}
public void setTotalHours(int totalHours) {
this.totalHours = totalHours;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Date getStartDate() {
return startDate;
}
public void setStartDate(Date startDate) {
this.startDate = startDate;
}
public Date getEndDate() {
return endDate;
}
public void setEndDate(Date endDate) {
this.endDate = endDate;
}
public String getReason() {
return reason;
}
public void setReason(String reason) {
this.reason = reason;
}
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
#Override
public String toString() {
return "LeaveQuery{" +
"id=" + id +
", startDate=" + startDate +
", endDate=" + endDate +
", denialReason='" + reason + '\'' +
'}';
}
}
It has a relation with an Account object which looks like this:
#Entity
//#JsonIgnoreProperties
//#JsonIdentityInfo(
// generator = ObjectIdGenerators.PropertyGenerator.class,
// property = "id",
// scope = Account.class)
public class Account implements Serializable {
#Id
#GeneratedValue
private Long id;
private String username;
private String password;
private String name;
private boolean admin;
private boolean enabled;
private int remainingStatutoryLeaveHours = 240;
private int remainingNonStatutoryLeaveHours = 60;
#JsonIgnore
#OneToMany(fetch = FetchType.EAGER, mappedBy = "account", cascade = CascadeType.ALL)
List<LeaveQuery> leaveQueryList;
//
#OneToMany(fetch = FetchType.LAZY, mappedBy = "account", cascade = CascadeType.ALL)
List<LaborPeriod> laborperiods = new ArrayList<>();
#OneToOne
private Person person;
#Enumerated
UserRole userRole = UserRole.USER;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public UserRole getUserRole() {
return userRole;
}
public void setUserRole(UserRole userRole) {
this.userRole = userRole;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public boolean isAdmin() {
return admin;
}
public void setAdmin(boolean admin) {
this.admin = admin;
}
public List<LaborPeriod> getLaborperiods() {
return laborperiods;
}
public void setLaborperiods(List<LaborPeriod> laborperiods) {
this.laborperiods = laborperiods;
}
public List<LeaveQuery> getLeaveQueryList() {
return leaveQueryList;
}
public void setLeaveQueryList(List<LeaveQuery> leaveQueryList) {
this.leaveQueryList = leaveQueryList;
}
public int getRemainingStatutoryLeaveHours() {
return remainingStatutoryLeaveHours;
}
public void setRemainingStatutoryLeaveHours(int remainingStatutoryLeaveHours) {
this.remainingStatutoryLeaveHours = remainingStatutoryLeaveHours;
}
public int getRemainingNonStatutoryLeaveHours() {
return remainingNonStatutoryLeaveHours;
}
public void setRemainingNonStatutoryLeaveHours(int remainingNonStatutoryLeaveHours) {
this.remainingNonStatutoryLeaveHours = remainingNonStatutoryLeaveHours;
}
#Override
public String toString() {
return "Account{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", name='" + name + '\'' +
", admin=" + admin +
", enabled=" + enabled +
", remainingStatutoryLeaveHours=" + remainingStatutoryLeaveHours +
", remainingNonStatutoryLeaveHours=" + remainingNonStatutoryLeaveHours +
", userRole=" + userRole +
'}';
}
}
Does anyone know what could be causing this error?
Any help would be appreciated.
All controller methods should be none transactional.
You should add one more layer between Controller and Repository (Service layer) and put #Transactional on Service class or put this annotation on your method in this Service class.
It should be Controller -> Service -> Repository
To let #Transactional work you should init TransactionalManager.
You can add something like this in your Persistence Configuration
#Bean
public JpaTransactionManager transactionManager() throws IOException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
return transactionManager;
}
Use orphanRemoval = true.
Try to update your Account class like so
#JsonIgnore
#OneToMany(fetch = FetchType.EAGER, mappedBy = "account", cascade = CascadeType.ALL, orphanRemoval = true)
List<LeaveQuery> leaveQueryList;
Also check out this question.
I am getting a mappedBy unknown error between the relatioships of the following two entities.
It is a one to one relationship and the owner of the relationship should be the Story entity. I can't see my mistake in this code.
Both entities have getters and setters.
This is the first entity:
#Entity
#Table(name = "story")
public class Story {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String name;
private String link;
#OneToOne(mappedBy = "story", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private DesignTechnique designTechnique;
public Story(){
}
public Story(String name, String link){
this.name = name;
this.link= link;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLink() {
return link;
}
public void setLink(String link) {
this.link= link;
}
public DesignTechnique getDesignTechnique() {
return designTechnique;
}
public void setDesignTechnique(DesignTechnique designTechnique) {
this.designTechnique = designTechnique;
}
#Override
public String toString() {
return "UserStory{" +
"id=" + id +
", name='" + name + '\'' +
", link='" + link+ '\'' +
", designTechnique='" + designTechnique + '\'' +
'}';
}
}
This is the second entity:
#Entity
#Table(name = "designTechnique")
public class DesignTechnique {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String technique;
#OneToOne
#JoinColumn(name = "story_ID")
private Story story;
public DesignTechnique(){
}
public DesignTechnique(String technique){
this.technique = technique;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTechnique() {
return technique;
}
public void setTechnique(String technique) {
this.technique = technique;
}
public Story getStory() {
return story;
}
public void setStory(Story story) {
this.story = story;
}
#Override
public String toString() {
return "TestdesignTechnique{" +
"id=" + id +
", technique='" + technique + '\'' +
", story='" + story+ '\'' +
'}';
}
}
EDIT
Stacktrace:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaAutoConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.AnnotationException: Unknown mappedBy in: com.clusters.Model.Story.designTechnique, referenced property unknown: com.clusters.Model.DesignTechnique.story
EDIT 2
I tried adding #PrimaryKeyJoinColumn instead of #JoinColumn in Design Entity, getting same error.
I have generated the getters and setters in both entities. So no typo's in these things.
It could be a hibernate bug !! see this :
https://hibernate.atlassian.net/browse/HHH-5695
Try to change the version of hibernate that you use.
How to prevent record insertion in #ManyToOne hibernate mapping. Their Parent table have no record. We tried to insert record without parent table primary key and still the record was inserted into child table
Domain class
Department Table(Parent)
#Table(name = "Department")
#Entity
public class Department {
#Id
#GenericGenerator(name = "g1", strategy = "increment")
#GeneratedValue(generator = "g1")
private int deptno;
private String deptname;
private String depthead;
public Department() {
System.out.println("Department:0-param constuctor");
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDeptname() {
return deptname;
}
public void setDeptname(String deptname) {
this.deptname = deptname;
}
public String getDepthead() {
return depthead;
}
public void setDepthead(String depthead) {
this.depthead = depthead;
}
#Override
public String toString() {
return "Department [deptno=" + deptno + ", deptname=" + deptname +
", depthead=" + depthead + "]";
}
}
Emplyee table(child)
#Table(name = "EmpDetails")
#Entity
public class EmpDetails {
#Id
private int eno;
private String ename;
private double salary;
#ManyToOne(targetEntity = Department.class,
cascade = CascadeType.ALL,
fetch = FetchType.LAZY)
#JoinColumn(name = "deptno", referencedColumnName = "deptno")
private Department dept;
public EmpDetails() {
System.out.println("EmpDetails:0-param constructor");
}
public int getEno() {
return eno;
}
public void setEno(int eno) {
this.eno = eno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
#Override
public String toString() {
return "EmpDetails [eno=" + eno + ", ename=" + ename + ", salary=" +
salary + "]";
}
}
DAO
#Override
public void addEmployeesWithDept() {
// get Session
Session ses = HibernateUtil.getSession();
// create Department (parent)
//Department dept=new Department();
//dept.setDeptname("Accounts");
//dept.setDepthead("Jhon");
//create Employees(childs)
EmpDetails emp1 = new EmpDetails();
emp1.setEno(107);
emp1.setEname("raja");
emp1.setSalary(9000);
EmpDetails emp2 = new EmpDetails();
emp2.setEno(108);
emp2.setEname("ravi");
emp2.setSalary(8000);
// set childs to parent
//emp1.setDept(); emp2.setDept();
//Save objs
Transaction tx = null;
try {
tx = ses.beginTransaction();
ses.save(emp1);
ses.save(emp2);
tx.commit();
System.out.println(" Employees(childs) and associated parent objs are saved");
} catch (Exception e) {
tx.rollback();
}
}
Main Method
public static void main(String[] args) {
// Get DAO
M2ODAO dao=M2ODAOFactory.getDAOInstance();
//perform persitence operations
dao.addEmployeesWithDept();
//Close objs
HibernateUtil.closeSession();
HibernateUtil.closeSessionFactory();
}//main
Please find the below classes.
Main change: http://docs.oracle.com/javaee/6/api/javax/persistence/JoinColumn.html#nullable()
Specify below line: nullable = false
#JoinColumn(name = "deptno", referencedColumnName = "deptno", nullable = false)
which makes deptNo column as not null. Additionally specify deptNo as not null column so it avoids saving empdetails without dept number.
Or you can use: #NotNull on that field.
#NotNull
private Deparment dept;
Your model classes
Domain class
Department Table(Parent)
#Table(name = "Department")
#Entity
public class Department {
#Id
#GenericGenerator(name = "g1", strategy = "increment")
#GeneratedValue(generator = "g1")
private int deptno;
private String deptname;
private String depthead;
#OneToMany(fetch = FetchType.LAZY, mappedBy = "department")
private List<EmpDetails> empDetails = new ArrayList<EmpDetails>();
public Department() {
System.out.println("Department:0-param constuctor");
}
public int getDeptno() {
return deptno;
}
public void setDeptno(int deptno) {
this.deptno = deptno;
}
public String getDeptname() {
return deptname;
}
public void setDeptname(String deptname) {
this.deptname = deptname;
}
public String getDepthead() {
return depthead;
}
public void setDepthead(String depthead) {
this.depthead = depthead;
}
public List<EmpDetails> getEmpDetails() {
return empDetails;
}
public void setEmpDetails(List<EmpDetails> empDetails) {
this.empDetails = empDetails;
}
#Transient
public void addRoomAndBed(EmpDetails empDetails) {
if (getEmpDetails() == null) {
setRoomAndBeds(new ArrayList<EmpDetails>());
}
getEmpDetails().add(empDetails);
}
#Override
public String toString() {
return "Department [deptno=" + deptno + ", deptname=" + deptname +
", depthead=" + depthead + "]";
}
}
Emplyee table(child)
#Table(name = "EmpDetails")
#Entity
public class EmpDetails {
#Id
private int eno;
private String ename;
private double salary;
#ManyToOne(targetEntity = Department.class,cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "deptno", referencedColumnName = "deptno", nullable = false)
private Department dept;
public EmpDetails() {
System.out.println("EmpDetails:0-param constructor");
}
public int getEno() {
return eno;
}
public void setEno(int eno) {
this.eno = eno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
#Override
public String toString() {
return "EmpDetails [eno=" + eno + ", ename=" + ename + ", salary=" +
salary + "]";
}
}