#ManyToMany Hibernate only update JoinTable - java

I have below entities and #ManyToMany mapping between the two.
#Entity
#Table(name = "user")
public class User implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 5340562707217344212L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
private String userName;
private String password;
private String firstName;
private String lastName;
private String emailId;
private Date createdDate;
private Byte status;
private Date lastModifiedDate;
#ManyToMany
#JoinTable(name = "user_products_mapper",
joinColumns = #JoinColumn(name = "user_id"),
inverseJoinColumns = #JoinColumn(name = "product_id")
)
private List<Products> products = new ArrayList<Products>();
public void addProducts(Products product){
this.products.add(product);
}
#Entity
#Table(name="products")
public class Products implements java.io.Serializable {
/**
*
*/
private static final long serialVersionUID = 1895580713896126954L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long productId;
private String productName;
private String description;
private double minBalance;
public Long getProductId() {
return this.productId;
}
public void setProductId(Long productId) {
this.productId = productId;
}
public String getProductName() {
return this.productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
My question is :
1)I already have these entities persisted. (User and Products)
2)User and Products are already exists in databasae and relation between them is #ManyToMany
3)I want to insert records ONLY IN JoinTable (user_products_mapper) since the rows are already present for User and Products.
4)One way to achieve this is to use UNIDIRECTIONAL mapping as I have above and just call
User.addProducts
5) Before doing this User and Products entities will be fetched like below :
User user = this.userDao.findOne(userId);
if(user == null){
//throw exception
}
Products product = this.productDao.findOne(productId);
6)Is there any way of doing this ?

When using Hibernate/JPA you do not control the actual queries being run, but you are not supposed to either.
What you would do to connect a user and a product would be something like:
#Transactional
public void addProductToUser(final Long userId, final Long productId) {
final User user = em.find(User.class, userId);
final Product product = em.find(Product.class, productId);
user.addProduct(product);
}
This will result in more queries than just inserting a row (since you will fetch both Product and User), but what you gain is simple and plain Java code. The cost of the extra queries in most cases is well within what is acceptable.

Related

can't set the relation using cascade type persist

hi i have the Account and Tweet classes as follows:
Account:
public class Account {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long accountId;
private String firstName;
private String lastName;
#Column(unique = true)
private String username;
private String password;
#OneToMany(mappedBy = "tweetAccount")
#Cascade(org.hibernate.annotations.CascadeType.PERSIST)
private List<Twit> accountTweet=new ArrayList<>();
public void addTweet(Twit tweet){
accountTweet.add(tweet);
}
}
}
tweet class
public class Tweet{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long tweetID;
#Column(length = 280)
private String text;
private int likes;
#ManyToOne
private Account tweetAccount;
}
i'm new to hibernate cascade types and trying to use CASCADETYPE.PERSIST
now suppose i have added an account and a tweet to the database before
and didn't set their relation.
when i run the following code from the repository,the relation is still not set.
am i missing something here?
public void addTweet(Account acc,Tweet tweet){
try(var session=sessionFactory.openSession()){
var trx=session.beginTransaction();
try{
acc.addTweet(tweet);
tweet.setTweetAccount(acc);
session.persist(acc);
session.flush();
trx.commit();
session.close();
}catch (Exception e){
trx.rollback();
}
}
}

Spring boot Hibernate batch insert

application.property:
jpa:
properties:
hibernate:
order_inserts: true
order_updates: true
batch_versioned_data: true
jdbc:
batch_size: 10
database: postgresql
hibernate:
ddl-auto: create-drop
logging:
level:
org:
hibernate:
SQL: DEBUG
Entity Product class:
public class Product {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String name;
private String description;
private LocalDateTime createdDate;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "product_id")
private List<ProductPrice> pricesList;
#ManyToOne
private User user;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "product_id")
private List<ProductLink> productLinks;
public Product(String name, String description, LocalDateTime createdDate, User user) {
this.name = name;
this.description = description;
this.createdDate = createdDate;
this.user = user;
}
}
Entity ProductLink class:
public class ProductLink {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String link;
#ManyToOne
private Product product;
public ProductLink(String link, Product product){
this.product = product;
this.link = link;
}
}
Entity ProductPrice class:
public class ProductPrice {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE)
private Long id;
private String storeName;
private String price;
private LocalDateTime updatedDate;
#ManyToOne
private Product product;
public ProductPrice(String storeName, String price, LocalDateTime updatedDate, Product product) {
this.product = product;
this.storeName = storeName;
this.price = price;
this.updatedDate = updatedDate;
}
}
Repository, same for the other
#Repository
public interface ProductLinkRepository extends JpaRepository<ProductLink, Long> {
}
I want to use Hibernate batch insert, but that doesn't Work, i only have multiple insert query in console (One insert for one ProductLink, ProductPrice)
Save method:
Product product = new Product(productDto.getName(), productDto.getDescription(), LocalDateTime.now(), user);
Product save = productRepository.save(product);
List<ProductLink> productLinks = new ArrayList<>();
List<ProductPrice> pricesList = new ArrayList<>();
for (ProductLinksDto productLink : productDto.getProductLinks()) {
if (!productLink.getLink().isEmpty()) {
URL url = new URL(productLink.getLink());
storeParser = new StoreParser(url);
productLinks.add(new ProductLink(productLink.getLink(), save));
pricesList.add(new ProductPrice(url.getHost(), storeParser.getPrice(), LocalDateTime.now(), save));
}
}
productPriceRepository.saveAll(pricesList);
productLinkRepository.saveAll(productLinks);

Hibernate One-to-Many Mapping Using Annotations; I'm trying to use foreign key association to save a user id in another table.

I'm not able to make this work.
I've also tried using a join table, but the result is the same. The user id that I need to appear in the table commissions doesn't.
Here's how I've created the entities.
For User and UserRole I've used a join table and it works.
I've tried to do the same for Commission but with no success (the joining table remained empty) so I tried like below with foreign key association.
User:
#Entity
#Table(name="USERS")
public class User implements Serializable{
/**
* serialVersionUID
*/
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#NotEmpty
#Column(name="USERNAME", unique=true, nullable=false)
private String username;
#NotEmpty
#Column(name="PASSWORD", nullable=false)
private String password;
#NotEmpty
#Column(name="FIRST_NAME", nullable=false)
private String firstName;
#NotEmpty
#Column(name="LAST_NAME", nullable=false)
private String lastName;
#NotEmpty
#Column(name="EMAIL", nullable=false)
private String email;
#NotEmpty
#ManyToMany(targetEntity=UserRole.class, fetch = FetchType.LAZY)
#JoinTable(name = "USERS_USER_ROLE",
joinColumns = { #JoinColumn(name = "USER_ID") },
inverseJoinColumns = { #JoinColumn(name = "USER_ROLE_ID") })
private Set<UserRole> userRoles = new HashSet<UserRole>();
#OneToMany(fetch = FetchType.LAZY, mappedBy="user")
private Set<Commission> commissions;
//getters and setters
Commission:
#Entity
#Table(name="COMMISSIONS")
public class Commission implements Serializable{
/**
* serialVersionUID
*/
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#NotEmpty
#Column(name="ORDER_NAME", unique=true, nullable=false)
private String orderName;
#NotEmpty
#Column(name="ORDER_DETAILS", unique=true, nullable=false)
private String orderDetails;
#Column(name="ORDER_STATUS", unique=true, nullable=false)
private String orderStatus;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "USER_ID", nullable = false)
private User user;
//getters and setters
UserRole:
#Entity
#Table(name="USER_ROLE")
public class UserRole implements Serializable{
/**
* serialVersionUID
*/
private static final long serialVersionUID = 1L;
#Id #GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="ROLE", length=15, unique=true, nullable=true)
private String role = UserRoleType.USER.getUserRoleType(); // getUserRoleType is defined in an enum with 'ADMIN', 'DBA', 'USER'
//getters and setters
In the UserDAO and CommissionDAO I've used SessionFactory to save the entities.
Extract from the abstract class which is extended by UserDAO and CommissionDAO.
#Autowired
private SessionFactory sessionFactory;
protected Session getSession(){
return sessionFactory.getCurrentSession();
}
public void persist(T entity) {
getSession().save(entity);
}
When I create a new user, everything works fine. The joining table has the correct id's added to it.
However...
When I add a new commission, the commission itself is added in the commissions table but the user_id remains null.
I'm new to hibernate and with this "project" of mine, I think I might've bit a more than I can chew.
Maybe the issue is somewhere else in the code and not here?
Anyhow, I'm in a bit of a bind and could use your expertise guys. Cheers!
Thanks Rossi Robinsion. That was it.
I missed to associate the user in my Commission controller.
This was before.
#RequestMapping(value = { "/newcommission" }, method = RequestMethod.POST)
public String saveCommission(#Valid Commission commission, BindingResult result, ModelMap model) {
if (result.hasErrors()) {
return "commissioncreation";
}
if(!commissionService.isUserOrderNameUnique(commission.getId(), commission.getOrderName())){
FieldError orderNameError =new FieldError("commission","orderName",
messageSource.getMessage("non.unique.orderName",
new String[]{commission.getOrderName()}, Locale.getDefault()));
result.addError(orderNameError);
return "commissioncreation";
}
commissionService.saveCommission(commission);
model.addAttribute("success", "Your commission was successfully created.");
model.addAttribute("loggedinuser", getPrincipal());
return "commissioncreationsuccess";
}
This is after.
#RequestMapping(value = { "/newcommission" }, method = RequestMethod.POST)
public String saveCommission(#Valid Commission commission, BindingResult result, ModelMap model) {
if (result.hasErrors()) {
return "commissioncreation";
}
if(!commissionService.isUserOrderNameUnique(commission.getId(), commission.getOrderName())){
FieldError orderNameError =new FieldError("commission","orderName",
messageSource.getMessage("non.unique.orderName",
new String[]{commission.getOrderName()}, Locale.getDefault()));
result.addError(orderNameError);
return "commissioncreation";
}
User user = userService.findByUsername(getPrincipal()); // associated the user properly.
commission.setUser(user);
commissionService.saveCommission(commission);
model.addAttribute("success", "Your commission was successfully created.");
model.addAttribute("loggedinuser", getPrincipal());
return "commissioncreationsuccess";
}
I don't know how I could miss this... sigh...
Thanks mate!

glassfish HTTP Status 500 - Internal Server Error with jpa one-to-many relationship

i am trying to create a bidirectional one to many relationship.
#Entity
#XmlRootElement
#NamedQueries({
#NamedQuery(name = Company.FIND_ALL, query = "select c from Company
})
public class Company {
public static final String FIND_ALL = "Company.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String email;
private String name;
private String phoneNumber;
#OneToMany(mappedBy = "company")
private List<Place> places;
private long millisSince1970;
private boolean deleted;
public Company() {
}
#PrePersist
public void addMillisPrePersist() {
millisSince1970 = Instant.now().getEpochSecond();
deleted = false;
}
#PreUpdate
public void addMillisPreUpdate() {
millisSince1970 = Instant.now().getEpochSecond();
}
}
Place class:
#Entity
#XmlRootElement
#NamedQueries({
#NamedQuery(name = Place.FIND_ALL, query = "select p from Place p")
})
public class Place {
public static final String FIND_ALL = "Place.findAll";
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private Type type;
private String email;
private String name;
private String city;
private String address;
private String phoneNumber;
private String latitude;
private String longitude;
private String workingHours;
#ManyToOne
#JoinColumn(name = "company_id", referencedColumnName = "id", nullable = false)
private Company company;
#OneToMany(mappedBy = "place")
private List<SpecialOffer> specialOffers;
#OneToMany(mappedBy = "place")
private List<Event> events;
private long millisSince1970;
private boolean deleted;
public Place() {
}
#PrePersist
public void addMillisPrePersist() {
millisSince1970 = Instant.now().getEpochSecond();
deleted = false;
}
#PreUpdate
public void addMillisPreUpdate() {
millisSince1970 = Instant.now().getEpochSecond();
}
}
And here is simple resource:
#GET
#Path("{companyId}")
#Produces({MediaType.APPLICATION_JSON})
public Company getCompany(#PathParam("companyId") int id) {
return entityManager.find(Company.class, id);
}
In my database i have Company and Place tables, in the Place table i have a foreign key column named company_id, so when i try to get some Company which has some corresponding Place glassfish returns http status 500 internal server error without any exception, and server logs are empty, thus i can not debug or understand the cause of this problem. If i try to get the company which doesn't have any places it returns it without any problem. So what am i doing wrong?
P.S. i think my question is similar to this one Glassfish: HTTP 500 Internal Server Error without any exception which unfortunately doesn't have any responses

Trouble with EntityManager Query

For some reason I don't get results when running this from method.
#SuppressWarnings("unchecked")
public Object[] getPointRaiting(Long id) {
EntityManager em = createEntityManager();
em.getTransaction().begin();
Query allPointsQuery = em
.createQuery("Select AVG(r.RATING) from Ratings r WHERE r.POINT_ID = :point");
allPointsQuery.setParameter("point", id);
Object[] rating = (Object[]) allPointsQuery.getSingleResult();
em.getTransaction().commit();
em.close();
closeEntityManager();
return rating;
}
SQL should be correct as it executes in HSQL db manager and returns the correct value. But java function stops running at query. It does'nt throw any errors just stops. I'm out of ideas, where should I look? (Other similiar methods with count and select all work correctly).
Using HSQLDB and Hibernate.
Found that the following error was thrown:
org.hibernate.QueryException: could not resolve property: RATING of: kaart.entities.Ratings [Select AVG(r.RATING) from kaart.entities.Ratings r WHERE r.POINT_ID = :point]
But this does not solve it for me as the RATING property is defined in table and in entity...
#Entity #Table(name = "RATINGS")
public class Ratings implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne
private Point point;
#ManyToOne
private User user;
#Column(name = "RATING")
private int rating;
private static final long serialVersionUID = 1L;
public Ratings() {
super();
}
public Ratings(Point point, User user, int rating) {
this.point = point;
this.user = user;
this.rating = rating;
}
/*all getters and setters here*/}
#Entity
#Table(name = "POINT")
public class Point implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#OneToMany(mappedBy = "point")
private List<Category> pointsByCategory;
#OneToMany(mappedBy = "point")
private List<Ratings> pointRatings;
#Column(name = "NAME")
private String name;
#Column(name = "LOCATION")
private String location;
#Column(name = "DESCRIPTION")
private String description;
#Column(name = "LINK")
private String link;
#ManyToOne
private User user;
private static final long serialVersionUID = 1L;
public Point() {
super();
}
public Point(String name, String location, String description, String link, User user) {
this.name = name;
this.location = location;
this.description = description;
this.link = link;
this.user = user;
} /* getters and setters*/
You can only pass JP-QL inside em.createQuery().
But seems you are using native SQL with values like r.RATING, r.POINT_ID, which may not be in the Java entity. Replace it with equivalent java entity variable, could be pointId
em.createQuery("Select AVG(r.RATING) from Ratings r WHERE r.POINT_ID = :point");
If you want to use native sql, you can use em.createNativeQuery().
Most likely this problem is caused by caps-locked property names: RATING, POINT_ID.
Try replacing them with the ones that you use in Ratings class, probably:
Select AVG(r.rating) from Ratings r WHERE r.point.id = :point_id

Categories