I have a criteria that looks like this:
public List<role> searchByFormStatus(boolean status) {
Criteria criteria = this.getSession().createCriteria(this.getPersistentClass());
List<role> result = (List<role>) criteria
.setFetchMode("role", FetchMode.JOIN)
.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
.createAlias("formApprovals", "f")
.add(Restrictions. eq("f.latestApproval", true))
.list();
return result;
}
At first look it should be working, but no matter if I send true or false value in the parameter, the result will always be
[{
"roleIsActive": true,
"roleName": "role1",
"roleNotes": "note",
"formApprovals": [
{
"approvalNotes": "good",
"approvedDate": 1449900000000,
"fkapprovedBy": 1,
"idformApproval": 1,
"latestApproval": true
},
{
"approvalNotes": "bad",
"approvedDate": 1449900000000,
"fkapprovedBy": 1,
"idformApproval": 2,
"latestApproval": false
}
}]
As you can see, the "formApprovals" brings all registers in the database, even if I create the restriction for the latestApproval property
The property declaration in the parent object (role) is:
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="role")
public Set<FormApproval> getFormApprovals() {
return this.formApprovals;
}
public void setFormApprovals(Set<FormApproval> formApprovals) {
this.formApprovals = formApprovals;
}
Checking the console, I can see that the where clause is being generated properly by hibernate, however, I can see that after that there are other queries, is it possible that those queries (I have no idea why are they there) are overwriting my criteria?
Any ideas?
EDIT
FormApproval Class
#Entity
#Table(name="FormApproval"
,catalog="catalog"
)
public class FormApproval implements java.io.Serializable {
private static final long serialVersionUID = 8L;
private int idformApproval;
private role role;
private Integer fkapprovedBy;
private Date approvedDate;
private String approvalNotes;
private boolean latestApproval;
public FormApproval() {
}
public FormApproval(int idformApproval, role role) {
this.idformApproval = idformApproval;
this.role = role;
}
public FormApproval(int idformApproval, role role, Integer fkapprovedBy, Date approvedDate, String approvalNotes, boolean latestApproval) {
this.idformApproval = idformApproval;
this.role = role;
this.fkapprovedBy = fkapprovedBy;
this.approvedDate = approvedDate;
this.approvalNotes = approvalNotes;
this.latestApproval = latestApproval;
}
#Id #GeneratedValue(strategy = IDENTITY)
#Column(name="IDFormApproval", unique=true, nullable=false)
public int getIdformApproval() {
return this.idformApproval;
}
public void setIdformApproval(int idformApproval) {
this.idformApproval = idformApproval;
}
#JsonIgnore
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="FKRole", nullable=false)
public role getrole() {
return this.role;
}
public void setrole(role role) {
this.role = role;
}
#Column(name="LatestApproval")
public boolean getLatestApproval() {
return this.latestApproval;
}
public void setLatestApproval(boolean latestApproval) {
this.latestApproval = latestApproval;
}
#Column(name="FKApprovedBy")
public Integer getFkapprovedBy() {
return this.fkapprovedBy;
}
public void setFkapprovedBy(Integer fkapprovedBy) {
this.fkapprovedBy = fkapprovedBy;
}
#Temporal(TemporalType.DATE)
#Column(name="ApprovedDate", length=10)
public Date getApprovedDate() {
return this.approvedDate;
}
public void setApprovedDate(Date approvedDate) {
this.approvedDate = approvedDate;
}
#Column(name="ApprovalNotes")
public String getApprovalNotes() {
return this.approvalNotes;
}
public void setApprovalNotes(String approvalNotes) {
this.approvalNotes = approvalNotes;
}
}
Role Class
#Entity
#Table(name="Role"
,catalog="catalog"
)
public class Role implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private int idRole;
private WorkType workType;
private String roleName;
private String roleNotes;
private boolean roleIsActive;
private Set<FormApproval> formApprovals = new HashSet<FormApproval>(0);
private Set<Topicrole> topicRoles = new HashSet<TopicRole>(0);
private Set<FormFeedBack> formFeedBacks = new HashSet<FormFeedBack>(0);
private Set<UserRole> userRoles = new HashSet<UserRrole>(0);
private Set<Interview> interviews = new HashSet<Interview>(0);
public Role() {
}
public Role(int idRole, WorkType workType, String roleName, boolean roleIsActive) {
this.idRole = idRole;
this.workType = workType;
this.RoleName = RoleName;
this.roleIsActive = roleIsActive;
}
public Role(int idRole, WorkType workType, String roleName, String roleNotes, boolean roleIsActive, Set<FormApproval> formApprovals, Set<TopicRole> topicRoles, Set<FormFeedBack> formFeedBacks, Set<UserRole> userRoles, Set<Interview> interviews) {
this.idRole = idRole;
this.workType = workType;
this.RoleName = RoleName;
this.roleNotes = roleNotes;
this.roleIsActive = roleIsActive;
this.formApprovals = formApprovals;
this.topicRoles = topicRoles;
this.formFeedBacks = formFeedBacks;
this.userRoles = userRoles;
this.interviews = interviews;
}
#Id #GeneratedValue(strategy = IDENTITY)
#Column(name="IDRole", unique=true, nullable=false)
public int getIdrole() {
return this.idRole;
}
public void setIdrole(int idRole) {
this.idRole = idRole;
}
#ManyToOne(fetch=FetchType.EAGER)
#JoinColumn(name="FKWorkType", nullable=false)
public WorkType getWorkType() {
return this.workType;
}
public void setWorkType(WorkType workType) {
this.workType = workType;
}
#Column(name="RoleName", nullable=false)
public String getRoleName() {
return this.roleName;
}
public void setRoleName(String roleName) {
this.roleName = roleName;
}
#Column(name="RoleNotes")
public String getRoleNotes() {
return this.roleNotes;
}
public void setRoleNotes(String roleNotes) {
this.roleNotes = roleNotes;
}
#Column(name="RoleIsActive", nullable=false)
public boolean isRoleIsActive() {
return this.roleIsActive;
}
public void setRoleIsActive(boolean roleIsActive) {
this.roleIsActive = roleIsActive;
}
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="role")
public Set<FormApproval> getFormApprovals() {
return this.formApprovals;
}
public void setFormApprovals(Set<FormApproval> formApprovals) {
this.formApprovals = formApprovals;
}
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="role")
public Set<TopicRole> getTopicRoles() {
return this.topicRoles;
}
public void setTopicRoles(Set<TopicRole> topicRoles) {
this.topicRoles = topicRoles;
}
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="role")
#JsonManagedReference
public Set<FormFeedBack> getFormFeedBacks() {
return this.formFeedBacks;
}
public void setFormFeedBacks(Set<FormFeedBack> formFeedBacks) {
this.formFeedBacks = formFeedBacks;
}
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="role")
public Set<UserRole> getUserRoles() {
return this.userRoles;
}
public void setUserRoles(Set<UserRole> userRoles) {
this.userRoles = userRoles;
}
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="acnrole")
public Set<Interview> getInterviews() {
return this.interviews;
}
public void setInterviews(Set<Interview> interviews) {
this.interviews = interviews;
}
}
You might try using the restriction as part of ON clause on top of the association.
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="role")
#Where(clause=" latestApproval='true' ")
public Set<FormApproval> getFormApprovals() {
return this.formApprovals;
}
Also you can eliminate setting FetchMode.JOIN fetch by pointing to the association path using the method org.hibernate.Criteria.createAlias(String associationPath, String alias, JoinType joinType)
public List<role> searchByFormStatus(boolean status) {
Criteria criteria = this.getSession().createCriteria(Role.class, "role")
.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY)
.createAlias("role.formApprovals", "formApprovals", JoinType.LEFT_OUTER_JOIN);
return criteria.list();
}
Update:
For older versions of hibernate, use the other method below. Where joinType value would be 1 for LEFT_OUTER_JOIN and join clause can be passed as the 4th argument.
public Criteria createAlias(String associationPath, String alias, int joinType, Criterion withClause) throws HibernateException;
Fixed using
.createCriteria("formApprovals","f",1,Restrictions.eq("f.latestApproval", status))
1 forces a Left outer join in the query
With EAGER fetch types, a nested criteria should work for this case:
public List<role> searchByFormStatus(boolean status) {
Criteria criteria = this.getSession().createCriteria(this.getPersistentClass());
List<role> result = (List<role>) criteria
.createCriteria("formApprovals")
.add(Restrictions.eq("latestApproval", true))
.list();
return result;
}
Related
I'm using spring boot to construct a database using AWS RDS as well. I want to track down how many stars a user gives to different products. I learnt to go around the many-to-many relationship by creating a table connecting two one-to-many other tables. For this reason, I have created the following tables:
When a user rates a product, an api is called through the put command in order to track down which user(uid) rates which product(pid). When the product(pid) is not rated by anyone, a rate_item is created that contains the pid and also the uid. However, when another user (with a different uid) rates the same product (same pid), the rate_item is updated, which is a problem becausse supposedly, a new row containing the same pid and a different uid should be created, as seen in the following (user with "uid 1" has already rated the same product and when user with "uid 2" rates the same product, the entity gets updated, but not like a new entity is created):
ProductEntity:
#Entity
#Table(name = "product")
public class ProductEntity {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name = "pid",nullable = false)
private Integer pid;
#Column(name = "name", nullable = false)
private String name;
#Column(name="theme", nullable = false)
private String theme;
#Column(name="color", nullable = false)
private String color;
#Column(name="sizeZero", nullable = true)
private String sizeZero;
#Column(name="sizeOne", nullable = true)
private String sizeOne;
#Column(name="sizeTwo", nullable = true)
private String sizeTwo;
#Column(name="sizeThree", nullable = true)
private String sizeThree;
#Column(name="description",nullable = false)
private String description;
#Column(name = "image_url", nullable = false)
private String imageUrl;
#Column(name = "price",nullable = false)
private BigDecimal price;
#Column(name = "stock",nullable = false)
private Integer stock;
public ProductEntity(CreateProductData createProductData) {
this.pid = createProductData.getPid();
this.name = createProductData.getName();
this.theme =createProductData.getTheme();
this.color=createProductData.getColor();
this.sizeZero=createProductData.getSizeZero();
this.sizeOne =createProductData.getSizeOne();
this.sizeTwo =createProductData.getSizeTwo();
this.sizeThree =createProductData.getSizeThree();
this.description =createProductData.getDescription();
this.imageUrl = createProductData.getImageUrl();
this.price = createProductData.getPrice();
this.stock = createProductData.getStock();
}
public ProductEntity(){
}
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTheme() {
return theme;
}
public void setTheme(String productType) {
this.theme = productType;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public String getSizeZero() {
return sizeZero;
}
public void setSizeZero(String sizeZero) {
this.sizeZero = sizeZero;
}
public String getSizeOne() {
return sizeOne;
}
public void setSizeOne(String smallSize) {
this.sizeOne = smallSize;
}
public String getSizeTwo() {
return sizeTwo;
}
public void setSizeTwo(String mediumSize) {
this.sizeTwo = mediumSize;
}
public String getSizeThree() {
return sizeThree;
}
public void setSizeThree(String largeSize) {
this.sizeThree = largeSize;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public Integer getStock() {
return stock;
}
public void setStock(Integer stock) {
this.stock = stock;
}
}
UserEntity:
#Entity
#Table(name="User")
public class UserEntity {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="uid",nullable = false)
private Integer uid;
#Column(name="username", nullable = false)
private String username;
#Column(name="email", nullable = false, unique = true)
private String email;
#Column(name="password", nullable = false)
private String password;
#Column(name = "firebase_uid", nullable = false)
private String firebaseUid;
#Column(name= "emailVerified", nullable = false,columnDefinition = "boolean default false")
private Boolean emailVerified=false;
#Column(name="subscribed", nullable = false)
private Boolean subscribed;
public UserEntity(UserEntity tempUserEntity){
this.uid=tempUserEntity.getUid();
this.firebaseUid=tempUserEntity.getFirebaseUid();
this.email=tempUserEntity.getEmail();
}
public UserEntity(CreateFirebaseUserData createFirebaseUserData){
this.username=createFirebaseUserData.getUsername();
this.email=createFirebaseUserData.getEmail();
this.password=createFirebaseUserData.getPassword();
this.firebaseUid= createFirebaseUserData.getFirebaseUid();
this.subscribed=createFirebaseUserData.getSubscribed();
}
public UserEntity(){
}
public Integer getUid() {
return uid;
}
public void setUid(Integer uid) {
this.uid = uid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getFirebaseUid() {
return firebaseUid;
}
public void setFirebaseUid(String firebaseUid) {
this.firebaseUid = firebaseUid;
}
public Boolean getEmailVerified() {
return emailVerified;
}
public void setEmailVerified(Boolean emailVerified) {
this.emailVerified = emailVerified;
}
public Boolean getSubscribed() {
return subscribed;
}
public void setSubscribed(Boolean subscribed) {
this.subscribed = subscribed;
}
}
RatingEntity:
#Entity
#Table(name="Rating")
public class ProductsRatedByUserEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="pruid")
private Integer pruid;
#OneToOne
#JoinColumn(name="pid",nullable = false)
private ProductEntity product;
#ManyToOne
#JoinColumn(name="uid",nullable = false)
private UserEntity user;
#Column
private Integer starsGiven;
#Column(name="total_stars", nullable = false)
private Integer totalStars;
#Column(name="total_num_of_users_who_rated", nullable = false)
private Integer totalNumOfUsersWhoRated;
#Column(name="average_stars")
private BigDecimal averageStars;
public ProductsRatedByUserEntity(UserEntity userEntity, ProductEntity productEntity, Integer numOfStars){
this.product=productEntity;
this.user=userEntity;
this.starsGiven=numOfStars;
this.totalStars=numOfStars;
this.totalNumOfUsersWhoRated=1;
this.averageStars=BigDecimal.valueOf(this.getTotalStars()).divide(BigDecimal.valueOf(this.getTotalNumOfUsersWhoRated()));
}
public ProductsRatedByUserEntity(ProductEntity product,UserEntity user,Integer numOfStars,Integer newTotalNumOfStars, Integer newTotalNumberOfUsers, BigDecimal averageStars){
this.product=product;
this.user=user;
this.starsGiven=numOfStars;
this.totalStars=newTotalNumOfStars;
this.totalNumOfUsersWhoRated=newTotalNumberOfUsers;
this.averageStars=averageStars;
}
public ProductsRatedByUserEntity(){
}
public Integer getPruid() {
return pruid;
}
public void setPruid(Integer plbuid) {
this.pruid = plbuid;
}
public ProductEntity getProduct() {
return product;
}
public void setProduct(ProductEntity product) {
this.product = product;
}
public UserEntity getUser() {
return user;
}
public void setUser(UserEntity user) {
this.user = user;
}
public Integer getStarsGiven() {
return starsGiven;
}
public void setStarsGiven(Integer starsGiven) {
this.starsGiven = starsGiven;
}
public Integer getTotalStars() {
return totalStars;
}
public void setTotalStars(Integer totalStars) {
this.totalStars = totalStars;
}
public Integer getTotalNumOfUsersWhoRated() {
return totalNumOfUsersWhoRated;
}
public void setTotalNumOfUsersWhoRated(Integer totalNumOfUsersWhoLiked) {
this.totalNumOfUsersWhoRated = totalNumOfUsersWhoLiked;
}
public BigDecimal getAverageStars() {
return averageStars;
}
public void setAverageStars(BigDecimal averageStars) {
this.averageStars = averageStars;
}
}
Api:
#CrossOrigin
#RestController
public class ProductApi {
private ProductService productService;
private ProductsRatedByUserService productsRatedByUserService;
#Autowired
public ProductApi(ProductService productService,ProductsRatedByUserService productsRatedByUserService){
this.productService=productService;
this.productsRatedByUserService=productsRatedByUserService;
}
#PutMapping("/product/rating/{pid}/{numOfStars}")
public ProductsRatedByUserResponseDto updateRating(#PathVariable Integer pid, #PathVariable Integer numOfStars, JwtAuthenticationToken jwtAuthenticationToken) throws ProductFoundByIdException {
FirebaseUserData firebaseUserData=new FirebaseUserData(jwtAuthenticationToken);
ProductsRatedByUserDetail productsRatedByUserDetail=productsRatedByUserService.updateProductRating(pid,numOfStars,firebaseUserData);
return new ProductsRatedByUserResponseDto(productsRatedByUserDetail);
}
}
RatingServiceImpl:
#Service
#Component
public class ProductsRatedByUserServiceImpl implements ProductsRatedByUserService {
public ProductsRatedByUserRepository productsRatedByUserRepository;
public ProductRepository productRepository;
public UserRepository userRepository;
#Autowired
public ProductsRatedByUserServiceImpl(ProductsRatedByUserRepository productsRatedByUserRepository,ProductRepository productRepository,UserRepository userRepository){
this.productsRatedByUserRepository=productsRatedByUserRepository;
this.productRepository=productRepository;
this.userRepository=userRepository;
}
#Override
public ProductsRatedByUserDetail updateProductRating(Integer pid, Integer numOfStars, FirebaseUserData firebaseUserData) throws ProductFoundByIdException {
if(!productRepository.existsById(pid)){
throw new ProductFoundByIdException();
}
UserEntity userEntity=userRepository.findUserEntityByEmail(firebaseUserData.getEmail());
ProductEntity productEntity =productRepository.findById(pid).orElse(null);
//check if the product has been rated by *any user*
//If no, we need to create an entity
if(!productsRatedByUserRepository.existsByProduct(productEntity)){
ProductsRatedByUserEntity productsRatedByUserEntity=new ProductsRatedByUserEntity(userEntity, productEntity, numOfStars);
ProductsRatedByUserEntity productsRatedByUserEntityReturned=productsRatedByUserRepository.save(productsRatedByUserEntity);
System.out.println("the product has been rated by *any user*");
return new ProductsRatedByUserDetail(productsRatedByUserEntityReturned);
}
//If yes, we update the entity from there
else {
//if the product has been rated by this very user
if (productsRatedByUserRepository.existsByUserAndProduct(userEntity, productEntity)) {
ProductsRatedByUserEntity productsRatedByUserEntity = productsRatedByUserRepository.findTopByUserAndProduct(userEntity, productEntity);
productsRatedByUserEntity.setTotalStars(productsRatedByUserEntity.getTotalStars() - productsRatedByUserEntity.getStarsGiven() + numOfStars);
productsRatedByUserEntity.setStarsGiven(numOfStars);
productsRatedByUserEntity.setAverageStars(BigDecimal.valueOf(productsRatedByUserEntity.getTotalStars()).divide(BigDecimal.valueOf(productsRatedByUserEntity.getTotalNumOfUsersWhoRated())));
ProductsRatedByUserEntity productsRatedByUserEntityReturned = productsRatedByUserRepository.save(productsRatedByUserEntity);
System.out.println("the product has been rated by this very user");
return new ProductsRatedByUserDetail(productsRatedByUserEntityReturned);
} else {
//The product has not been rated by this very user
ProductsRatedByUserEntity productsRatedByUserEntity = productsRatedByUserRepository.findTopByProduct(productEntity);
int newTotalNumOfStars = (productsRatedByUserEntity.getTotalStars() + numOfStars);
int newTotalNumberOfUsers = productsRatedByUserEntity.getTotalNumOfUsersWhoRated() + 1;
productsRatedByUserEntity.setUser(userEntity);
System.out.println("The product has not been rated by this very user");
return new ProductsRatedByUserDetail(productsRatedByUserRepository.save(new ProductsRatedByUserEntity(productEntity, userEntity, numOfStars, newTotalNumOfStars, newTotalNumberOfUsers, BigDecimal.valueOf(newTotalNumOfStars).divide(BigDecimal.valueOf(newTotalNumberOfUsers)))));
}
}
}
}
RatingServiceInterface:
public interface ProductsRatedByUserService {
ProductsRatedByUserDetail updateProductRating(Integer pid, Integer numOfStars, FirebaseUserData firebaseUserData) throws ProductFoundByIdException;
}
Repository:
public interface ProductsRatedByUserRepository extends CrudRepository<ProductsRatedByUserEntity,Integer> {
boolean existsByProduct(ProductEntity product);
ProductsRatedByUserEntity findTopByProduct(ProductEntity product);
boolean existsByUserAndProduct(UserEntity userEntity, ProductEntity product);
ProductsRatedByUserEntity findTopByUserAndProduct(UserEntity userEntity, ProductEntity product);
}
I will really appreciate anyone who can help me with this! I've been stuck for a whole day! I don't want to use the many-to-many annotation because it seems a bit messy. Thanks!
I have found the mistake. In my RatingEntity code, the getter and setter are erroneous. There's some typos there. It should be
public Integer getPruid() {
return pruid;
}
public void setPruid(Integer pruid) {
this.pruid = pruid;
}
I have a Spring-Boot-Project with JPA and JSON-Serialization. I try to use #JsonView to serialize only specified Properties. It works ok, but for my associations in Order (e.g. order.user) it serialized empty Json-Object.
I use following dependencies
Spring-Boot 2.0.1.RELEASE
Spring-Boot-Starter-JPA 2.0.1.RELEASE
Spring-Hateos 0.24.0.RELEASE
See following Json-Result:
{
"content" : {
"orderResources" : [ {
"receiptDate" : "2019-08-14",
"state" : "BILL_CREATED",
"user" : { },
"employer" : { },
"orderplace" : { },
"propertyManagement" : null,
"plannings" : [ { } ]
}, {
"receiptDate" : "2019-08-17",
"state" : "BILL_CREATED",
"user" : { },
"employer" : { },
"orderplace" : { },
"propertyManagement" : null,
"plannings" : [ ]
} ]
},
"links" : {
"next" : {
"href" : "https://orderbook-demo.localhost:8443/api/order?page=1"
},
"1" : {
"href" : "https://orderbook-demo.localhost:8443/api/order?page=1"
}
},
"page" : {
"size" : 6,
"totalElements" : 2,
"totalPages" : 1,
"number" : 0
}
}
My Entities
Order
#Entity
#JsonRootName("Order")
#BatchSize(size = 100 )
#Table(name="`order`")
#Access(AccessType.FIELD)
public class Order extends BaseEntity {
private static final long serialVersionUID = 1L;
#Column(name="receipt_date", nullable = false)
#Type(type = "de.orderbook.hibernate.type.LocalDateUserType")
#JsonSerialize(using = LocalDateJsonSerializer.class)
#JsonDeserialize(using = LocalDateJsonDeserializer.class)
#JsonProperty
#JsonView(View.ListView.class)
private LocalDate receiptDate;
#Column(name="state", nullable = false)
#Enumerated(value = EnumType.STRING)
#JsonProperty
#JsonView(View.ListView.class)
private State state = State.OPEN;
#ManyToOne
#JoinColumn(name = "offer_id")
#JsonProperty
#JsonIgnore
private Offer offer;
#OneToMany(targetEntity = OrderOrderdetail.class, mappedBy = "order", orphanRemoval = true, cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#PrimaryKeyJoinColumn
#BatchSize(size = 100)
#JsonProperty
private List<OrderOrderdetail> orderdetails = new ArrayList<>(10);
#ManyToOne(targetEntity = Address.class, cascade = CascadeType.ALL)
#JoinColumn(name= "employer_id")
#Fetch(FetchMode.SELECT)
#BatchSize(size = 100)
#JsonProperty
#JsonView(View.ListView.class)
private Address employer;
#ManyToOne(targetEntity = Address.class, cascade = CascadeType.ALL)
#JoinColumn(name= "orderplace_id")
#Fetch(FetchMode.SELECT)
#BatchSize(size = 100)
#JsonProperty
#JsonView(View.ListView.class)
private Address orderplace;
#ManyToOne(targetEntity = Address.class, cascade = CascadeType.ALL)
#JoinColumn(name= "property_management_id")
#Fetch(FetchMode.SELECT)
#BatchSize(size = 100)
#JsonProperty
#JsonView(View.ListView.class)
private Address propertyManagement;
#ManyToOne
#JoinColumn(name="user_id")
#BatchSize(size = 100 )
#JsonProperty
#JsonView(View.ListView.class)
private User user;
#OneToMany(targetEntity = Planning.class, mappedBy = "order", cascade = CascadeType.ALL)
#BatchSize(size = 100 )
#JsonProperty
#JsonView(View.ListView.class)
private List<Planning> plannings = new ArrayList<Planning>(3);
public Order() {
super();
}
public Order(Offer offer) {
super();
this.receiptDate = LocalDate.now();
this.employer = offer.getEmployer();
this.orderplace = offer.getOrderplace();
this.propertyManagement = offer.getPropertyManagement();
this.user = offer.getUser();
this.offer = offer;
for (OfferOrderdetail orderdetail : offer.getOrderdetails()) {
OrderOrderdetail orderOrderdetail = new OrderOrderdetail(orderdetail.getOrderdetail(), orderdetail.getCount());
orderOrderdetail.setOrder(this);
this.getOrderdetails().add(orderOrderdetail);
}
}
#JsonCreator
public Order(#JsonProperty("receiptDate") LocalDate receiptDate,
#JsonProperty("state") State state,
#JsonProperty("user") User user,
#JsonProperty("employer") Address employer,
#JsonProperty("orderplace") Address orderplace,
#JsonProperty("propertyManagement") Address propertyManagement,
#JsonProperty("orderdetails") List<OrderOrderdetail> orderdetails,
#JsonProperty("plannings") List<Planning> plannings
) {
super();
this.receiptDate = receiptDate;
this.state = state;
this.user = user;
this.employer = employer;
this.orderplace = orderplace;
this.propertyManagement = propertyManagement;
this.orderdetails = orderdetails;
this.plannings = plannings;
}
public LocalDate getReceiptDate() {
return receiptDate;
}
public void setReceiptDate(LocalDate receiptDate) {
this.receiptDate = receiptDate;
}
public List<OrderOrderdetail> getOrderdetails() {
return orderdetails;
}
public void setOrderdetails(List<OrderOrderdetail> orderdetails) {
this.orderdetails = orderdetails;
}
public void addOrderdetail(OrderOrderdetail orderdetail) {
this.orderdetails.add(orderdetail);
}
public void removeOrderdetail(OrderOrderdetail orderdetail) {
this.orderdetails.remove(orderdetail);
}
public boolean containsOrderdetail(OrderOrderdetail orderdetail) {
return this.orderdetails.contains(orderdetail);
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Planning> getPlannings() {
return plannings;
}
public void addPlanning(Planning planning) {
this.plannings.add(planning);
}
public void removePlanning(Planning planning) {
this.plannings.remove(planning);
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public Address getEmployer() {
return employer;
}
public void setEmployer(Address employer) {
this.employer = employer;
}
public Address getOrderplace() {
return orderplace;
}
public void setOrderplace(Address orderplace) {
this.orderplace = orderplace;
}
public Address getPropertyManagement() {
return propertyManagement;
}
public void setPropertyManagement(Address propertyManagement) {
this.propertyManagement = propertyManagement;
}
public void setPlannings(List<Planning> plannings) {
this.plannings = plannings;
}
public Offer getOffer() {
return offer;
}
public void setOffer(Offer offer) {
this.offer = offer;
}
}
User
#Entity
#Table(name="`user`")
#JsonView(View.ListView.class)
public class User extends BaseEntity {
private static final long serialVersionUID = 1L;
#JsonProperty
#JsonView(View.ListView.class)
private String name;
#NaturalId
#JsonProperty
#JsonView(View.ListView.class)
private String username;
#JsonProperty
#JsonView(View.ListView.class)
private String email;
private #JsonIgnore String password;
#JsonProperty
#JsonView(View.ListView.class)
private boolean enabled;
#OneToMany(targetEntity = Authority.class)
#JoinColumn(name = "username", referencedColumnName = "username")
#BatchSize(size = 100)
#JsonProperty
#JsonView(View.ListView.class)
private List<Authority> roles;
public User() {
super();
}
public User(String username, String name, String password, String email, boolean enabled, Authority... roles) {
super();
this.username = username;
this.name = name;
this.email = email;
this.enabled = enabled;
this.setPassword(password);
this.roles = roles == null ? Collections.emptyList() : Arrays.asList(roles);
}
#JsonCreator
public User(#JsonProperty("username") String username, #JsonProperty("name") String name, #JsonProperty("email") String email, #JsonProperty("enabled") boolean enabled, #JsonProperty("roles") List<Authority> roles) {
super();
this.username = username;
this.name = name;
this.email = email;
this.enabled = enabled;
this.roles = roles == null ? Collections.emptyList() : roles;
}
public User(String username) {
super();
this.username = username;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Authority> getRoles() {
return roles;
}
public void setRoles(List<Authority> roles) {
this.roles = roles;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
My Controller
#Controller
public class OrderController extends BaseController<Order, OrderRepository> {
private static int PAGE_SIZE = 6;
#Autowired
private UserRepository userRepository;
#Autowired
private BillRepository billRepository;
#Transactional
#JsonView(View.ListView.class)
#RequestMapping(value = "/api/order", method = RequestMethod.GET, headers = "content-type=application/json", consumes = "*/*", produces = "application/json")
public #ResponseBody
HttpEntity<OrderPagedResource> findAll(Principal principal, #RequestParam(name="page") Long page) {
List<Order> list = super.list(page, Long.valueOf(PAGE_SIZE));
for (Order order : list) {
Hibernate.initialize(order.getPlannings());
Hibernate.initialize(order.getUser().getRoles());
}
List<OrderResource> resources = new OrderResourceAssembler().toResources(list);
Long count = this.repository.count();
return new HttpEntity<OrderPagedResource>(new OrderPagedResource(resources, new MyPagedMetadata(PAGE_SIZE, page, count)));
}
}
OrderResource
public class OrderResource extends ResourceSupport {
#JsonUnwrapped
#JsonView(View.ListView.class)
private Order content;
public OrderResource(Order order) {
super();
this.content = order;
}
public Order getContent() {
return content;
}
public void setContent(Order content) {
this.content = content;
}
}
OrderPagedResource
public class OrderPagedResource extends PagedResources<OrderResource> {
private Map<String, MyLink> links = new HashMap(5);
public OrderPagedResource(Collection<OrderResource> content, PageMetadata metadata) {
super(content, metadata);
for (int i = 1; i <= metadata.getTotalPages(); i++) {
if (i == metadata.getNumber() - 1)
this.links.put("prev", new MyLink(linkTo(OrderController.class).slash("/api/order?page=" + i).withRel("prev")));
if (i == metadata.getNumber() + 1)
this.links.put("next", new MyLink(linkTo(OrderController.class).slash("/api/order?page=" + i).withRel("next")));
this.links.put(Integer.toString(i), new MyLink(linkTo(OrderController.class).slash("/api/order?page=" + i).withRel(Integer.toString(i))));
}
}
#Override
#JsonProperty("page")
#JsonView(View.ListView.class)
public PageMetadata getMetadata() {
return super.getMetadata();
}
#Override
#JsonProperty("content")
#JsonView(View.ListView.class)
public Collection<OrderResource> getContent() {
return super.getContent();
}
#JsonProperty("links")
#JsonView(View.ListView.class)
public Map<String, MyLink> getLinks2() {
return this.links;
}
public class MyLink extends Link {
private #XmlAttribute #JsonProperty #JsonView(View.ListView.class) String rel;
private #XmlAttribute #JsonProperty #JsonView(View.ListView.class) String href;
public MyLink(Link link) {
super(link.getHref(), link.getRel());
this.rel = link.getRel();
this.href = link.getHref();
}
public MyLink(String href) {
super(href);
this.href = href;
}
public MyLink(String href, String rel) {
super(href, rel);
this.href = href;
this.rel = rel;
}
public MyLink() {
}
#Override
#JsonView(View.ListView.class)
public String getRel() {
return this.rel;
}
#Override
#JsonView(View.ListView.class)
public String getHref() {
return this.href;
}
}
}
OrderResourceAssembler
#Component
public class OrderResourceAssembler extends ResourceAssemblerSupport<Order, OrderResource> {
public OrderResourceAssembler() {
super(OrderController.class, OrderResource.class);
}
#Transactional
#Override
public OrderResource toResource(Order entity) {
OrderResource resource = new OrderResource(entity);
resource.add(linkTo(OrderController.class).slash("/api/order/" + entity.getId()).withSelfRel());
if (entity.getOffer() != null)
resource.add(linkTo(OrderController.class).slash("/api/offer/" + entity.getOffer().getId()).withRel("offer"));
resource.add(linkTo(UserController.class).slash("/api/user/" + entity.getUser().getId()).withRel("user"));
return resource;
}
}
By default Spring doesn't include properties in child object into a #JsonView. You can either add #JsonView to the child POJO, or enable all the children properties by applying the following configuration.
spring.jackson.mapper.default-view-inclusion=true
These are my model classes:
Film.java
#Entity
public class Film {
private Integer id;
private String title;
private List<FilmActor> filmActors;
#OneToMany(mappedBy = "film")
public List<FilmActor> getFilmActors() {
return filmActors;
}
public void setFilmActors(List<FilmActor> filmActors) {
this.filmActors = filmActors;
}
}
Actor.java
#Entity
public class Actor {
private Integer id;
private String firstname;
private String lastname;
private List<FilmActor> filmActors;
#OneToMany(mappedBy = "actor")
public List<FilmActor> getFilmActors() {
return filmActors;
}
public void setFilmActors(List<FilmActor> filmActors) {
this.filmActors = filmActors;
}
}
And this is the Join Table Entity:
#Entity
#Table(name = "film_actor")
public class FilmActor {
private FilmActorPK id;
private Film film;
private Actor actor;
private Timestamp lastUpdate;
#EmbeddedId
public FilmActorPK getId() {
return id;
}
public void setId(FilmActorPK id) {
this.id = id;
}
#ManyToOne
#MapsId("film")
#JoinColumn(name = "film_id")
public Film getFilm() {
return film;
}
public void setFilm(Film film) {
this.film = film;
}
#ManyToOne
#MapsId("actor")
#JoinColumn(name = "actor_id")
public Actor getActor() {
return actor;
}
public void setActor(Actor actor) {
this.actor = actor;
}
#Column(name = "last_update")
public Timestamp getLastUpdate() {
return lastUpdate;
}
public void setLastUpdate(Timestamp lastUpdate) {
this.lastUpdate = lastUpdate;
}
}
and the Primary Key class:
#Embeddable
public class FilmActorPK implements Serializable {
private int actorId;
private int filmId;
#Column(name = "actor_id")
public int getActorId() {
return actorId;
}
public void setActorId(int actorId) {
this.actorId = actorId;
}
#Column(name = "film_id")
public int getFilmId() {
return filmId;
}
public void setFilmId(int filmId) {
this.filmId = filmId;
}
}
So I want to find films where 2 given actors acts. This is what I have:
#Override
public Collection<Film> filmsActorsTogether(Actor a, Actor b) {
final List<Film> filmsOfActorA = filmsOfActor(a);
final List<Film> filmsOfActorB = filmsOfActor(b);
final Collection<Film> intersection = CollectionUtils.intersection(filmsOfActorA, filmsOfActorB);
return intersection;
}
#Override
public List<Film> filmsOfActor(Actor actor) {
final EntityManager entityManager = persistenceUtil.getEntityManager();
final Actor persistentActor = entityManager.find(Actor.class, actor.getId());
final ArrayList<Film> films = new ArrayList<Film>();
for (FilmActor filmActor : persistentActor.getFilmActors()) {
films.add(filmActor.getFilm());
}
entityManager.close();
return films;
}
Is there any way to achieve this without fetching ALL films of 2 actors, and using filtering in memory? How do I get the Films directly from the DB with JQL?
Maybe there is something more elegant, but the following query should work:
select f from Film f where
(select count(fa.id) from FilmActor fa
where fa.film = f
and (fa.actor = :actor1 or fa.actor = :actor2)) = 2
Side note: your PK class should have a correct equals() and hashCode() methods
public User updateUser(User user) {
try {
User result = session.get(User.class, user.getId());
if (result == null) {
throw new FilamentNoSuchRecordException(new CoreError(304, "User does not exist"));
}
session.clear();
session.update(user);
return user;
} catch (HibernateException e) {
e.printStackTrace();
}
throw new FilamentDataConnectivityException(new CoreError(305,"Connectivity issue. Please see System Administrator"));
}
customer model is as follows
#Entity
#Table(name = "customers")
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id")
#DynamicUpdate(value=true)
#SelectBeforeUpdate(value=true)
#SQLDelete(sql="Update customers SET deleted = true where customer_id=?")
#Where(clause="deleted != true")
#ApiModel(description="Create or update Customers")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Customer {
#Id
#Column(name="customer_id")
#NotNull
#GeneratedValue(strategy=GenerationType.AUTO)
private int id = 0;
#Column(name="name")
#ApiModelProperty(value="The name of the customer", example="Mr J. Bond")
#NotNull
private String name;
#Column(name="description")
#ApiModelProperty(value="Desciption of the customer")
#NotNull
private String description;
#Column(name="logo_url")
#ApiModelProperty(value="Logo of user")
#NotNull
private String logo;
#Column(name="created_at")
#ApiModelProperty(value="The date the item was created", example="")
#NotNull
private Date createdAt;
#Column(name="updated_at")
#ApiModelProperty(value="The date the item was updated", example="")
#NotNull
private Date updatedAt;
#ApiModelProperty(hidden=true)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
private Set<Application> applications = new HashSet<Application>();
#ManyToMany(mappedBy = "customers")
private Set<Service> services = new HashSet<Service>();
#ApiModelProperty(hidden=true)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
private Set<User> users = new HashSet<User>();
#ManyToMany(cascade = CascadeType.ALL)
#JoinTable(
name = "customer_subscription",
joinColumns = #JoinColumn(name = "customer_id"),
inverseJoinColumns = #JoinColumn(name = "subscription_id")
)
private Set<Subscription> subscriptions = new HashSet<Subscription>();
#ApiModelProperty(hidden=true)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "customer")
private Set<Corpus> corpus = new HashSet<Corpus>();
#Column(name="deleted")
#NotNull
private boolean deleteFlag;
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 Set<Application> getApplications() {
return applications;
}
public void setApplications(Set<Application> applications) {
this.applications = applications;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getLogo() {
return logo;
}
public void setLogo(String logo) {
this.logo = logo;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}
public Set<Service> getServices() {
return services;
}
public void setServices(Set<Service> services) {
this.services = services;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public Set<Corpus> getCorpus() {
return corpus;
}
public void setCorpus(Set<Corpus> corpus) {
this.corpus = corpus;
}
public Set<Subscription> getSubscriptions() {
return subscriptions;
}
public void setSubscriptions(Set<Subscription> subscriptions) {
this.subscriptions = subscriptions;
}
public boolean getDeleteFlag() {
return deleteFlag;
}
public void setDeleteFlag(boolean deleteFlag) {
this.deleteFlag = deleteFlag;
}
}
I check whether the object exists within the database, then update with an object, for example all fields could be null apart from the ID and the one thats needs to be updated. All fields are set to #NotNull in the model and I am using the #DynamicUpdate(value=true) and #SelectBeforeUpdate(value=true) annotations, but these seem to do nothing.
Just get failure saying the null fields can not be null. How do I update the row?
As we discussed in above comments, try this -
public User updateUser(User user) {
try {
User result = session.get(User.class, user.getId());
if (result == null) {
throw new FilamentNoSuchRecordException(new CoreError(304, "User does not exist"));
}
result.setName(user.getName()); // update some properties
session.update(result); // you should update 'result', not 'user'
return result;
} catch (HibernateException e) {
e.printStackTrace();
throw new FilamentDataConnectivityException(new CoreError(305,"Connectivity issue. Please see System Administrator"));
}
}
By using this method I found in another stack overflow post solved the issue. This checks each field and uses the 'not null' value. Then i can update from an object with only 1 field changed.
public static <T> T getNotNull(T a, T b) {
return b != null && a != null && !a.equals(b) ? a : b;
}
Please help me in accessing Employee object in the below code using JAXB annotations. The application was developed in JPA SPRING. We are unable to access sub-object properties i.e, Employee properties
RESOURCE CORE FILE
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="resource")
#Entity
#Table(name = "resource")
public class Resource implements java.io.Serializable {
private Integer resourceId;
private String resourceCode;
private String resourceName;
private String resourceNumber;
private Employee employee;
public Resource() {
}
public Resource(Employee employee,String resourceCode, String resourceName,
String resourceNumber
) {
this.employee = employee;
this.resourceCode = resourceCode;
this.resourceName = resourceName;
this.resourceNumber = resourceNumber;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "resource_id", unique = true, nullable = false)
public Integer getResourceId() {
return this.resourceId;
}
public void setResourceId(Integer resourceId) {
this.resourceId = resourceId;
}
#Column(name = "resource_code")
public String getResourceCode() {
return this.resourceCode;
}
public void setResourceCode(String resourceCode) {
this.resourceCode = resourceCode;
}
#Column(name = "resource_number")
public String getResourceNumber() {
return this.resourceNumber;
}
public void setResourceNumber(String resourceNumber) {
this.resourceNumber = resourceNumber;
}
#Column(name = "resource_name")
public String getResourceName() {
return this.resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "employee_id")
public Employee getEmployee() {
return this.employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
EMPLOYEE CORE FILE
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="employee")
#Entity
#Table(name = "employee")
public class Employee implements java.io.Serializable {
private Integer employeeId;
private String employeeCode;
private String employeeName;
private List<Resource> resources = new ArrayList<Resource>(0);
public Employee() {
}
public Employee(String employeeCode, String employeeName,List<Resource> resources
) {
this.employeeCode = employeeCode;
this.employeeName = employeeName;
this.resources = resources;
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "employee_id", unique = true, nullable = false)
public Integer getEmployeeId() {
return this.employeeId;
}
public void setEmployeeId(Integer employeeId) {
this.employeeId = employeeId;
}
#Column(name = "employee_code")
public String getEmployeeCode() {
return this.employeeCode;
}
public void setEmployeeCode(String employeeCode) {
this.employeeCode = employeeCode;
}
#Column(name = "employee_name")
public String getEmployeeName() {
return this.employeeName;
}
public void setEmployeeName(String employeeName) {
this.employeeName = employeeName;
}
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "employee")
public List<Resource> getResources() {
return this.resources;
}
public void setResources(List<Resource> resources) {
this.resources = resources;
}
}
You have to use the FetchType : Eager in RESOURCE CORE FILE of getEmployee() Method. Lazy fetch type is pulling only the parent object. Eager is pulling both.