Selecting from a list using JPA Query - java

I am very new to JPA and have the following entities defined
public class CustomerOrders {
#Column(name = "CUSTOMER_ID", nullable = false)
private Long customerId;
#OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true)
#JoinColumn(name = "ORDER_ID", nullable = false)
private List<Order> orders;
}
public class Order {
#Column(name = "ORDER_ID", nullable = false)
private Long orderId;
#Column(name = "AMOUNT", precision = 16, scale = 2, nullable = false)
private BigDecimal orderAmount;
#Column(name ="AWARD_FULFILLED_INDIC", nullable = false)
private Boolean awardFulIndicator;
}
Given the above, how would I write a JPA query against the CustomerOrders entity, that when passed the customer id as a parameter, it would return those CustomerOrders having at least one Order with an amount of greater than $10 positive amount and whose AWARD_FULFILLED_INDIC is true?
Thank you in advance.

I'd try this:
SELECT * FROM CustomerOrders c INNER JOIN c.orders o
WHERE c.customerId = :cId AND o.awardFulIndic = true
HAVING MAX(o.orderAmount) >= 10.00;

#MawrCoffeePls 's solution worked

Related

Hibernate CriteriaQuery How to Find list of integer having two conditions

I got two entity class one:
#Table(name = "package")
public class Package {
#Id
#Column(name = "package_id", insertable = false, nullable = false)
private Long packageId;
#Column(name = "timestamp", nullable = false, updatable = false)
#Temporal(TemporalType.TIMESTAMP)
private Date timestamp;
#Column(name = "name", nullable = false)
private String name;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "queue_id",foreignKey=#ForeignKey(name = "package_queue_id_fk"))
private Queue Queue;
#Column(name = "file_number", nullable = true)
private Integer fileNumber;
And
#Table(name = "queue")
public class Queue {
#Id
#Column(name = "queue_id", insertable = false, nullable = false)
private Integer queue;
#Column(name = "description", nullable = true)
private String description;
#Column(name = "name", nullable = false)
private String name;
#OneToMany(mappedBy = "Queue", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.REFRESH })
#MapKeyColumn(name = "package_id")
private Set<Package> packages;
And I would like to find List of fileNumbers depending on package.name and package.queue.queue_id
So currently I got only one condition (name) and it looks like this:
public List<Integer> getAllFileNumbers(String fileName, Integer queueId) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Integer> query = cb.createQuery(Integer.class);
Root<Package> package = query.from(package.class);
query.select(package.get("fileNumber")).where(cb.equal(package.get("name"), fileName));
return em.createQuery(query).getResultList();
}
Anyone could help me add another one, on top of thet remamber that the value need to be from another entity.
Edit:
So after #Leviand hint I did it like this:
Predicate filenamePred= cb.equal(package.get("name"), fileName);
Predicate queueIdPred = cb.equal(package.get("queue_id"), queueId);
query.select(package.get("fileNumber")).where(cb.and(filenamePred, queueIdPred ));
I got error:
Caused by: java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [queue_id] on this ManagedType
You need to add the two predicates ( you can ofc write it all inline, I'm splitting so it's clearer) in a or condition, for example:
Predicate filename= cb.equal(package.get("name"), fileName);
Predicate queueId = cb.equal(package.get("queue"), queueId);
//then use them in a or condition
query.select(root).where(cb.and(filename, queueId ));
queue_id is the name of the column. You have to use the name of the field, which is Queue, and you have to get it's id field (queue) to compare.
This can be made easier and more type-safe if you use the metamodel-generator.

JPA entity join column on composite key, with date as one of PK

I have to join two tables with ManyToOne relationship using JPA.
TABLE 1 -> manF
#Entity
#Table(name = "manf")
public class ManF {
#EmbeddedId
private ManFCompositeKey manFCompositeKey;
#Column(name = "name", length = 10)
private String manFName;
#Column(name = "desc", length = 150)
private String manFDesc;
}
#Embeddable
public class ManFCompositeKey {
#Column(name = "man_code", length = 20, nullable = false)
private String manCode;
#Column(name = "update_time", nullable = false)
private Date updTime;
}
TABLE 2 -> products
#Entity
#Table(name = "products")
public class Prod {
#EmbeddedId
private ProdCompositeKey prodCompositeKey;
#Column(name = "name", length = 10)
private String prodName;
#Column(name = "prod_desc", length = 150)
private String prodDesc;
// -> JoinColumn here.
#Column(name = "man_code", length = 20, nullable = false)
private String manCode;
}
#Embeddable
public class ProdCompositeKey {
#Column(name = "prod_code", length = 20, nullable = false)
private String prodCode;
#Column(name = "update_time", nullable = false)
private Date updTime;
}
Now, manF(Table 1) can have many products(Table 2). Thus, for each row in product table, there can be same manFCode.
I intend to establish a join b/w T1 and T2 such that manCode column in products behaves as the FK for this table referenceing man_code of Table 1.
Below is the join condition I wrote:
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumns({
#JoinColumn(name = "man_code", referencedColumnName = "man_code")
})
#Column(name = "man_code", length = 20, nullable = false)
private ManF manF;
This should make sense(I thought), but threw an error, stating: ManF not mapped to a single property.
Now I can do this:
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumns({
#JoinColumn(name = "man_code", referencedColumnName = "man_code")
#JoinColumn(name = "update_time", referencedColumnName = "update_time")
})
#Column(name = "man_code", length = 20, nullable = false)
private ManF manF;
But then I would be keeping a FK reference on the time, on which a ManF was inserted.
I need to know how can I join the two tables here such that I can create a FK reference on the man_code of ManF table and the man_code in the product (child) table.
You can use hibernate native query and write the join condition. If that is not a option I would particularly change the embeddedId on Manf to a regular id and create a constraint in your db, to maintain integrity an use a regular joincolumn condition. Like this:
SQL: ALTER TABLE 'manf' ADD UNIQUE 'UNIQUE_CONSTRAINT'('man_code', 'update_time');
#Entity
#Table(name = "manf")
public class ManF {
#Id
#SequenceGenerator(name = "SEQUENCE_NAME", sequenceName = "SEQUENCE_NAME", allocationSize = 1, initialValue = 1)
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SEQUENCE_NAME")
#Column(name = "man_code", length = 20, nullable = false)
private String manCode;
#Column(name = "update_time", nullable = false)
private Date updTime;
#Column(name = "name", length = 10)
private String manFName;
#Column(name = "desc", length = 150)
private String manFDesc;
}
#Entity
#Table(name = "products")
public class Prod {
#EmbeddedId
private ProdCompositeKey prodCompositeKey;
#Column(name = "name", length = 10)
private String prodName;
#Column(name = "prod_desc", length = 150)
private String prodDesc;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "man_code")
private ManF manF;
}
This is what I have done, to achieve this. May be a hack.
I have put the man_code from from Table 1 (ManF), in the main class (it stays is the Embeddable as well). But in the ManF class I did something like this:
#Entity
#Table(name = "manf")
public class ManF {
#EmbeddedId
private ManFCompositeKey manFCompositeKey;
*#Column(name = "man_code", insertable = false, updatable= false)
private String manCode;*
#Column(name = "name", length = 10)
private String manFName;
#Column(name = "desc", length = 150)
private String manFDesc;
}
#Embeddable
public class ManFCompositeKey {
#Column(name = "man_code", length = 20, nullable = false)
private String manCode;
#Column(name = "update_time", nullable = false)
private Date updTime;
}
On the other hand, I have changed my Table 2 as follows:
#Entity
#Table(name = "products")
public class Prod {
#EmbeddedId
private ProdCompositeKey prodCompositeKey;
#Column(name = "name", length = 10)
private String prodName;
#Column(name = "prod_desc", length = 150)
private String prodDesc;
*#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumns({
#JoinColumn(name = "man_code", referencedColumnName =
"man_code")})
private ManF manF;*
*#Column(name = "man_code", insertable = false, updatable = false)
private String manCode;*
#Column(name = "man_code", length = 20, nullable = false)
private String manCode;
}
#Embeddable
public class ProdCompositeKey {
#Column(name = "prod_code", length = 20, nullable = false)
private String prodCode;
#Column(name = "update_time", nullable = false)
private Date updTime;
}
This is somehow working, but I have had to add a new variable in the Child table (here: manCode with insertable and updatabale as false)
I am not sure if this is the correct approach. Please, let me know if someone has a better and elegant idea to approach this issue.

Mapping three identical tables in one entity

i'm needing your help.
i have 3 tables on my database running on postgresql. they are exactly the same structure. so i thought if i could mapp them in one entity.
i try this:
#Entity
#Table(name = "stock_tierra")
#SecondaryTables({
#SecondaryTable(name = "stock_bebelandia"),
#SecondaryTable(name = "stock_libertador")
})
public class Stock implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id_stock", unique = true, nullable = false)
private int idStock;
#Column(name = "cantidad", nullable = false)
private int cantidad;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_producto", nullable = false)
private Producto idProducto;
#Column(name = "estado", nullable = false)
private boolean estado;
#Column(name = "usuario_creacion", nullable = false)
private int usuarioCreacion;
#Column(name = "usuario_modificacion")
private Integer usuarioModificacion;
#Temporal(TemporalType.DATE)
#Column(name = "fecha_creacion", nullable = false, length = 13)
private Date fechaCreacion;
#Temporal(TemporalType.DATE)
#Column(name = "fecha_modificacion", length = 13)
private Date fechaModificacion;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "id_sucursal", nullable = false)
private Sucursal idSucursal;
but when i try to look in to one table i only get data from the first stock_tierra
String stockSucursal = null;
switch (sucursal) {
case 1:
stockSucursal = "stock_tierra";
break;
case 2:
stockSucursal = "stock_bebelandia";
break;
case 3:
stockSucursal = "stock_libertador";
break;
}
Criteria criteria = getSession().createCriteria(Stock.class, stockSucursal);
criteria.add(Restrictions.eq("estado", true));
criteria.addOrder(Order.asc("idStock"));
List<Stock> list = criteria.list();
return list;
some idea what i'm doing wrong?
#SecondaryTables is used to denote one entity being spread over multiple tables in terms of columns, not as a union.
The only thing I can think of right now is using a view which does a union over all the tables, but I am not sure whether postgres can handle writable views, or how you declare them (if you even need a write interface.)

JPQL : How to construct a WHERE clause?

i would like to create a namedquery in JPQL, but i don't understand how it's working...
Here my entity:
#Entity
#NamedQueries({
#NamedQuery(name = "Translation.lang",
query = "SELECT t FROM Translation t WHERE t.reference.id = :refId AND t.language.lang = :lang")
})
#Table(name = "T_E_TRANSLATION_TRL")
public class Translation implements java.io.Serializable {
#Id
#Column(name = "TRL_ID", unique = true, nullable = false)
#TableGenerator(name="translationSeqStore",
table="T_S_APP_SEQ_STORE_AST",
pkColumnName="AST_SEQ_NAME",
valueColumnName = "AST_SEQ_VALUE",
pkColumnValue = "T_E_TRANSLATION_TRL.TRL_ID",
allocationSize=1)
#GeneratedValue(strategy=GenerationType.TABLE,
generator="translationSeqStore")
private Integer id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRL_REF_ID", nullable = false)
private Reference reference;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "TRL_LAN_ID", nullable = false)
private Language language;
#Column(name = "TRL_LABEL", nullable = false, length = 4000)
private String label;
Should i use LEFT JOIN on Reference & Language to select my translatation with these id ?
Thank you.
I think you want:
SELECT t FROM Translation t join fetch t.reference join fetch t.language WHERE t.reference.id = :refId AND t.language.lang = :lang
That will join (and fetch the LAZY reference and language) and return the Translations for the reference with ID refId and language with lang = lang.

Hibernate query causing lots extra unnecassery queries

I am developing a auction site. The problem lies in 3 entities i use:
Product (has zero or many ProductBid)
ProductBid (has zero or one ProductBidRejection)
ProductBidRejection
I use a hibernate query to get the bids:
select pb from ProductBid pb left join pb.rejection pbr where pbr is null and pb.product = :product order by pb.amount desc
This generates this query (via console):
select
productbid0_.id as id4_,
productbid0_.amount as amount4_,
productbid0_.bid_by as bid4_4_,
productbid0_.date as date4_,
productbid0_.product_id as product5_4_
from
product_bids productbid0_
left outer join
product_bid_rejections productbid1_
on productbid0_.id=productbid1_.product_bid_id
where
(
productbid1_.id is null
)
and productbid0_.product_id=?
But for each bid it gets it also generates:
select
productbid0_.id as id3_1_,
productbid0_.date_rejected as date2_3_1_,
productbid0_.product_bid_id as product4_3_1_,
productbid0_.reason as reason3_1_,
productbid0_.rejected_by as rejected5_3_1_,
productbid1_.id as id4_0_,
productbid1_.amount as amount4_0_,
productbid1_.bid_by as bid4_4_0_,
productbid1_.date as date4_0_,
productbid1_.product_id as product5_4_0_
from
product_bid_rejections productbid0_
inner join
product_bids productbid1_
on productbid0_.product_bid_id=productbid1_.id
where
productbid0_.product_bid_id=?
These are my entities:
ProductBid
#Entity
#Table(name = "product_bids")
public class ProductBid
{
#Column(name = "id", nullable = false)
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#JoinColumn(name = "product_id", nullable = false)
#Index(name="product")
#ManyToOne(fetch = FetchType.LAZY)
private Product product;
#Column(name = "amount", nullable = false)
private BigDecimal amount;
#JoinColumn(name = "bid_by", nullable = false)
#Index(name="bidBy")
#ManyToOne(fetch = FetchType.LAZY)
#Fetch(FetchMode.JOIN)
private User bidBy;
#Column(name = "date", nullable = false)
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime date;
#OneToOne(fetch = FetchType.LAZY, mappedBy = "productBid")
private ProductBidRejection rejection;
}
ProductBidRejection
#Entity
#Table(name = "product_bid_rejections")
public class ProductBidRejection
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id", nullable = false)
private long id;
#Column(name = "reason", nullable = false, columnDefinition = "TEXT")
private String reason;
#Column(name = "date_rejected", nullable = false)
#Type(type = "org.joda.time.contrib.hibernate.PersistentDateTime")
private DateTime dateRejected;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "rejected_by", nullable = false)
private User rejectedBy;
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "product_bid_id", nullable = false)
#Fetch(FetchMode.JOIN)
private ProductBid productBid;
}
Its because you have #Fetch(FetchMode.JOIN) on ProductBid.
So for each of the ProductBidRejections you retrieve, it also loads a ProductBid.
UPDATE
Try this query. It will get distinct pb and eagerly fetch the PBR
select distinct pb from ProductBid pb left join fetch pb.rejection pbr where pbr is null and pb.product = :product order by pb.amount desc
Use Criteria instead of HQL your problem will be solve
session.createCriteria(ProductBid.class).add(Restrictions.eq("product",yourproduct)).list();
and in ProductBid Entity Class use annotation to join EAGER ly to ProductBidRejection

Categories