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

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());
}

Related

How to build a Simple search page using Spring MVC?

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;
}

ebean query 2 models and render to html

I have setup 2 models in ebean, both work fine when queried separately. Now i need to get into my Show.scala.html fields from both my product & heading models, the product fields work fine but I also need the DateOrder from heading, but I am getting a compilation error of value DateOrder is not a member of object models.Heading, please help
My Models
package models;
import io.ebean.Finder;
import io.ebean.Model;
import play.data.validation.Constraints;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
#Entity
#Table(name="Heading")
public class Heading extends Model {
#Id
#Column(name="JobKeyID")
public Integer JobKeyID;
#Constraints.MaxLength(50)
#Constraints.Required
#Column(name="Name")
public String Name;
#Column (name="JobNumber", columnDefinition = "NVARCHAR")
public String JobNumber;
#Constraints.Required
#Column(name="SellingPriceIncTax")
public Integer SellingPriceIncTax;
#Constraints.Required
#Column(name="DateOrder")
public Date DateOrder;
#Column(name="CustomerID")
public Integer CustomerID;
#OneToMany(mappedBy = "heading", fetch = FetchType.EAGER)
public List<Product> product;
public static Finder<Integer, Heading> find = new Finder<>(Heading.class);
}
package models;
import io.ebean.Finder;
import io.ebean.Model;
import io.ebeaninternal.server.type.ScalarTypeJsonList;
import play.data.validation.Constraints;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
#Entity
#Table(name="Product")
public class Product extends Model {
#Id
#Column(name = "ItemKeyID")
public Integer ItemKeyID;
#Constraints.MaxLength(50)
#Constraints.Required
#Column(name = "ProductName")
public String ProductName;
#Column(name = "ItemNumber")
public Integer ItemNumber;
#Constraints.Required
#Column(name = "DesignName")
public String DesignName;
#Column(name = "JobKeyID")
public Integer JobKeyID;
#ManyToOne
#JoinColumn(name="JobKeyID")
public Heading heading;
#OneToMany(mappedBy = "product")
public List<Information> information;
public static Finder<Integer, Product> find = new Finder<>(Product.class);
}
My Controller
public Result show(Integer id){
List<Product> products = Ebean.find(Product.class)
.fetch("heading")
.where().eq("JobKeyID",id)
.setFirstRow(0)
.setMaxRows(10)
.findList();
return ok(show.render(products)) ;
}
and my scala.html
#(products : List[Product])
#Layout("All Books") {
<h1> All Books</h1>
#for(product <- products) {
<a class="btn btn-link" href="#routes.BooksController.specinfo(product.JobKeyID, product.ItemKeyID)">#product.ProductName</a>
<p> Design Name : #product.DesignName</p>
<p> Order Date : #Heading.DateOrder</p>
<img src ="#routes.ImagesController.getImage("419326-1.svg")"/>
}
}
You're trying to get field DateOrder via class, but it's not a static member. I believe it's the cause. If I understood your intention correctly, you should replace #Heading.DateOrder with #product.heading.DateOrder.

Convert Java object to BigQuery TableRow

I am exploring Google Cloud Dataflow.
I was wondering if automatic conversion between java object or JSON to TableRow can be done.
Just like we can automatically parse JSON to POJO class.
I could not find relevant information.
Hope not to duplicate question.
Will be grateful for any info!
Greetings
I've looking for examples for the same with no luck. I created a POJO class that almost match the schema of the bigquery table and matches the structure of the JSON objects that are the input for the pipeline. Finally, when I have to convert those objects to TableRow, for the nested and repeated values I made something like below, and the conversion was made by the API
TableRow row = new TableRow()
.set("items", c.element().getItems())
.set("orderDate", c.element().getOrderDate())
.set("orderNumber", c.element().getOrderNumber());
Where Item class is part of the Order object :
#JsonProperty("items")
private List<Item> items = null;
This is the code for Item class:
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#JsonInclude(JsonInclude.Include.NON_NULL)
#JsonPropertyOrder({
"id",
"code",
"detail",
"name",
"shortName",
"description",
"sku",
"quantity",
"category",
"products"
})
public class Item implements Serializable
{
#JsonProperty("id")
private Integer id;
#JsonProperty("code")
private String code;
#JsonProperty("detail")
private String detail;
#JsonProperty("name")
private String name;
#JsonProperty("shortName")
private String shortName;
#JsonProperty("description")
private String description;
#JsonProperty("sku")
private String sku;
#JsonProperty("quantity")
private Integer quantity;
#JsonProperty("category")
private Category category;
#JsonProperty("products")
private List<Product> products = null;
#JsonIgnore
private Map<String, Object> additionalProperties = new HashMap<String, Object>();
private final static long serialVersionUID = -5644586446669059821L;
#JsonProperty("id")
public Integer getId() {
return id;
}
#JsonProperty("id")
public void setId(Integer id) {
this.id = id;
}
#JsonProperty("code")
public String getCode() {
return code;
}
#JsonProperty("code")
public void setCode(String code) {
this.code = code;
}
#JsonProperty("detail")
public String getDetail() {
return detail;
}
#JsonProperty("detail")
public void setDetail(String detail) {
this.detail = detail;
}
#JsonProperty("name")
public String getName() {
return name;
}
#JsonProperty("name")
public void setName(String name) {
this.name = name;
}
#JsonProperty("shortName")
public String getShortName() {
return shortName;
}
#JsonProperty("shortName")
public void setShortName(String shortName) {
this.shortName = shortName;
}
#JsonProperty("description")
public String getDescription() {
return description;
}
#JsonProperty("description")
public void setDescription(String description) {
this.description = description;
}
#JsonProperty("sku")
public String getSku() {
return sku;
}
#JsonProperty("sku")
public void setSku(String sku) {
this.sku = sku;
}
#JsonProperty("quantity")
public Integer getQuantity() {
return quantity;
}
#JsonProperty("quantity")
public void setQuantity(Integer quantity) {
this.quantity = quantity;
}
#JsonProperty("category")
public Category getCategory() {
return category;
}
#JsonProperty("category")
public void setCategory(Category category) {
this.category = category;
}
#JsonProperty("products")
public List<Product> getProducts() {
return products;
}
#JsonProperty("products")
public void setProducts(List<Product> products) {
this.products = products;
}
#JsonAnyGetter
public Map<String, Object> getAdditionalProperties() {
return this.additionalProperties;
}
#JsonAnySetter
public void setAdditionalProperty(String name, Object value) {
this.additionalProperties.put(name, value);
}
}
And this is the schema of the BigQuery table in regards Items, where Item is a RECORD and REPEATED field and also contain a nested RECORD and REPEATED field: products. See the screenshot of the schema
Item schema fields in BQ

Generator not incrementing in strategy=GenerationType.TABLE in jpa

i am using a strategy=GenerationType.TABLE on my Employee table and i defined a generator using #TableGenerator(name="Empl_Gen", table="ID_GEN",pkColumnName="GEN_NAME",valueColumnName="GEN_VALUE") and specified the generator in #GeneratedValue(generator="Emp_Gen") using the name of the generator which is "Empl_Gen". when the application starts up , it creates a table named "ID_GEN" but the table dont contain any Generator of the name ""Empl_Gen".Infact it will create a generator "EMPLOYEE" which is same as my entity class name. Also the value of the ""GEN_VALUE" doesnt get incremented when persisting the employee entity.The ids for the employee are generated randomly too..
package com.test.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.TableGenerator;
#Entity
public class Employee {
#TableGenerator(name="Empl_Gen", table="ID_GEN",pkColumnName="GEN_NAME",valueColumnName="GEN_VALUE")
#Id#GeneratedValue(generator="Empl_Gen",strategy=GenerationType.TABLE)
private Long id;
private String Name;
private String Country;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getCountry() {
return Country;
}
public void setCountry(String country) {
Country = country;
}
}

entity association in java

I am trying to get rid of this error:
Exception Description: [class utilisateurs.modeles.Utilisateur] uses a non-entity [class java.util.Collection] as target entity in the relationship attribute [field adresses].
at org.eclipse.persistence.exceptions.ValidationException.nonEntityTargetInRelationship(ValidationException.java:1343)
.........
org.eclipse.persistence.internal.jpa.deployment.PersistenceUnitProcessor.processORMetadata(PersistenceUnitProcessor.java:526)
at org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl.predeploy(EntityManagerSetupImpl.java:1320)
... 36 more
with the following entity:
utilisateurs.modeles;
import adresses.Adresse;
import java.io.Serializable;
import java.util.Collection;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
#Entity(name="Utilisateur")
public class Utilisateur implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
public void setAdresses(Collection<Adresse> adresses) {
this.adresses = adresses;
}
private String firstname;
private String lastname;
private String login;
#ManyToOne(cascade=CascadeType.PERSIST)
private Collection<Adresse> adresses;
public Collection<Adresse> getAdresses() {
return adresses;
}
public Utilisateur() {
}
public Utilisateur(final String firstname, final String lastname, final String login) {
this.firstname = firstname;
this.lastname = lastname;
this.login = login;
}
//getters and setters here
#Override
public int hashCode() {
int hash = 0;
hash += (int) id;
return hash;
}
#Override
public boolean equals(Object object) {
// TODO: Warning - this method won't work in the case the id fields are not set
if (!(object instanceof Utilisateur)) {
return false;
}
Utilisateur other = (Utilisateur) object;
if (this.id != other.id) {
return false;
}
return true;
}
}
If you have any idea please.
Adresse is not an Entity, maybe you just forgot the #Entity annotation on that class?
The #ManyToOne annotation defines a relationship between entities.