I am new to Hibernate. I have two tables Team(parent) and Product(child) with TEAM_ID column as a relationship, each team will have multiple products and each product will have single team. I have created entity classes with #OneToMany mapping in Team class and #ManyToOne in Product class.
I need to coverup below scenarios,
To save both product and team when team is new
Save only product if the team is already available
When i am trying to save product it tries to save team again throws constraint error.
Please help.
Team:
#Entity
#Table(name = "TEAM")
public class Team implements Serializable{
private static final long serialVersionUID = 5819170381583611288L;
#Id
#SequenceGenerator(name="teamIdSeq",sequenceName="team_id_seq",allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="teamIdSeq")
#Column(name="TEAM_ID", updatable = false, nullable = false, unique = true)
private int teamId;
#Column(name="NAME", nullable = false, unique = true)
private String teamName;
#Column(name="DESCRIPTION", nullable = false)
private String teamDesc;
#Column(name="CONTACTS", nullable = false)
private String contacts;
#Column(name="APPROVER_NAME", nullable = false)
private String approverName;
#Column(name="APPROVAL_STATUS", nullable = false)
private int approvalStatus;
#Temporal(TemporalType.DATE)
#Column(name="CREATED_ON", nullable = false)
private Date createdOn;
#Column(name="CREATED_BY", nullable = false)
private String createdBy;
#Temporal(TemporalType.DATE)
#Column(name="MODIFIED_ON", nullable = false)
private Date modifiedOn;
#Column(name="MODIFIED_BY", nullable = false)
private String modifiedBy;
#OneToMany(fetch = FetchType.LAZY, mappedBy="team", cascade = CascadeType.ALL)
private Set<Product> products;
//setters and getters
}
Product:
#Entity
#Table(name = "PRODUCT", uniqueConstraints = {#UniqueConstraint(columnNames = {"PRODUCT_ID", "TEAM_ID"})})
public class Product implements Serializable{
private static final long serialVersionUID = 5819170381583611288L;
#Id
#SequenceGenerator(name="productIdSeq", sequenceName="product_id_seq",allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="productIdSeq")
#Column(name="PRODUCT_ID", updatable = false, nullable = false)
private int productId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TEAM_ID")
private Team team;
#Column(name="NAME", nullable = false, unique = true)
private String productName;
#Column(name="DESCRIPTION", nullable = true)
private String productDesc;
#Column(name="APPROVER_NAME", nullable = false)
private String approverName;
#Column(name="APPROVAL_STATUS", nullable = false)
private int approvalStatus;
#Temporal(TemporalType.DATE)
#Column(name="CREATED_ON", nullable = false)
private Date createdOn;
#Column(name="CREATED_BY", nullable = false)
private String createdBy;
#Temporal(TemporalType.DATE)
#Column(name="MODIFIED_ON", nullable = false)
private Date modifiedOn;
#Column(name="MODIFIED_BY", nullable = false)
private String modifiedBy;
#OneToMany(fetch = FetchType.LAZY, mappedBy="product")
private Set<Form> forms;
//setters and getters
}
DAO:
#Repository
#EnableTransactionManagement
public class KMDBDAOImpl implements KMDBDAO {
#Autowired
private SessionFactory sessionFactory;
public void addTeam(Team team) {
Product product = new Product(team, "BMA" + Math.random(), "UI Tool", "test",
1, new Date(), "test", new Date(), "test");
Set<Product> products = new HashSet<Product>();
products.add(product);
team.setProducts(products);
if(getTeam(team.getTeamName()) != null) {
product.setTeam(getTeam(team.getTeamName()));
sessionFactory.getCurrentSession().saveOrUpdate(product);
} else {
sessionFactory.getCurrentSession().saveOrUpdate(team);
}
}
public Team getTeam(String teamName) {
Query query = sessionFactory.getCurrentSession().createQuery("from Team where teamName = :name");
query.setString("name", "teamName");
return (query.list().size() > 0 ? (Team) query.list().get(0) : null);
}
The only time that you should set Product list on Team is when Team is a new entity. So:
Set<Product> products = new HashSet<Product>();
products.add(product);
if(getTeam(team.getTeamName()) != null) {
product.setTeam(getTeam(team.getTeamName()));
sessionFactory.getCurrentSession().saveOrUpdate(product);
} else {
team.setProducts(products);
sessionFactory.getCurrentSession().saveOrUpdate(team);
}
i give you some example code for one to many relationship please go through it and let me kn if some problem .... i have 2 tables 1.product 2.sku my condition is , one product have many sku's ...
Product.java
#LazyCollection(LazyCollectionOption.FALSE)
#ElementCollection(targetClass=Product.class)
#OneToMany(mappedBy="product" , cascade=CascadeType.MERGE)
private List<Sku> listSkuOrders = new ArrayList<>();
Sku.java
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = PRODUCT_ID , nullable = false)
private Product product;
Related
i want to join 4 tables with hibernate. i write following code for fetch course name , teacher detail of course and schedules of course by student id:
my student entity is:
#Entity
#Table(name = "students", schema = "public")
public class Student {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "students_id_seq")
#SequenceGenerator(name = "students_id_seq", sequenceName = "students_id_seq", allocationSize = 1)
#Column(name = "id", nullable = false, unique = true)
private int id;
#Column(name = "name", nullable = false, length = 60)
private String name;
#Column(name = "code_melli", nullable = false, length = 10)
private String codeMelli;
#Column(name = "register_date", nullable = false)
private Date registerDate;
#Column(name = "mobile", length = 11)
private String mobile;
#Column(name = "phone", length = 15)
private String phone;
#Column(name = "email", length = 50)
private String email;
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "student_id", referencedColumnName = "id", insertable = false, updatable = false)
private List<Attend> attends;
my Attend Entity that determines the attendance of the student in the course and his score is:
#Entity
#Table(name = "attend", schema = "public")
public class Attend {
#EmbeddedId
AttendKey attendKey;
#Column(name = "score")
private int score;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "student_id", referencedColumnName = "id", insertable = false, updatable = false)
private Student student;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "course_id", referencedColumnName = "id", insertable = false, updatable = false)
private Course course;
course entity that map course detail is:
#Entity
#Table(name = "courses", schema = "public")
public class Course {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "courses_id_seq")
#SequenceGenerator(name = "courses_id_seq", sequenceName = "courses_id_seq", allocationSize = 1)
#Column(name = "id", nullable = false, unique = true)
private int id;
#Column(name = "code")
private int code;
#Enumerated(EnumType.ORDINAL)
#Column(name = "cluster", nullable = false)
private ClusterType cluster;
#Column(name = "name", nullable = false, length = 40)
private String name;
#OneToOne
#JoinColumn(name = "teacher_id")
private Teacher teacher;
#Column(name = "students", nullable = false)
private int students;
#Column(name = "salary", nullable = false)
private int salary;
#Column(name = "tuition", nullable = false)
private int tuition;
#Column(name = "start_date")
private Date startDate;
#Column(name = "end_date")
private Date endDate;
#JsonIgnore
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "course_id", referencedColumnName = "id", insertable = false, updatable = false)
private List<Schedule> scheduleList;
and schedule entity that saves the start and end time of the class in one day of the week is:
#Entity
#Table(name = "schedule", schema = "public")
#IdClass(ScheduleKey.class)
public class Schedule {
#Id
#Column(name = "course_id")
private int course_id;
#Id
#Column(name = "day")
#Enumerated(EnumType.ORDINAL)
private Day day;
#Column(name = "start", nullable = false)
private Time start;
#Column(name = "endt", nullable = false)
private Time endt;
how can i join these tables with hibernate criteria API and fetch course schedule of specific student.
SQL query for fetch data:
select
*
from
students
inner join
attend
on students.id=attend.student_id
inner join
courses
on attend.course_id=course.id
left outer join
schedule_
on course.id=schedule.course_id
left outer join
public.teachers
on course.teacher_id=teacher.id
where
students.id=102552
i use
public Student getStudentDetail(int studentId) {
Criteria criteria = createEntityCriteria();
criteria.add(Restrictions.eq("id", studentId));
criteria.setFetchMode("attends", FetchMode.JOIN);
Criteria attendCriteria = criteria.createCriteria("attends", "attend")
.setFetchMode("course", FetchMode.JOIN);
Criteria courseCriteria = attendCriteria.createCriteria("course", "course")
.setFetchMode("scheduleList", FetchMode.JOIN);
Criteria scheduleCriteria = courseCriteria.createCriteria("scheduleList", "schedule");
return (Student) scheduleCriteria.uniqueResult();
}
I did googled a lot, still dont find any solution hence posting a question here..
I am developing Many-To-Many relationship example using lombok. I just want to create argument constructor for only two fields out of four. How we can do that ?
#Data
#Entity
#Table(name = "stock")
public class Stock implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "STOCK_ID", unique = true, nullable = false)
private Integer stockId;
#Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
private String stockCode;
#Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
private String stockName;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "stock_category", joinColumns = {
#JoinColumn(name = "STOCK_ID", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "CATEGORY_ID", nullable = false, updatable = false)})
private Set<Category> categories = new HashSet<Category>(0);
}
Category
#Data
#RequiredArgsConstructor(staticName = "of")
#Entity
#Table(name = "category")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CATEGORY_ID", unique = true, nullable = false)
private Integer categoryId;
#Column(name = "NAME", nullable = false, length = 10)
#NonNull
private String name;
#Column(name = "[DESC]", nullable = false)
#NonNull
private String desc;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "categories")
private Set<Stock> stocks = new HashSet<Stock>(0);
}
App.java
Why cant I set the limitted field constructor
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("7052");
stock.setStockName("PADINI");
Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
Category category2 = new Category("INVESTMENT", "INVESTMENT COMPANY");
Set<Category> categories = new HashSet<Category>();
categories.add(category1);
categories.add(category2);
stock.setCategories(categories);
session.save(stock);
session.getTransaction().commit();
System.out.println("Done");
}
}
The reason is that
If staticName set, the generated constructor will be private, and an additional
static 'constructor' is generated with the same argument list that
wraps the real constructor.
Please, don't forget about #NoArgsConstructor because Hibernate needs it.
I'm using JPA with QueryDSL, In that scenario, I'm going to use JpaQuery Projections for fetching the only required data from DB. In my entity there is one OneToMany(List) Mapping But I'm not able to do projection on OneToMany mapping fields ie List. Please, anyone, tell me how we can get List by using projections in OneToMany mapping.
My entity class:-
public class Brand {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = COLUMN_BRAND_ID)
private int brandId;
#Column(name = COLUMN_BRAND_NAME, columnDefinition = "VARCHAR(255)", nullable = false, unique = true)
private String brandName;
#OneToOne(cascade = CascadeType.MERGE )
#JoinColumn(name = BRAND_LOGO_SMALL_FOREIGN_KEY)
private File brandLogoSmall;
#OneToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = BRAND_LOGO_LARGE_FOREIGN_KEY)
private File brandLogoLarge;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = COLUMN_CONTACT_PERSONS, nullable = true)
private List<BrandContactPerson> contactPersons;
#Column(name = COLUMN_OTHER_DETAILS, columnDefinition = "VARCHAR(255)", nullable = true)
private String otherDetails;
#Column(name = COLUMN_BRAND_STATUS, columnDefinition = "TINYINT(1) DEFAULT 1", nullable = false)
private int status;
#Column(name = BRAND_ADDED_BY_FOREIGN_KEY, nullable = true)
private int createdBy;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = COLUMN_BRAND_ADDED_ON, columnDefinition = "DATETIME", nullable = false)
private Date createdDate;
#Column(name = BRAND_MODIFIED_BY_FOREIGN_KEY, nullable = true)
private int updatedBy;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = COLUMN_BRAND_MODIFIED_ON, columnDefinition = "DATETIME", nullable = true)
private Date updatedDate;
#OneToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = COLUMN_CLASSIFICATION)
private Classification classification;
//Setter Getter
}
Service Impl Class
#Repository
public class BrandCustomRepositoryImpl implements BrandCustomRepository {
#Autowired
private BrandQueryDslRepository brandQueryDslRepository;
#Autowired
private EntityManager em;
#Override
public List<Brand> search(BrandSearchModel searchQuery) {
JPAQuery<Contract> query = new JPAQuery<>(em);
QBrand qBrand = QBrand.brand;
BooleanBuilder builder = new BooleanBuilder();
if (searchQuery.getPageNo() == null) {
searchQuery.setPageNo(0);
}
if (searchQuery.getPageSize() == null) {
searchQuery.setPageSize(UserSearchModel.DEFAULT_PAGE_SIZE);
}
prepareBrandSearchBuilder(builder, qBrand, searchQuery);
builder.and(qBrand.status.eq(Constant.ACTIVE));
List<Brand> brand1 = query.from(qBrand.brand).where(builder).offset(0).limit(20)
.select(Projections.bean(Brand.class, qBrand.brandName,qBrand.contactPersons))
.fetch();
return brand1;
}
This is the above example. Thanks in advance.
I have a question about "annotations" in hibernate.
I have a BaseEntity class and another class like state.java who extend
#JsonIgnoreProperties({ "hibernateLazyInitializer", "handler", "createdBy", "updatedBy" })
#MappedSuperclass
public abstract class BaseEntity<T> implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private T id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CreatedBy", nullable = true)
private User createdBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "UpdatedBy", nullable = true)
private User updatedBy;
#Column(name = "createdDate", nullable = true, updatable = false)
private Date createdDate;
#Column(name = "UpdatedDate", nullable = true)
private Date updatedDate;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "subsite", nullable = true)
private Subsite subsite;
#Column(name = "ip", nullable = true)
private String ip;
#Entity
#Table(name="State")
public class State extends BaseEntity<Long> {
#Column(name = "state", nullable = true)
private String state;
#Column(name = "city", nullable = true)
private String city;
when program creat my tables in DataBase my table'design build like this:
How can I create a table so that the BaseEntity'fields place after state'fields in my Table
I'm developing a project which uses BackboneJS in front-end and Java - Spring Core in back-end. I have a problem about mapping entity(domain) objects to DTO objects. I am getting an error message like that :
org.apache.cxf.interceptor.Fault: Infinite recursion (StackOverflowError) (through reference chain: com.countdown.dto.CategoryDTO["countdownList"]->java.util.ArrayList[0]->com.countdown.dto.CountdownDTO["category"]->.......
User.java
#Entity
#Table(name = "Users")
public class User implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "USER_ID", nullable = false)
private int id;
#Column(name = "EMAIL", nullable = false, unique = true)
private String email;
#Column(name = "NAME_SURNAME", nullable = false)
private String nameSurname;
#Column(name = "PASSWORD", nullable = false)
private String password;
#Column(name = "USERNAME", nullable = false, unique = true)
private String username;
#Column(name = "REGISTER_DATE", nullable = false)
private Date registerDate;
#ManyToOne
#JoinColumn(name = "ROLE_ID")
private Role role;
#OneToMany(mappedBy = "createUser")
private List<Countdown> createCountdownList = new ArrayList<Countdown>();
#OneToMany(mappedBy = "updateUser")
private List<Countdown> updateCountdownList = new ArrayList<Countdown>();
#ManyToMany
#JoinTable(name = "FOLLOWINGS",
joinColumns = #JoinColumn(name = "USER_ID"),
inverseJoinColumns = #JoinColumn(name = "COUNTDOWN_ID"))
private List<Countdown> followings = new ArrayList<Countdown>();
//Getters and setters..
}
Role.java
#Entity
public class Role implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "ROLE_ID")
private int id;
#Column(name = "ROLE_NAME", nullable = false)
private String roleName;
#OneToMany(mappedBy = "role",fetch = FetchType.LAZY)
List<User> userList = new ArrayList<User>();
}
Countdown.java
#Entity
#Table(name = "COUNTDOWN")
public class Countdown implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "COUNTDOWN_ID")
private int id;
#Column(name = "COUNTDOWN_NAME", nullable = false)
private String countdownName;
#Column(name = "COUNTDOWN_DATE", nullable = false)
private Date countdownDate;
#Column(columnDefinition = "varchar(5000)")
private String countdownDescription;
#JoinColumn(name = "CATEGORY_ID", nullable = false)
#ManyToOne
private Category category;
#JoinColumn(name = "CREATE_USER", nullable = false)
#ManyToOne
private User createUser;
#Column(name = "CREATE_DATE", nullable = false)
private Date createDate;
#JoinColumn(name = "UPDATE_USER", nullable = false)
#ManyToOne
private User updateUser;
#Column(name = "UPDATE_DATE", nullable = false)
private Date updateDate;
#Column(name = "CREATE_USER_IP", nullable = false)
private int createIP;
#ManyToMany
private List<User> followers = new ArrayList<User>();
}
Category.java
#Entity
#Table(name="CATEGORY")
public class Category implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="CATEGORY_ID")
private int id;
#Column(name = "CATEGORY_NAME" , nullable = false)
private String categoryName;
#OneToMany(mappedBy = "category")
private List<Countdown> countdownList = new ArrayList<Countdown>();
}
Business Logic : CategoryServiceImpl.java
I'm getting error in forEach loop.
#Transactional(readOnly = true)
public List<CategoryDTO> getAllCategories() {
List<Category> categoryList;
List<CategoryDTO> categoryDTOList = new ArrayList<CategoryDTO>();
logger.debug("getAllCategories called");
try {
categoryList = categoryDAO.findAll();
for(Category category : categoryList){
categoryDTOList.add(mapper.map(category,CategoryDTO.class));
}
}catch (NoResultException e){
logger.error("getAllCategories method : No Category wasn't found");
logger.warn(e,e);
}catch (Exception e){
logger.error("getAllCategories method : Categories wasn't found");
logger.warn(e,e);
}
return categoryDTOList;
}
Also Do I have to use DTO object in Presentation Layer? Can I use entity objects in presentation layer instead of DTO objects?
How can I solve this problem? Sorry my bad english. Thank you!
Please Try :
#Transactional(readOnly = true)
public List<CategoryDTO> getAllCategories() {
List<Category> categoryList;
List<CategoryDTO> categoryDTOList = new ArrayList<CategoryDTO>();
logger.debug("getAllCategories called");
try {
categoryList = categoryDAO.findAll();
for(Category category : categoryList){
if(category.getCountdownList() != null && !category.getCountdownList().isEmpty()){
for(Countdown countdown : category.getCountdownList()){
countdown.setCategory(null);
}
}
categoryDTOList.add(mapper.map(category,CategoryDTO.class));
}
}catch (NoResultException e){
logger.error("getAllCategories method : Hata: No Category wasn't found");
logger.warn(e,e);
}catch (Exception e){
logger.error("getAllCategories method : Hata: Categories wasn't found");
logger.warn(e,e);
}
return categoryDTOList;
}
For those who are struggling with infinite recursion issue in Dozer.
I use mapId to define a leaf object and stops the recursion.
Let assume we have two entities Course and Teacher, which contains a Many-to-Many relationship, and we want to convert the following object graph to one represented by CourseDTO and TeacherDto. And we hope Dozer stops at the 3rd level.
Teacher 1 ---> m Course 1 ---> m Teacher ---> ...
1st level 2nd level 3rd level
We can first define the following definition for Teacher to TeacherDTO conversion.
This first mapping is used for the root Teacher entity.
Include any other fields you need in the mapping.
mapping(Teacher.class, TeacherDTO.class,
TypeMappingOptions.oneWay()
, mapNull(false)
).fields("courses", "courses");
The following mapping will prevent Dozer from going further to map the contained Course. We define a mapId teacherLeaf for it.
Exclude the fields that cause the infinite recursion. (In my example, it's courses)
Include any other fields you need in the mapping.
mapping(Teacher.class, TeacherDTO.class,
TypeMappingOptions.oneWay(), TypeMappingOptions.mapId("teacherLeaf")
, mapNull(false)
).exclude("courses");
The last one is the mapping rule for Course to courseDTO. The key is that we tell the mapper to use the teacherLeaf mapping rule defined previously to convert the contained Teachers.
mapping(Course.class, CourseDTO.class,
TypeMappingOptions.oneWay()
, mapNull(false)
).fields("teachers", "teachers", useMapId("teacherLeaf"));
Hope this helps!
I use Dozer 6.1.0.