Java CriteriaBuilder Join - cannot be solved or is not a field - java

I'm trying to do a select using a join in CriteriaBuilder, but I'm getting this error in Eclipse. How can I fix it?
Hibernate version: hibernate-jpa-2.0-api<br />
Java Version: 1.8
fonte cannot be solved or is not a field
NotificacaoDao.java
#Stateless
public class NotificacaoDao {
#PersistenceContext(unitName = "PostgreSQLDS")
private EntityManager em;
#EJB
private NotificacaoDao NotificacaoDao;
public List<Notificacao> getResultList(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) throws ApplicationException{
try {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Notificacao> cq = cb.createQuery(Notificacao.class);
Metamodel m = em.getMetamodel();
EntityType<Notificacao> Notificacao_ = m.entity(Notificacao.class);
Root<Notificacao> myObj = cq.from(Notificacao_);
Join<Notificacao, Fonte> fontes = myObj.join(Notificacao_.fonte); // HERE I'M GETTING THE ERROR
cq.where(NotificacaoDao.getFilterCondition(cb, myObj, filters));
Predicate filterCondition = NotificacaoDao.getFilterCondition(cb, myObj, filters);
filterCondition = cb.and(filterCondition, cb.equal(myObj.get("excluido"), "N"));
cq.where(filterCondition);
if (sortField != null) {
if (sortOrder == SortOrder.ASCENDING) {
cq.orderBy(cb.asc(myObj.get(sortField)));
} else if (sortOrder == SortOrder.DESCENDING) {
cq.orderBy(cb.desc(myObj.get(sortField)));
}
}
return em.createQuery(cq).setFirstResult(first).setMaxResults(pageSize).getResultList();
} catch(Exception e) {
throw new ApplicationException("myException", e);
}
}
Notificacao.java
#Entity
#Table(name = "tb_notificacao", schema = "indicadores")
#NamedQuery(name = "Notificacao.findAll", query = "SELECT n FROM Notificacao n")
#FilterDef(name="notificacaoNaoExcluido", defaultCondition="excluido = 'N'")
public class Notificacao implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "tb_notificacao_codnotificacao_seq", sequenceName = "TB_NOTIFICACAO_CODNOTIFICACAO_SEQ", schema = "indicadores", allocationSize = 1)
#GeneratedValue(generator = "tb_notificacao_codnotificacao_seq")
#Column(name = "codnotificacao", nullable = false)
private Integer codnotificacao;
private String descricao;
private String excluido;
private String nome;
// bi-directional many-to-one association to CargaNotificacao
#OneToMany(mappedBy = "notificacao")
private List<CargaNotificacao> cargaNotificacoes;
// bi-directional many-to-one association to Fonte
#Inject
#ManyToOne
#JoinColumn(name = "codfonte")
private Fonte fonte;
// bi-directional many-to-one association to UsuarioNotificacao
#OneToMany(mappedBy = "notificacao")
#Filter(name="usuarioNaoExcluido", condition="excluido = 'N'")
private List<UsuarioNotificacao> usuarioNotificacoes;
public Notificacao() {
}
// getters and setters
}
Fonte.java
#Entity
#Table(name = "tb_fonte", schema = "indicadores")
#NamedQuery(name = "Fonte.findAll", query = "SELECT f FROM Fonte f")
public class Fonte implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#SequenceGenerator(name = "tb_fonte_codfonte_seq", sequenceName = "TB_FONTE_CODFONTE_SEQ", schema = "indicadores", allocationSize = 1)
#GeneratedValue(generator = "tb_fonte_codfonte_seq")
#Column(name = "codfonte", nullable = false)
private Integer codfonte;
private String nome;
// bi-directional many-to-one association to Indicador
#OneToMany(mappedBy = "fonte")
#Filter(name="indicadorNaoExcluido", condition="excluido = 'N'")
private List<Indicador> indicadores;
// bi-directional many-to-one association to Notificacao
#OneToMany(mappedBy = "fonte")
#Filter(name="notificacaoNaoExcluido", condition="excluido = 'N'")
private List<Notificacao> notificacoes;
public Fonte() {
}
// getters and setters
}

Well, on Metamodels there are basically three approaches to use:
Using IDE based metamodel generation tools
Using Static Canonical Metamodel Classes
Using em.getMetamodel() API i.e. the one you are using.
The solution I am proposing for you to use which is closer to what you were doing is on Point 3.
Point 3 Solution :
Replace the below code :
Metamodel m = em.getMetamodel();
EntityType<Notificacao> Notificacao_ = m.entity(Notificacao.class);
Root<Notificacao> myObj = cq.from(Notificacao_);
Join<Notificacao, Fonte> fontes = myObj.join(Notificacao_.fonte); // HERE I'M GETTING THE ERROR
With new code :
Metamodel m = em.getMetamodel();
EntityType<Notificacao> notificacao_ = m.entity(Notificacao.class);
Root<Notificacao> myObj = cq.from(notificacao_);
Join<Notificacao, Fonte> fontes = myObj.join(notificacao_.getSingularAttribute("fonte",Fonte.class));
Points 1 & 2 Solutions
Please note the Notificacao_ must be a class either static or generated and must never be an instance of em.getMetamodel(). Also note in your case before Notificacao_ was a variable instead of a class as shown:
EntityType<Notificacao> Notificacao_ = m.entity(Notificacao.class);
If you need more info, let me know please.

Related

Spring JPA Criteria API Query on OneToMany List Field

I want to load all the CustomerRequests for a specific Customer with the JPA/Hibernate Criteria API.
In specific: I want to load all the CustomerRequest for which a CustomerRequest2Customer entry with a specific customerId exists.
#Entity
public class CustomerRequest {
#Id
private int id;
private int priority;
#OneToMany(mappedBy = "customerRequestId")
private List<CustomerRequest2Customer> listCustomerRequestToCustomer; // <- Query this field
}
#Entity
public class CustomerRequest2Customer {
#Id
private int id;
#ManyToOne
private Customer customer; // <- Query this field
#ManyToOne
private CustomerRequest customerRequest;
}
#Entity
public class Customer {
#Id
private int id; // <- Query this field
private String name;
}
How I currently query other fields:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<CustomerRequest> cq =
cb.createQuery(CustomerRequest.class);
Root<CustomerRequest> root = cq.from(CustomerRequest.class);
cq.where(cb.equal(root.get("priority"), 1));
return entityManager.createQuery(cq).getResultList();
You have to join the entities like this:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<CustomerRequest> cq = cb.createQuery(CustomerRequest.class);
Root<CustomerRequest> root = cq.from(CustomerRequest.class);
Join<CustomerRequest, CustomerRequest2Customer> customerRequest2Customer = root.join("listCustomerRequestToCustomer");
Join<CustomerRequest2Customer, Customer> customer = customerRequest2Customer .join("customer");
cq.where(cb.equal(customer .get("id"), 1));
return entityManager.createQuery(cq).getResultList();

How to set value of related entities(objects)

I have two entity that have a relation,The relationship works fine, but how can I set value from one object to another in controller.
#Entity
#Table(name = "material_manu_calculator")
public class MaterialManuCalcu {
#Id
#GeneratedValue
#Column(name = "no")
private int no;
#ManyToOne
#JoinColumn(name = "order_id")
private OrderProductManu orderProductManu;
//.....getters and setters and constructors}
Below is the second Entity
#Entity
#Table(name = "orders_products_manu")
public class OrderProductManu {
#Id
#GeneratedValue
#Column(name = "order_id")
private int orderManuId;
#OneToMany(cascade = CascadeType.ALL,mappedBy = "orderProductManu")
private List<MaterialManuCalcu> materialCalcu = new ArrayList<>();
//.....getters and setters and constructors}
below is the Repository
#Repository
#Transactional
public interface OrderProductManuRepository extends JpaRepository <OrderProductManu, Integer> {
#Query(value ="SELECT *FROM orders_products_manu WHERE orders_products_manu.order_id =?", nativeQuery = true)
public OrderProductManu getOrderProductById(int id);
}
I want to set the value of MaterilaManuCalcu in controller as below
#Controller
public class ProductsController {
#Autowired
private OrderProductManuRepository orderRepo;
OrderProductManu orderProduct = orderRepo.getOrderProductById(1);
MaterialManuCalcu manCalc = new MaterialManuCalcu();
manCalc.setOrderProductManu(orderProduct.getOrderManuId());
// I get the error says:
// The method setOrderProductManu(OrderProductManu) in
// the type MaterialManuCalcu is not applicable for the arguments (int)
Update: Constructors
public MaterialManuCalcu(int no, int amountOrdered, int amountAvailable, int amountWillRemain,
MaterialManu materialmanu, OrderProductManu orderProductManu) {
this.no = no;
this.amountOrdered = amountOrdered;
this.amountAvailable = amountAvailable;
this.amountWillRemain = amountWillRemain;
this.materialmanu = materialmanu;
this.orderProductManu = orderProductManu;
}
Another one
public OrderProductManu(int orderManuId, String customerName, int amountOrderedManu, String dateOrdered, Users users,
ProductsManu productsManu) {
this.orderManuId = orderManuId;
this.customerName = customerName;
this.amountOrderedManu = amountOrderedManu;
this.dateOrdered = dateOrdered;
this.users = users;
this.productsManu = productsManu;
}
Update:Showing how both entities are created
For : OrderProductManu
OrderProductManu orderProduct = new OrderProductManu();
orderProduct.setDateOrdered("2021-04-14");
orderProduct.setAmountOrderedManu(platenum);
orderProduct.setCustomerName("Wapili Mteja");
orderProduct.setUsers(userMoja.get(0));
orderProduct.setProductsManu(typeofProduct);
orderProductManus.setOrderManuId(007);//this is the value that I want to set inside
//MateriaManCalcu entity for property setOrderProductManu
//You can check the relationship above
For: MaterialManuCalcu
MaterialManuCalcu manCalc = new MaterialManuCalcu();
manCalc.setAmountAvailable(availableSheets);
manCalc.setAmountOrdered(sheetsNum);
manCalc.setAmountWillRemain(sheetWillRemain);
manCalc.setMaterialmanu(materialSheet);
manCalc.setOrderProductManu(orderProduct);//doing this the whole object of
//orderProduct entity goes inside a one column in our MatrialManuCalcuof entity
Table:material_manu_calculator
How should I do this correctly. Thanks in advance.
You are trying to set id of orderProduct which is returned by calling orderProduct.getOrderManuId() of type int to variable of type OrderProductManu.
Just pass your orderProduct like this manCalc.setOrderProductManu(orderProduct)

Unable to locate Attribute with the the given name [XXX] on this ManagedType [unknown]

I have this entity with its ID defined in Identifiable class.
InventoryLoad has InventoryLoadID as its PK
public class InventoryLoad extends AbstractIdentifiable<InventoryLoadId> implements Auditable {
    #OneToMany(mappedBy = "inventoryLoad")
    private Set<InventorySubLoad> inventorySubLoads = Sets.newLinkedHashSet();
    #ManyToOne(fetch = FetchType.LAZY, optional = false)
    #JoinColumns({
            #JoinColumn(name = "stoloc", referencedColumnName = "stoloc"),
            #JoinColumn(name = "wh_id", referencedColumnName = "wh_id")
    })
   private Location location;
    #Column(name = "lodwgt")
    private Double loadWeight;
    #Column(name = "prmflg")
    private Boolean permanentLoadSubFlag;
}
This is the ID for above class
#Embeddable
public class InventoryLoadId extends AbstractIdentifiableId {
   private static final long serialVersionUID = 1L;
    #Column(name = "lodnum")
    private String loadNumber;
// some another code below
}
I am using Criteria builder to get to the column of ID class.
To get this using Path to get the path of inventoryid that is PK.
Session session = new HibernateTools().getSession();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class);
Root<InventoryLoad> inventoryLoadRoot = criteriaQuery.from(InventoryLoad.class);
Path<InventoryLoadId> inventoryLoadIdPath = inventoryLoadRoot.get("id");
criteriaQuery.multiselect(inventoryLoadIdPath.get("loadNumber"),
Getting this error
Unable to locate Attribute  with the the given name [loadNumber] on this ManagedType [unknown]
Criteria in hibernate work fine with JPA static metamodel. Try to use it
#Embeddable
public class InventoryLoadId extends AbstractIdentifiableId {
private static final long serialVersionUID = 1L;
#Column(name = "lodnum")
private String loadNumber;
}
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(InventoryLoadId.class)
public abstract class InventoryLoadId_ {
public static volatile SingularAttribute<InventoryLoadId, String> loadNumber;
}
Session session = new HibernateTools().getSession();
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
// create the query
CriteriaQuery<InventoryLoadId> query = criteriaBuilder.createQuery(InventoryLoadId.class);
// set the root class
Root<InventoryLoadId> inventoryLoadRoot = query.from(InventoryLoadId.class);
query.multiselect(inventoryLoadRoot.get(InventoryLoadId_.loadNumber).alias("loadNumber"));

Right join using JPA criteria api

I'm trying to implement this sql query using jpa criteria api :
SELECT F.* FROM PF right join F on F.FID = PF.FID WHERE PF.PFID is null;
Which also can be written as:
SELECT F.* FROM F left join PF on F.FID = PF.FID WHERE PF.FID is null;
This is what I tried:
public List<F> listFWithoutP() {
final CriteriaBuilder builder = getCriteriaBuilder();
final CriteriaQuery<F> query = builder.createQuery(F.class);
final Root<PF> from = query.from(PF.class);
Join<PF, F> join = from.join(PF_.f, JoinType.RIGHT);
query.select(join.get(PF_.f))
.where(builder.isNull(from.get(PF_.pFId)));
final TypedQuery<F> typedQuery = getEntityManager().createQuery(query);
return typedQuery.getResultList();
}
But it doesn't work, I get the following error in this line : query.select(join.get(PF_.f))
The method get(SingularAttribute<? super F,Y>) in the type Path<F> is not applicable for the arguments (SingularAttribute<PF,F>)
How can I solve this ?
Update:
These are my entities :
public class F extends AbstractDomain<Long> {
#Id
#Column
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "idgen")
private Long fId;
#Column(nullable = false)
private String lib;
}
public class PF extends AbstractDomain<Long> {
#Id
#Column
private Long pFId;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(nullable = false)
private P p;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(nullable = false)
private F f;
}
Update 2:
It seems like RIGHT JOIN is not supported by the jpa criteria api, so this can be done using the second query.
final Session session = entityManager.unwrap(Session.class);
final Criteria criteria = session.createCriteria(PF.class, "pf")
.createAlias("pf.f", "f")
.add(Restrictions.eqProperty("pf.pFId",
"f.fId"))
.add(Restrictions.isNull("pf.pFId"));
Hello Aimad,
please try this criteria query and let me know if that works,this criteria would exactly replicate your SQL query.

Logical OR between a Criterion and Criteria

I have the following model classes:
#Entity
#Table(name = "title")
public final class Title extends ModelData<Title>
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer titleID;
#Column(name = "title")
private String title;
#Column(name = "description")
private String description;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "title")
private Set<Book> books;
}
#Entity
#Table(name = "book")
public final class Book extends ModelData<Book>
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "bookID")
private int bookID;
#ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
#JoinColumn(name = "titleID")
private Title title;
#Column(name = "edition")
private Integer edition;
#Column(name = "isbn")
private String ISBN;
}
I want to write a Criteria query that is equivalent to the following SQL;
Select
t.title, b.edition
from
books b, title t
where
b.titleID = t.titleID
and
(b.edition=4 OR t.title LIKE '%Java%);
I tried the following:
Criteria c = session.createCriteria(Book.class);
Criteria titleCriteria = c.createCriteria("title");
titleCriteria.add(Restrictions.like("title", "%Java%");
Criterion edition = Restrictions.eq("edition", 4);
LogicalExpression orExp = Restrictions.or(edition, titleCriteria); //cannot do this
How do I achieve the above?
Thanks.
public class MyDTO {
private String dtoTitle;
private String dtoEdition;
// + setters/getters
}
Criteria c = session.createCriteria(Book.class,"b");
c.createAlias("title", "t");
c.add(
Restrictions.disjunction()
.add( Restrictions.like("t.title", "%Java%") )
.add( Restrictions.eq("b.edition", 4) )
);
c.setProjection(
Projections.projectionList()
.add( Projections.property("t.title"), "dtoTitle" )
.add( Projections.property("b.edition"), "dtoEdition" )
);
c.setResultTransformer(Transformers.aliasToBean(MyDTO.class));
List<MyDTO> result = (List<MyDTO>)c.list();
Something like this should work fine.
On dao using many criterias you should consider using static imports.
Another idea
Convert yout criteria to formula field and evaluate as normal criterios
Add formula field to mapping file, or annotations to your classes
<property name="titlename" type="string"
formula="(Select title.title from title
where title.titleID= titleID)"/>
then
Criteria c = session.createCriteria(Book.class)
Criteria titleCriteria = c.createCriteria("title");
titleCriteria.add(Restrictions.like("titlename", "%Java%");
Criterion edition = Restrictions.eq("edition", 4);
LogicalExpression orExp = Restrictions.or(edition, titleCriteria); //CAN< do this!!!
I think you want this. I haven't tested it, so there may be some minor errors, but the basic idea is correct.
Criteria c = session.createCriteria(Book.class);
Criterion titleCriterion = Restrictions.like("title.title", "%Java%");
Criterion edition = Restrictions.eq("edition", 4);
c.add( Restrictions.or( edition, titleCriterion ));
For more than 2 OR conditions it's more readable to use:
c.add(
Restrictions.disjunction()
.add(Restrictions.eq(...))
.add(Restrictions.eq(...))
.add(Restrictions.eq(...))
)

Categories

Resources