ebean query 2 models and render to html - scala

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.

Related

How to select particular column from different Table using Spring Data JPA Join

I am trying to access particular column from different table using Spring Data JPA Inner Join.
I created four model. AccountModel is main model.
i used manyToOne mapping in AccountModel to the other three model(DepartmentModel,AccountCPCMappingModel,InvestigatorModel). I am trying to access particular column from four table using native Query in AccountRepository
This is my application scenario.
1.AccountModel.java
package com.demo.model;
import java.io.Serializable;
import java.sql.Timestamp;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
#Entity
#Table(name="account")
public class AccountModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
public Integer naccountid;
public String namount;
public String sacctdesc;
public Integer naccountcpcmappingid;
public Integer nindirectcostrate;
public Integer nagencyid ;
public Integer ndeptid ;
public String sgrantnum;
public Timestamp dstartdate;
public Timestamp denddate;
public String slocation;
public String sclientacctid;
public Integer ninvestigatorid;
public Integer ninstid;
public Integer ntempaccountid;
#ManyToOne(optional = true)
#JoinColumn(name="ndeptid",insertable = false, updatable = false)
public DepartmentModel department;
#ManyToOne(optional = true)
#JoinColumn(name="ninvestigatorid",insertable = false, updatable = false)
public InvestigatorModel investigator;
#ManyToOne(optional = false)
#JoinColumn(name="naccountcpcmappingid",insertable = false, updatable = false)
public AccountCPCMappingModel accountCPC;
//...Getter and Setter
}
2 DepartmentModel
package com.demo.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name = "department")
public class DepartmentModel implements Serializable {
private static final long serialVersionUID = 1L;
#Id
public Integer ndeptid;
public String sdeptname ;
public Integer ninstid ;
public Boolean bislocked;
public String sclientdeptid;
public Integer nsurveymethodid;
public Boolean bisjointuse;
public Integer ntempdeptid;
public Boolean balternatejointusepercentage;
public Integer ndivid;
//...Getter and Setter
3.InvestigatorModel
package com.demo.model;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
#Entity
#Table(name="investigator")
public class InvestigatorModel implements Serializable{
private static final long serialVersionUID = 1L;
#Id
public Integer ninvestigatorid;
public String sinvestigatorname;
public Integer ninstid ;
public String stitle;
public Integer ntempinvestigatorid;
public Integer nempid;
AccountRepository
package com.demo.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import com.demo.model.AccountModel;
#Repository
public interface AccountRepository extends JpaRepository<AccountModel, Integer>{
#Query(value="select acct.sclientacctid,acct.sacctdesc,acct.slocation,invest.sinvestigatorname, \r\n" +
"dept.sclientdeptid,dept.sdeptname,acp.sccpcode \r\n" +
"from Account acct join Department dept on acct.nDeptID=dept.nDeptID \r\n" +
"join Investigator invest on acct.nInvestigatorID=invest.nInvestigatorID \r\n" +
"join AccountCPCMapping acp on acct.nAccountCPCMappingID=acp.nAccountCPCMappingID \r\n" +
"where acct.nInstID=60 \r\n" +
"order by acct.sclientacctid Asc",nativeQuery=true)
List<Object[]> findByNaccountid();
}
AccountService
package com.demo.services;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.demo.model.AccountModel;
import com.demo.repository.AccountRepository;
#Service
public class AccountService {
#Autowired
AccountRepository accRepo;
public List<AccountModel> findLocation()
{
return accRepo.findBySlocation();
}
public Set<Object[]> gridLoad()
{
Set<Object[]> gridObj=accRepo.findByNaccountid();
return gridObj;
}
}
AccountController
package com.demo.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.demo.model.AccountModel;
import com.demo.services.AccountService;
#RestController
#RequestMapping("/SpaceStudy/SpaceAdmin")
public class AccountController
{
#Autowired
AccountService accService;
#CrossOrigin(origins="*")
#GetMapping("/AccountMaintenance/LoadLocation")
public List<AccountModel> findLocation()
{
return accService.findLocation();
}
#CrossOrigin(origins="*")
#PostMapping("/AccountMaintenance/LoadGrid")
public Set<Object[]> GridLoad()
{
return accService.gridLoad();
}
}
I am getting output in this format
But I want output in JSON Format like this (key,value pairs)
sample output
[
{
"userId": 1,
"id": 1
}
]
Can any one help me what i need to change in my code for json data.
Your query should return List<Object[]> and not List<AccountModel>.
JPA equivalent query will be something like this.
Query("select acct.sclientacctid,acct.sacctdesc,acct.slocation,invest.sinvestigatorname, dept.sclientdeptid,dept.sdeptname,acp.sccpcode
from AccountModel acct join acct.department dept join acct.investigator invest join acct.accountCPC acp
where acct.nInstID= :instId
order by acct.sclientacctid")
List<Object[]> findByInstId (#Param("instId") Integer instId);
This will return you a List of Object array and the array will have the columns in order it appears in the select. Give it a try.

#ManyToOne seems not working as i expect it to be

I'm working with many-to-one relationship between my two tables(Employee and Department) in which any Employee can work in more than one department. I used the #ManyToOne annotation on the Department object field which I created in Employee entity class. Now when I persist the Employee entity with a particular department, it works fine but when I try to persist another Employee entity with the same department, it creates a new Department entity with the same name and persists it with different id. What I expect it to do is that when I persist an Employee entity with already persisted department, it should just update the foriegn key of the Employee entity to point the id of that department. Sorry if I didnt got the many-to-one concept totally.
EMPLOYEE entity
package com.test.domain;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.TableGenerator;
#Entity
public class Employee {
#TableGenerator(name="Empl_Gen", table="ID_GEN",pkColumnName="GEN_NAME",valueColumnName="GEN_VALUE", initialValue=0, allocationSize=1)
#Id#GeneratedValue(generator="Empl_Gen",strategy=GenerationType.TABLE)
private Long id;
private String Name;
private String Country;
#ManyToOne(cascade=CascadeType.ALL)
#JoinColumn(name="DEPT_ID")
private Department department;
public Department getDepartment() {
return department;
}
public void setDepartment(Department department) {
this.department = department;
}
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;
}
}
DEPARTMENT entity
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 Department {
#TableGenerator(name="DEP_GEN",table="ID_GEN",pkColumnName="GEN_NAME",valueColumnName="GEN_VALUE", pkColumnValue="DEP_GEN",initialValue=0,allocationSize=1)
#Id#GeneratedValue(strategy=GenerationType.TABLE,generator="DEP_GEN")
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.test.controllers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.test.domain.Employee;
import com.test.service.EmployeeService;
/**
* Handles requests for the application home page.
*/
#Controller
#RequestMapping("/addEmployee")
public class HomeController {
#Autowired
EmployeeService service;
#RequestMapping(method=RequestMethod.GET)
public String getform(Model model)
{
model.addAttribute("employee",new Employee());
return "home";
}
#RequestMapping(method=RequestMethod.POST)
public String setform(Employee employee)
{
service.save(employee);
return"success";
}
}
package com.test.dao;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.test.domain.Employee;
#Repository
#Transactional
public class Employeedaoimpl implements Employeedao
{
#PersistenceContext
EntityManager manager;
#Override
public void save(Employee employee) {
manager.persist(employee);
}
}
Try this:
#TableGenerator(name="DEP_GEN",table="ID_GEN",pkColumnName="GEN_NAME",valueColumnName="GEN_VALUE", pkColumnValue="DEP_GEN",initialValue=0,allocationSize=1)
#Id#GeneratedValue(strategy=GenerationType.TABLE,generator="DEP_GEN")
#Column(name = "DEPT_ID")
private Long id;

Convert String or int To Enum in JPA

I don't know how I can persist an entity(with enum) to the database.
When I fill my form like this;
form.setTypZamowienia(SlownikZamowienie.SENIOR)
then 666 is stored in the database. But when I try like this;
form.setTypZamowienia(SlownikZamowienie.valueOf(request.getParameter("typKlienta").trim()));
0 is stored in the database.
How do I make this work?
For any help I will be very grateful.
My enum :
public enum SlownikZamowienie
{
JUNIOR(42),
SENIOR(666),
PRINCIPAL(31416);
private final int wartosc;
SlownikZamowienie(int wartosc) {
this.wartosc = wartosc;
}
}
My Entity:
package test.jpa.domain;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import test.enums.SlownikZamowienie;
#Entity
#Table(name="Piess")
public class Pies implements Serializable {
private static final Long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#Column(name="id")
int id;
#Column(name = "imie")
String imie;
#Enumerated
#Column(name = "rasa")
SlownikZamowienie typzamowienia;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getImie() {
return imie;
}
public void setImie(String imie) {
this.imie = imie;
}
public SlownikZamowienie getTypzamowienia() {
return typzamowienia;
}
public void setTypzamowienia(SlownikZamowienie typzamowienia) {
this.typzamowienia = typzamowienia;
}
}
As of JPA 2.1 you can use an attribute converter (known as a UserType in the Hibernate world). See these two articles for details on how to implement such a solution:
www.thoughts-on-java.org/jpa-21-type-converter-better-way-to/
www.thoughts-on-java.org/jpa-21-how-to-implement-type-converter/

Play Framework: Inheritance sort by type

In my Application, I have 2 Classes:
- Group
- Model
and one base class Element.
I use the single table strategy to persist these models. (strategy = InheritanceType.SINGLE_TABLE). Thus a column dtypeis created in my table.
I'm now trying to sort my pages based on this type:
find.where().disjunction()
.add(Expr.ilike("name", "%" + filter + "%"))
.orderBy("dtype asc, name asc," + sortBy + " " + order).findList()
But this throws an Exception, that dtype cannot be found.
How can I sort based on the type?
Thanks!
Sample base model can look like:
package models.db;
import play.db.ebean.Model;
import javax.persistence.*;
import java.util.Date;
#Entity
#Table(name = "content")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "dtype", discriminatorType = DiscriminatorType.STRING)
#DiscriminatorValue("content")
public abstract class Content extends Model {
#Id
public Long id;
#Column(name = "dtype", insertable = false, updatable = false)
public String dtype;
public static Finder<Long, Content> find = new Finder<>(Long.class, Content.class);
public String title;
public Date created = new Date();
public Date modified = new Date();
}
Then you can extend it like:
package models.db;
import javax.persistence.*;
#Entity
#DiscriminatorValue("news")
public class News extends Content {
#Id
public Long id;
public static Finder<Long, News> find = new Finder<>(Long.class, News.class);
public String newsSource;
}
or
package models.db;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.util.Date;
#Entity
#DiscriminatorValue("post")
public class Post extends Content {
#Id
public Long id;
public static Finder<Long, Post> find = new Finder<>(Long.class, Post.class);
public Date publishDate;
}
So you can choose all contents via:
List<Content> contents = Content.find.where().orderBy("dtype ASC").findList();
Of course these objects will have only shared fields: id, dtype, title, created and modified, for getting i.e. (News) newsSource or (Post) publishDate you need to get these objects with their own finders i.e. using id value from general Content query.

JPA Transparent Indirection and Container Policies

Suppose I have the following simple Customer/Order implementation:
A record of customers defined by a Customer class.
Each customer can have multiple orders defined by an Order class.
Drawing on the explanation of Transparent Indirection from here and Container Policies from here my understanding of these concepts EclipseLink is as follows:
Transparent Indirection allows me to say
Customer customer = Customer.getCustomerById(1);
Set<Order> orders = customer.getOrders();
Two points to note are:
Indirection allows lazy loading of attributes so a customer's orders are only fetched from the DB on line 2, not line 1.
I can treat the orders of a customer as a Set (or Collection or List or Map) of objects of type Order.
The Container Policy tells to EclipseLink which actual class should be used for the Set and it should therefore implement Set in the example above.
That is my understanding of Transparent Indirection and Container Policies in EclipseLink.
I am seeing the following error when I try to access the database:
Exception [EclipseLink-148] (Eclipse Persistence Services - 2.3.0.v20110604-r9504): org.eclipse.persistence.exceptions.DescriptorException
Exception Description: The container policy [CollectionContainerPolicy(class org.eclipse.persistence.indirection.IndirectSet)] is not compatible with transparent indirection.
Mapping: org.eclipse.persistence.mappings.OneToManyMapping[orders]
Descriptor: RelationalDescriptor(my.model.Customer --> [DatabaseTable(Customer)])
I'm sure I have an error in my code somewhere which I am trying to debug but I didn't specify the CollectionContainerPolicy mentioned in the error so I assume org.eclipse.persistence.indirection.IndirectSet is the default. But if I'm using the default policy then I'm not sure what the cause of this error may be or which policy I should be using.
For now, I'd just like to know if my understanding of Transparent Indirection and Container Policies as I mentioned above is correct.
If it is correct I'm probably missing something relatively small in my code (an invocation or configuration option etc.) but if I'm not understanding the concepts then clearly I need to do more research first.
Customer model
package my.model;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
/**
* The persistent class for the customer database table.
*
*/
#Entity
#Table(name=Customer.TBL_NAME)
#NamedQueries({
#NamedQuery(name=Customer.QRY_BY_NAME,query="Select object(a) from Customer a where " +
"a.name=:" + Customer.PRM_NAME),
#NamedQuery(name=Customer.QRY_ALL, query="select object(a) from Customer a")
})
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
// Table specific onstants
public static final String TBL_NAME = "Customer";
public static final String QRY_BY_NAME = TBL_NAME + ".byName";
public static final String QRY_ALL = TBL_NAME + ".all";
public static final String PRM_NAME = "name";
private int id;
private String name;
private Set<Order> orders;
public Customer() {
}
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
//bi-directional many-to-one association to Order
#OneToMany(mappedBy="customer")
public Set<Order> getOrders() {
return this.orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
}
Order model
package my.model;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
/**
* The persistent class for the order database table.
*
*/
#Entity
#Table(name=Order.TBL_NAME)
public class Order implements Serializable {
private static final long serialVersionUID = 1L;
// Table constants
public static final String TBL_NAME = "Order";
private int id;
private Customer customer;
public Order() {
}
#Id
public int getId() {
return this.id;
}
public void setId(int id) {
this.id = id;
}
//bi-directional many-to-one association to Customer
#ManyToOne
public Customer getCustomer() {
return this.customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
Your understanding is correct, but shouldn't be needed as this isn't something you need to configure when using JPA. EclipseLink will determine the collection policy and implementation to use based on the type of the property and the lazy/eager setting, and it seems to be doing so correctly. The exception is thrown in error, probably due to classloader issues so that the classloader used for init isn't the one used to validate against, but I don't know how that could happen. You will need to look at the environment this is running in as the exception itself is just a symptom