How to build a Simple search page using Spring MVC? - rest

I have created webapp using Spring MVC and i have done the CRUD operations and now stuck with the search page.
I have already have coded below jsp and the controller.
JSP page body
<div align="center">
<h1>Search Items</h1>
<form action="search_1" method="get" modelAttribute="search">
<table>
<tr>
<td>Category:</td>
<td>
<select type="text" name="category_id">
<option value="Book">Book</option>
<option value="Audio Books">Audio Books</option>
<option value="Videos">Videos</option>
<option value="Music">Music</option>
</select>
</td>
</tr>
<tr>
<td>Publisher ID:</td>
<td>
<select type="text" name="publisher_id">
<option value="Harper Collins">Harper Collins</option>
<option value="Penguins">Penguins</option>
<option value="Franciscan Media">Franciscan Media</option>
<option value="Orbis">Orbis</option>
</select>
</td>
</tr>
<tr>
<td>Price Range:</td>
<td>Min: <input type="text" name="price_1"/> Max:
<input type="text" name="price_2"/></td>
</tr>
<tr>
<td colspan="2" align="center"><input type="submit" value="search"></td>
</tr>
</table>
</form>
</div>
Controller
#RequestMapping(value ="/search_1",method = RequestMethod.GET)
public ModelAndView search_1(HttpServletRequest request, HttpServletResponse response) {
String category_id = request.getParameter("category_id");
String publisher_id = request.getParameter("publisher_id");
int price = Integer.parseInt(request.getParameter("price"));
ModelAndView model = new ModelAndView();
model.setViewName("searchResult");
return model;
}
Items bean
package com.jwt.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "items")
public class Items implements Serializable {
private static final long serialVersionUID = -3465813074586302847L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Column
private String ISBN;
#Column
private String title;
#Column
private String category_id;
#Column
private String Author;
#Column
private String publisher_id;
#Column
private float price;
#Column
private int stock;
#Column
private int photo_id;
public int getid() {
return id;
}
public void setid(int id) {
this.id = id;
}
public String getISBN() {
return ISBN;
}
public void setISBN(String ISBN) {
this.ISBN = ISBN;
}
public String gettitle() {
return title;
}
public void settitle(String title) {
this.title = title;
}
public String getcategory_id() {
return category_id;
}
public void setcategory_id( String category_id) {
this.category_id = category_id;
}
public String getAuthor() {
return Author;
}
public void setAuthor(String Author) {
this.Author = Author;
}
public String getpublisher_id() {
return publisher_id;
}
public void setpublisher_id(String publisher_id) {
this.publisher_id = publisher_id;
}
public float getprice() {
return price;
}
public void setprice(float price) {
this.price = price;
}
public int getstock() {
return stock;
}
public void setstock(int stock) {
this.stock = stock;
}
public int getphoto_id() {
return photo_id;
}
public void setphoto_id(int photo_id) {
this.photo_id = photo_id;
}
}
The search has to be done as per the search criteria on the JSP page. The results view can be on the same page. It really doesn't matter,

I am not sure why are you confused, but let's see if I can help.
In your controller, you have to extract all of the criteria correctly then retrieve the list of items using these criteria from your database. Create a method in a service class that takes these criteria as parameter and returns a list of items. Attached that item in model and display in "searchResult.jsp" page.
Here is a rough controller method that should handle your search
#RequestMapping(value = "/search_1", method = RequestMethod.GET)
public ModelAndView search(HttpServletRequest request) {
String categoryId = request.getParameter("category_id");
String publisherId = request.getParameter("publisher_id");
int minPrice = Integer.parseInt(request.getParameter("price_1"));
int maxPrice = Integer.parseInt(request.getParameter("price_2"));
List<Item> items = someService.getItems(categoryId, publisherId, minPrice, maxPrice);
ModelAndView model = new ModelAndView();
model.addObject("items", items);
model.setViewName("searchResult");
return model;
}

Related

Is there an easier way to query "all" from an entity property, which is another Entity / Enum / Boolean / Long? Spring Data

I have an Entity called Item. Item has, among other things, a productNumber (Long) a category (own Entity), an itemType (Enum of own creation) and an isHidden (Boolean). I want to do queries like this:
List<Item> findByItemTypeAndCategoryAndIsHiddenAndNameIgnoreCaseContainingAndProductNumberAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(ItemType itemType, Category category, Boolean isHidden, String name, Long productNumber, String manufacturer, String wholesaler);
A user of the application is able to search Items in such a manner:
Item type: All / Product / Service
Category: All / category1 / category2...
Hidden: All / don't show hidden / show only hidden
Product Number: a number field
Is there a way to use the above query if itemtype/category/isHidden are All? I know that I can create own queries for those situations by leaving out the particular property from which the user wants to find all. But surely there is a way to use that one query for each instance, I just don't know how to edit it to include null/empty so that it returns "All".
And how about the productNumber? Is there an equivalent to "containing" for type Long? So that one could query "456" and it would return all Items with "456" included in the productNumber?
Thanks in advance!
Item:
package mortar.euroshopper.eCommerceApplication;
import java.io.Serializable;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
#Entity
#NoArgsConstructor
#Getter
#Setter
#ToString
public class Item implements Serializable, Comparable<Item> {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private ItemType itemType;
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "category")
private Category category;
private Long productNumber;
private String name;
private String amount;
private Unit unit;
private String manufacturer;
private String wholesaler;
private Double price;
private Double discountPrice;
private Double discountPercentage;
private LocalDate discountStarts;
private LocalDate discountEnds;
private Double stock;
private LocalDate expirationDate;
#Column(length = 10000)
private String description;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Image> images = new ArrayList<>();
private Long mainImageId;
private Boolean isHidden;
private PromotionLevel promotionLevel;
#Override
public int compareTo(Item other) {
return name.compareToIgnoreCase(other.name);
}
public Item(Long productNumber, String name, String manufacturer, String wholesaler, Double price, String description, Double stock, Category category) {
this.name = name;
this.price = price;
this.description = description;
this.stock = stock;
this.category = category;
}
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof Item)) {
return false;
}
Item other = (Item) o;
return id != null && id.equals(other.getId());
}
#Override
public int hashCode() {
return getClass().hashCode();
}
}
ItemType:
public enum ItemType {
PRODUCT, SERVICE
}
Category:
package mortar.euroshopper.eCommerceApplication;
import com.fasterxml.jackson.annotation.JsonBackReference;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.LazyCollection;
import org.hibernate.annotations.LazyCollectionOption;
import org.springframework.data.jpa.domain.AbstractPersistable;
#Entity
#NoArgsConstructor
#Data
public class Category extends AbstractPersistable<Long> {
#NotNull
private String name;
#JsonBackReference
#ManyToOne(cascade = CascadeType.MERGE)
#JoinColumn(name = "parentCategory")
private Category parentCategory;
#OneToMany(mappedBy = "parentCategory")
private List<Category> subCategories = new ArrayList<>();
#LazyCollection(LazyCollectionOption.FALSE)
#OneToMany(mappedBy = "category")
private List<Item> items = new ArrayList<>();
public Category(String name) {
this.name = name;
}
public Category(String name, Category parent) {
this.name = name;
this.parentCategory = parent;
}
public Integer subCategoryLevel;
}
----------------------------------- EDIT -----------------------------------
I changed productNumber to type String and that solved my problem on that part. Otherwise, my solution for now looks like this (and I cant believe that this is the best, or even a good way to do this):
HTML:
<form th:action="#{/items}" method="GET">
<div class="form-row">
<div class="form-group mr-2">
<label for="type">Type</label>
<select class="form-control" id="type" name="type">
<option value="">All</option>
<option value="product">Products</option>
<option value="service">Services</option>
</select>
</div>
<div class="form-group mr-2">
<label for="category">Category</label>
<input class="form-control" list="category" name="category" id="categories" placeholder="All"/>
<datalist id="category">
<option th:each="ca : ${categories}" th:value="${ca.name}"/>
</datalist>
</div>
<div class="form-group">
<label for="hidden">Hidden</label>
<select class="form-control" id="hidden" name="showHidden">
<option value="all">All</option>
<option value="true">Only hidden</option>
<option value="false">No hidden</option>
</select>
</div>
</div>
... non relevant stuff....
JpaRepositotry:
public interface ItemRepository extends JpaRepository<Item, Long> {
Item findByProductNumber(String productNumber);
List<Item> findByItemTypeIgnoreCaseContainingAndCategoryAndIsHiddenAndNameIgnoreCaseContainingAndProductNumberContainingAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(String itemType, Category category, Boolean isHidden, String name, String productNumber, String manufacturer, String wholesaler);
List<Item> findByItemTypeIgnoreCaseContainingAndIsHiddenAndNameIgnoreCaseContainingAndProductNumberContainingAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(String itemType, Boolean isHidden, String name, String productNumber, String manufacturer, String wholesaler);
List<Item> findByItemTypeIgnoreCaseContainingAndCategoryAndNameIgnoreCaseContainingAndProductNumberContainingAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(String itemType, Category category, String name, String productNumber, String manufacturer, String wholesaler);
List<Item> findByItemTypeIgnoreCaseContainingAndNameIgnoreCaseContainingAndProductNumberContainingAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(String itemType, String name, String productNumber, String manufacturer, String wholesaler);
List<Item> findByCategoryOrderByName(Category category);
}
Controller method:
#GetMapping("/items")
public String viewItems(Model model, #RequestParam(required = false) String type, #RequestParam(required = false) String category, #RequestParam(required = false) String showHidden, #RequestParam(required = false) String name, #RequestParam(required = false) String productNumber, #RequestParam(required = false) String manufacturer, #RequestParam(required = false) String wholesaler) {
itemService.addAttributesToModelForPageItems(model, type, category, showHidden, name, productNumber, manufacturer, wholesaler);
return "items";
}
addAttributesToModelForPageItems -method:
public void addAttributesToModelForPageItems(Model model, String type, String category, String showHidden, String name, String productNumber, String manufacturer, String wholesaler) {
List<Item> items = new ArrayList<>();
if (type != null) {
if (category.equals("") && showHidden.equals("all")) {
items = itemRepository.findByItemTypeIgnoreCaseContainingAndNameIgnoreCaseContainingAndProductNumberContainingAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(type, name, productNumber, manufacturer, wholesaler);
}
if (!category.equals("") && showHidden.equals("all")) {
items = itemRepository.findByItemTypeIgnoreCaseContainingAndCategoryAndNameIgnoreCaseContainingAndProductNumberContainingAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(type, categoryRepository.findByName(category), name, productNumber, manufacturer, wholesaler);
}
if (category.equals("") && !showHidden.equals("all")) {
items = itemRepository.findByItemTypeIgnoreCaseContainingAndIsHiddenAndNameIgnoreCaseContainingAndProductNumberContainingAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(type, Boolean.valueOf(showHidden), name, productNumber, manufacturer, wholesaler);
}
if (!category.equals("") && !showHidden.equals("all")) {
items = itemRepository.findByItemTypeIgnoreCaseContainingAndCategoryAndIsHiddenAndNameIgnoreCaseContainingAndProductNumberContainingAndManufacturerIgnoreCaseContainingAndWholesalerIgnoreCaseContainingOrderByName(type, categoryRepository.findByName(category), Boolean.valueOf(showHidden), name, productNumber, manufacturer, wholesaler);
}
}
model.addAttribute(
"items", items);
model.addAttribute(
"categories", categoryRepository.findAll());
}

Spring Security configuration with the login form

It showing me the defult Login form and my login form i use the defult User name und passowrd to login to time. in the first time it sowing me my login form and when i try to login in the same default username and password it rturn alwas to the second login form with code stat:302. (i saved employee in the database but it givs me alwas err)
#EnableWebSecurity
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
EmployeeDao employeeDao;
#Autowired
private DataSource dataSource;
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery("select username,password
from employees where username=?")
.authoritiesByUsernameQuery("select username, authority from employees where username=?")
.passwordEncoder(bCryptPasswordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests().antMatchers("/admin/**").hasRole("ADMIN").anyRequest().authenticated()
.and()
.formLogin().loginPage("/login").failureUrl("/login?error=true").defaultSuccessUrl("/home", true)
.and()
.logout().logoutSuccessUrl("/login?logout=true") ;
}
}
My Controller:
#GetMapping({"/","/login"})
public String LoginForm() { return "login";}
#GetMapping("/home")
public String showhome(Model model) { return "index";}
My Entity:
#Entity
#Getter
#Setter
#Table(name = "employees")
public class Employee {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
#Column(name = "username", nullable = false)
private String username;
#Column(name = "password", nullable = false)
private String password;
#Column(name = "fullname", nullable = false)
private String fullname;
#Column(name = "authority", nullable = false)
private String authority;
#OneToMany(mappedBy = "employee", fetch = FetchType.EAGER)
#Cascade(CascadeType.ALL)
private List<Role> roles;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getFullname() {
return fullname;
}
public void setFullname(String fullname) {
this.fullname = fullname;
}
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public List<Role> getRoles() {
return roles;
}
public void setRoles(List<Role> roles) {
this.roles = roles;
}
}
My Login form:
<div class="divLogin" align="center">
<h1 clase="text-center">Login Page</h1>
<form class="addForm" th:action="#{/login}" method="post">
<fieldset>
<legend lase="text-center">Please Login</legend>
<input class="inputForm" type="text" id="username" name="username" placeholder="Username"/>
<input class="inputForm" type="password" id="password" name="password" placeholder="Passowrd"/>
<div class="divBottonLogin" align="center">
<button class="botten" type="submit">Log in</button>
</div>
</fieldset>
</form>
</div>

Primefaces Lazy Datatable Sort/Filter with table relation - Eclipselink

I have a lazy datatable of primefaces as follows:
<h:form id="form">
<p:dataTable value="#{beanReceipts.lazyModel}" paginator="true" rows="10" paginatorPosition="bottom"
paginatorTemplate="{RowsPerPageDropdown} {FirstPageLink} {PreviousPageLink} {CurrentPageReport} {NextPageLink} {LastPageLink}"
rowsPerPageTemplate="5,10,15" var="item" emptyMessage="#{bundle['NoData']}" reflow="true"
rowStyleClass="centered" styleClass="centered" lazy="true" resizableColumns="true">
<p:column style="width:24px" styleClass="centered">
<p:rowToggler/>
</p:column>
<p:column headerText="#{bundle['Name']}" filterBy="#{item.userId.name}" filterMatchMode="contains"
styleClass="centered" sortBy="#{item.userId.name}">
<h:outputText value="#{item.userId.name}"/>
</p:column>
<p:column headerText="#{bundle['Premium']}" styleClass="centered"
sortBy="#{item.userId.premiumExpiresAt}">
<p:selectBooleanCheckbox value="#{item.userId.premiumExpiresAt != null}" disabled="true"/>
</p:column>
<p:column headerText="#{bundle['Product']}" sortBy="#{item.productId}" styleClass="centered">
<h:outputText value="#{item.productId}"/>
</p:column>
<p:column headerText="#{bundle['AutoRenew']}" sortBy="#{item.autoRenew}" styleClass="centered">
<p:selectBooleanCheckbox value="#{item.autoRenew}" disabled="true"/>
</p:column>
<p:column headerText="#{bundle['ExpiresAt']}" styleClass="centered">
<h:outputText value="#{item.expiresAt}">
<f:convertDateTime type="date" pattern="dd/MM/yyyy"/>
</h:outputText>
</p:column>
<p:column headerText="#{bundle['PurchasedAt']}" sortBy="#{item.purchasedAt}" styleClass="centered">
<h:outputText value="#{item.purchasedAt}">
<f:convertDateTime type="date" pattern="dd/MM/yyyy"/>
</h:outputText>
</p:column>
<p:column headerText="#{bundle['Platform']}" sortBy="#{item.platform}" styleClass="centered">
<h:outputText value="#{item.platform}"/>
</p:column>
<p:rowExpansion>
<h:panelGrid columns="2" cellspacing="3" cellpadding="3">
<h:outputText value="#{bundle['OrderId']}" style="font-weight: bold"/>
<h:outputText value="#{item.orderId}"/>
<h:outputText value="#{bundle['PurchaseToken']}" style="font-weight: bold"/>
<h:outputText value="#{item.purchaseToken}"/>
<h:outputText value="#{bundle['IsProcessed']}" style="font-weight: bold"/>
<p:selectBooleanCheckbox value="#{item.purchasedAt != null}" disabled="true"/>
<h:outputText value="#{bundle['RawData']}" style="font-weight: bold"/>
<h:outputText value="#{item.rawData}"/>
</h:panelGrid>
<br/>
<p:commandButton actionListener="#{beanReceipts.checkPaymentForUser}" icon="ui-icon-refresh"
value="#{bundle['Validate']}"
oncomplete="window.location.reload();" onstart="PF('loadingDia').show();"
onsuccess="PF('loadingDia').hide();" style="margin: auto;display: block;"/>
</p:rowExpansion>
<p:column headerText="#{bundle['Options']}" styleClass="centered">
<p:commandButton icon="ui-icon-pencil" onsuccess="PF('editdia').show();" update=":editdia"
style="margin: 8px;">
<f:setPropertyActionListener value="#{item}" target="#{beanReceipts.editableItem}"/>
</p:commandButton>
<p:commandButton icon="ui-icon-trash" oncomplete="window.location.reload();"
action="#{beanReceipts.deleteEntity}"
onclick="if (!confirm('#{bundle['RemovePrompt']}'))return false;"
style="margin: 0 auto; text-align: center;">
<f:setPropertyActionListener value="#{item}" target="#{beanReceipts.removableItem}"/>
</p:commandButton>
</p:column>
</p:dataTable>
</h:form>
And here is my entity class:
public class UsersReceipts extends BaseEntity {
private static final long serialVersionUID = 1L;
#Basic(optional = false)
#Column(name = "RECEIPT_TYPE", nullable = false)
#Enumerated(EnumType.STRING)
private DBUserReceiptTypeEnum receiptType;
#Column(name = "AUTO_RENEW")
private Boolean autoRenew;
#Column(name = "ORDER_ID", length = 255)
private String orderId;
#Column(name = "PRODUCT_ID", length = 255)
private String productId;
#Column(name = "PACKAGE_NAME", length = 255)
private String packageName;
#Column(name = "EXPIRES_AT")
#Temporal(TemporalType.TIMESTAMP)
private Date expiresAt;
#Column(name = "PURCHASED_AT")
#Temporal(TemporalType.TIMESTAMP)
private Date purchasedAt;
#Lob
#Column(name = "PURCHASE_TOKEN", length = 65535)
private String purchaseToken;
#Basic(optional = false)
#Column(name = "PLATFORM", nullable = false, length = 8)
#Enumerated(EnumType.STRING)
private DBAppPlatformTypeEnum platform;
#Basic(optional = false)
#Lob
#Column(name = "RAW_DATA", nullable = false, length = 65535)
private String rawData;
#JoinColumn(name = "USER_ID", referencedColumnName = "ID", nullable = false)
#ManyToOne(optional = false, fetch = FetchType.LAZY)
private Users userId;
public UsersReceipts() {
}
public UsersReceipts(Integer id) {
this.id = id;
}
public UsersReceipts(Integer id, DBEntryStatusTypeEnum status, Date createdAt, DBAppPlatformTypeEnum platform,
DBUserReceiptTypeEnum receiptType, String rawData) {
this.id = id;
this.status = status;
this.createdAt = createdAt;
this.platform = platform;
this.receiptType = receiptType;
this.rawData = rawData;
}
public Boolean getAutoRenew() {
return autoRenew;
}
public void setAutoRenew(Boolean autoRenew) {
this.autoRenew = autoRenew;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getProductId() {
return productId;
}
public void setProductId(String productId) {
this.productId = productId;
}
public String getPackageName() {
return packageName;
}
public void setPackageName(String packageName) {
this.packageName = packageName;
}
public Date getExpiresAt() {
return expiresAt;
}
public void setExpiresAt(Date expiresAt) {
this.expiresAt = expiresAt;
}
public Date getPurchasedAt() {
return purchasedAt;
}
public void setPurchasedAt(Date purchasedAt) {
this.purchasedAt = purchasedAt;
}
public String getPurchaseToken() {
return purchaseToken;
}
public void setPurchaseToken(String purchaseToken) {
this.purchaseToken = purchaseToken;
}
public DBAppPlatformTypeEnum getPlatform() {
return platform;
}
public void setPlatform(DBAppPlatformTypeEnum platform) {
this.platform = platform;
}
public DBUserReceiptTypeEnum getReceiptType() {
return receiptType;
}
public void setReceiptType(DBUserReceiptTypeEnum receiptType) {
this.receiptType = receiptType;
}
public String getRawData() {
return rawData;
}
public void setRawData(String rawData) {
this.rawData = rawData;
}
#JsonIgnore
#XmlTransient
public Users getUserId() {
return userId;
}
public void setUserId(Users userId) {
this.userId = userId;
}
}
As you can already see my each 'receipt' object in datatable has a relation (ManyToOne) to a 'Users' object (class). In my datatable when I add:
#{item.userId.name}
it can show me user's name which the receipt belongs to.This also applies to
#{item.userId.premiumExpiresAt}
field in 2nd column. My problem is when I try to sort/filter 1st and 2nd column in my lazy datatable I get the following error because of relation:
SEVERE [http-nio-8080-exec-5] com.sun.faces.application.view.FaceletViewHandlingStrategy.handleRenderException Error Rendering View[/panel/receipts.xhtml]
java.lang.IllegalArgumentException: The attribute [userId.name] is not present in the managed type [EntityTypeImpl#422737256:UsersReceipts [ javaType: class entities.UsersReceipts descriptor: RelationalDescriptor(entities.UsersReceipts --> [DatabaseTable(test_esimibul.users_receipts)]), mappings: 14]].
at org.eclipse.persistence.internal.jpa.metamodel.ManagedTypeImpl.getAttribute(ManagedTypeImpl.java:148)
at org.eclipse.persistence.internal.jpa.querydef.FromImpl.get(FromImpl.java:312)
at core.AbstractFacade.getFilterCondition(AbstractFacade.java:175)
at core.AbstractFacade.count(AbstractFacade.java:131)
at core.panel.crud.LazyCrudBean$EntityLazyModel.load(LazyCrudBean.java:44)
As far as exception says that I need to include usersId (Users entity in my case) into the query, I couldn't achieve that. Here is my AbstractFacade's methods that perform lazy loading:
/**
* Returns paginated, sorted and filtered result list.
*
* #param startingAt
* #param maxPerPage
* #param sortField
* #param sortOrder
* #param filters
* #return
*/
#Override
public List<T> getAll(int startingAt, int maxPerPage, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
EntityManager em = getEntityManager();
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<T> cq = cb.createQuery(type);
Root<T> c = cq.from(type);
cq.where(getFilterCondition(cb, c, filters));
if (sortField != null) if (sortOrder == SortOrder.ASCENDING) cq.orderBy(cb.asc(c.get(sortField)));
else if (sortOrder == SortOrder.DESCENDING) cq.orderBy(cb.desc(c.get(sortField)));
List<T> results = em.createQuery(cq).setFirstResult(startingAt).setMaxResults(maxPerPage).getResultList();
em.close();
return results;
}
/**
* Returns the count of rows for the given filtering criterias.
*
* #param filters
* #return
*/
#Override
public int count(Map<String, Object> filters) {
EntityManager em = getEntityManager();
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Long> cq = cb.createQuery(Long.class);
Root<T> c = cq.from(type);
cq.where(getFilterCondition(cb, c, filters));
cq.select(cb.count(c));
int count = em.createQuery(cq).getSingleResult().intValue();
em.close();
return count;
}
/**
* Creates a dynamic filtering condition with the given params.
*
* #param cb
* #param c
* #param filters
* #return
*/
private Predicate getFilterCondition(CriteriaBuilder cb, Root<T> c, Map<String, Object> filters) {
Predicate filterCondition = cb.conjunction();
filters.put("status", DBEntryStatusTypeEnum.ACTIVE);
for (Map.Entry<String, Object> filter : filters.entrySet())
if (!filter.getValue().equals(""))
filterCondition = cb.and(filterCondition, cb.like(c.get(filter.getKey()), String.format("%%%s%%", filter.getValue())));
return filterCondition;
}
I need to know how to include relations when using them in a lazy datatable with sorting/filtering. Any help on solving the issue would be greatly appreciated.
I'm not sure filterBy works with lazy datatables. I have a similar case that I've solved by using new Primefaces 10 Datatable syntax:
<p:datatable value="#{myView.lazymodel}" var="entry">
<p:column field="entry.user.name"/>
....
This way, Primefaces detects relationship and filtering works just fine.

How to use findByxxx in our custom repository

I want to use findByHostObjectId to query MyEnity, but it says "No property hostObjectId found for type MyEntity"
I have my Rest Controller and #autowired MyRepository and I want to use MyRepository.findByHostObjectId(hostObjectId) to get MyEntity by request parameter(hostObjectId).
Repository
public interface MyRepository extends PagingAndSortingRepository<MyEntity, MyEntityId> {
//success
MyEntity findById(#Param("id") MyEntityId id);
//fail
MyEntity findByHostObjectId(#Param("hostObjectId") Integer hostObjectId);}
MyEntity
public class MyEntity implements java.io.Serializable {
private MyEntityId id;
public MyEntity() {
}
public MyEntity(MyEntityId id) {
this.id = id;
}
#EmbeddedId
public MyEntityId getId() {
return this.id;
}
public void setId(MyEntityId id) {
this.id = id;
}}
MyEntityId
#Embeddable
public class MyEntityId implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private int objectId;
private Integer hostObjectId;
private String hostName;
public MyEntityId() {
}
public MyEntityId(int objectId, Integer hostObjectId, String hostName) {
this.objectId = objectId;
this.hostObjectId = hostObjectId;
this.hostName = hostName;
}
public int getObjectId() {
return this.objectId;
}
public void setObjectId(int objectId) {
this.objectId = objectId;
}
public Integer getHostObjectId() {
return this.hostObjectId;
}
public void setHostObjectId(Integer hostObjectId) {
this.hostObjectId = hostObjectId;
}
public String getHostName() {
return this.hostName;
}
public void setHostName(String hostName) {
this.hostName = hostName;
}}
MyEntiry.hbm.xml
<hibernate-mapping>
<class name="sud.MyEntity" table="sud_view_myentity">
<composite-id name="id" class="sud.MyEntityId">
<key-property name="objectId" type="int">
<column name="OBJECT_ID" />
</key-property>
<key-property name="hostObjectId" type="java.lang.Integer">
<column name="HOST_OBJECT_ID" />
</key-property>
<key-property name="hostName" type="string">
<column name="HOST_NAME" length="64" />
</key-property>
</composite-id>
</class>
</hibernate-mapping>
Have you tried using property expressions for nested properties like findByMyEntityId_HostObjectId? I am not sure if this will work because embeddable classes id is special case.
Take a look at the examples in the link
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.query-methods.query-property-expressions
Thanks very much
it works!!!
MyEntity findById_HostObjectId(#Param("hostObjectId") Integer hostObjectId);

JPA Cascade Persist Error

I have a One-to-Many relationship: A ProductCategory can contains many Product. This is the code:
#Entity
public class Product implements Serializable {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private String id;
#Column(name="ProductName")
private String name;
private BigDecimal price;
private String description;
#ManyToOne
#JoinColumn(name="UserId")
private User user;
#ManyToOne
#JoinColumn(name="Category")
private ProductCategory category;
private static final long serialVersionUID = 1L;
public Product() {
super();
}
public String getId() {
return this.id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getPrice() {
return this.price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public String getDescription() {
return this.description;
}
public void setDescription(String description) {
this.description = description;
}
public User getUser() {
return this.user;
}
public void setUser(User user) {
this.user = user;
}
public ProductCategory getCategory() {
return this.category;
}
public void setCategory(ProductCategory category) {
this.category = category;
}
}
#Entity
public class ProductCategory {
#Id
private String categoryName;
#OneToMany(cascade= CascadeType.ALL,mappedBy="category")
private List<Product> products;
public String getCategoryName() {
return categoryName;
}
public void setCategoryName(String productName) {
this.categoryName = productName;
}
public List<Product> getProducts() {
return products;
}
public void setProducts(List<Product> products) {
this.products = products;
}
}
This is Servlet code which use the 2 entities:
String name = request.getParameter("name");
BigDecimal price = new BigDecimal(request.getParameter("price"));
String description = request.getParameter("description");
ProductCategory category = new ProductCategory();
category.setCategoryName(request.getParameter("category"));
Product product = new Product();
product.setName(name);
product.setPrice(price);
product.setDescription(description);
product.setCategory(category);
User user = userManager.findUser("Meow");
product.setUser(user);
productManager.createProduct(product); // productManager is an EJB injected by container
And this is the error:
java.lang.IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST
Why does this error happen? I marked the field as "cascade = CascadeType.All"!
You're trying to save a product. And this product is linked to a category. So when JPA saves the product, its category must already exist, or there must be a cascade configured so that persisting the product cascades to persisting its category.
But you don't have such a cascade. What you have is a cascade saying that any operation done on a category cascades to its list of products.