JPA Critera Query In Spring - jpa

public Product findProductById(String id , String subCategoryId)
{
return em.find(Product.class, id);
}
In this method pass two parameter. How to retrieve record form product table id and subCategoryId?
Actually I am retrieve record based on Id but apply subCategoryId (with and Condition) Error occour.
Please send also Link explain How it's Work? Thanks.

public List findProductIdSubCategoryIdCategoryId(String categoryId, String subCategoryId,String id)
{
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery criteria = cb.createQuery(Product.class);
Root product = criteria.from(Product.class);
cb.equal(product.get("subCategoryId"),subCategoryId);
Predicate csi = cb.and(cb.equal(product.get("categoryId"), categoryId), cb.equal(product.get("subCategoryId"), subCategoryId),
cb.equal(product.get("id"), id));
criteria.select(product).where(csi);
return em.createQuery(criteria).getResultList();
}
It's working fine and attached also link http://en.wikibooks.org/wiki/Java_Persistence/Criteria

Related

Where is client evaluation needed?

I have a query which works fine in Linq to Objects in this fiddle:
var list = from order in orders
join detail in details
on order.id equals detail.order into od
select new { order = order, details = od };
I tried applying the same query when the data is in a database (note I am mapping Linq to Sql manually):
public class dbContext: DbContext {
public DbSet<Order> Orders { get; set; }
public DbSet<Detail> Details { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder oB) {
oB.UseSqlServer("...connection string...");
}
}
using (var db = new dbContext() {
var list = from order in db.Orders
join detail in db.Details
on order.id equals detail.order into orderDetails
select new { order = order, details = orderDetails };
}
The above gives:
could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
I tried details = orderDetails.ToList() in the last line but the same error is there. Where should I add the manual client evaluation?
Some background information: the following database query (without the into) works fine:
var list = from order in db.Orders
join detail in db.Details
on order.id equals detail.order
select new { order = order, detail = detail };
Instead of a join you should declare Navigation Properties and use something like:
var query = from order in db.Orders
select new { order = order, details = order.OrderDetails };
var list = query.ToList();
or simply
var list = db.Orders.Include(o => o.OrderDetails).ToList();

Hibernate Criteriabuilder Query with part of a compound id

I have a class that I am attempting to query by "userid"
#Entity
#IdClass(CollectionPK.class)
#Table(name="collection", schema="mageduelsusers")
public class Collection{
#Id
#Column(name = "userid")
private int userId;
#Id
#Column(name = "cardid")
private int cardId;
...
Id class of
public class CollectionPK implements Serializable{
private int userId;
private int cardId;
public CollectionPK() {
}
...
Query code is
public List<Collection> readCollection(int id) {
List<Collection> collection = null;
Session session = factory.openSession();
Transaction tx = null;
try {
tx = session.beginTransaction();
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Collection> criteriaQuery = builder.createQuery(Collection.class);
Root<Collection> root = criteriaQuery.from(Collection.class);
ParameterExpression userIdParameter = builder.parameter(Collection.class);
criteriaQuery.where(builder.equal(root.get("userid"), userIdParameter));
Query<Collection> query = session.createQuery(criteriaQuery);
query.setParameter("userid", id);
collection = query.getResultList();
tx.commit();
}
...
Error is
Exception in thread "main" java.lang.IllegalArgumentException: Unable to locate Attribute with the the given name [userid] on this ManagedType [com.panda.userinfo.Collection]
Ideal query would be
Select * from collection where userid = 'userid';
How do I modify to make this work?
Pretty sure error is in the criteria builder section as session.save(). session.get(), and session.delete() all work properly
Update:
Did a little bit of testing and the cause of the issue is definitely root.get("userid") Is there any way to check what Attributes hibernate has for a class?
Update2:
Capitalizing the I in root.get("userId") fixes that error. However both forms still cause an error at query.setParameter("userId", id)
java.lang.IllegalArgumentException: Unable to locate parameter registered with that name [userId]
Update 3:
Figured it out or at least made it functional. Hibernate was renaming things in the background. Solved by printing everything to find the correct parameter name.
for(Parameter<?> p:query.getParameters()) {
System.out.println(p.getName());
}
System.out.println(query.getParameters().size());
Try to correct your query in this way:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<Collection> criteriaQuery = builder.createQuery(Collection.class);
Root<Collection> root = criteriaQuery.from(Collection.class);
ParameterExpression<Integer> userIdParameter = builder.parameter(Integer.class);
criteriaQuery.where(builder.equal(root.get("userid"), userIdParameter));
List<Collection> collection = session.createQuery(criteriaQuery)
.setParameter("userid", id)
.getResultList();
See also this section of the documentation.

Searching by query for attributes of complex objects in Java EE

I have created the object Person, I can deleted and modify it and I can also search for Person by his name or phonenumber... but I don't know for exemple how to search for a person by his ** home address**. Here is my code:
My entity Person.java:
public class Person{
private Long id;
private String name;
#ManyToOne(cascade = CascadeType.ALL)
private Address address;
....
}
My entity Address.java
public class Address{
...
private String streetName;
...
}
And here is the most interesting function that I am trying to modify to get what I want, I would like to search for Persons who live in xxx (streetName = xxx). Here is my function getByQuery:
public List<Person> getByQuery(PersonSearchQuery searchQuery) {
Map<String, String> criteriaQuery = new HashMap<String, String>();
if (searchQuery.getName() != null)
criteriaQuery.put("name",searchQuery.getName());
TypedQuery<Person> query = this.findByQuery(criteriaQuery);
return query.getResultList();
}
The object PersonSearchQuery contains just to attributes name (String) and streetName (String) and their getters.
Function findByQuery:
public TypedQuery<T> findByQuery(Map<String, String> criteriaQuery) {
CriteriaBuilder builder = this.em.getCriteriaBuilder();
CriteriaQuery<T> criteria = builder.createQuery(this.entityClass);
Root<T> root = criteria.from(this.entityClass);
criteria.select(root);
Predicate predicate = builder.conjunction();
if (criteriaQuery.size() != 0) {
for (String key : criteriaQuery.keySet()) {
try{
predicate = builder.and(predicate, builder.equal(root.<String>get(key), criteriaQuery.get(key)));
}catch(IllegalArgumentException e){
continue;
}
}
}
criteria.where(predicate);
return this.em.createQuery(criteria);
}
So I can search for Persons by their names by I cannot search for them by streetName the problem is my function getByQuery I would like to do something like this:
if (searchQuery.getStreetName() != null)
criteriaQuery.put("Address.streetName",searchQuery.getStreetName());
The problem is I don't know how to define the key in this case. Thanks for your help
I only use CriteriaBuilder if I have several similar Entities which needs to be used/rendered in the same way, so if person is the only Entity with an Address reference I would just use JPQL, like this:
entityManager.createQuery(
"select p from Person p where p.address.streetName like :streetName", Person.class)
.setParameter("streetName", "xyz" + "%").getResultList()
The main reason I tend to avoid CriteriaBuilder, is because it has a rather steep learning curve, and you need to write a lot of code to express very simple concepts. In contrast any developer familiar with SQL can read and maintain JPQL code.
These days I always use frameworks, like DeltaSpike Data (for EE) and Spring Data, they both implements most of the basic DAO/Repository features, so If you don't mind an extra dependency (and some magic) it can save you a lot of boilerplate JPA code.

How can I query specific columns from 2 tables inside my objects using JPA 2.0?

I am looking for a way to request specific columns and have the foreign object present in the root object using CriteriaBuilder. Here is the context:
I have EntityA
#Entity
#Table(name = "ENTITY_A")
public class EntityA {
int id;
int entityBKey;
EntityBObject entityBObject;
int AColumn1;
int AColumn2;
#Basic
public Long getEntityBKey() {
return entityBKey;
}
#ManyToOne
#JoinColumn(name = "ENTITY_B_FK")
public EntityBObject getProgramType() {
return entityBObject;
}
#Basic
#Column(name = "COLUMN_1")
public String getAColumn1() {
return AColumn1;
}
...
}
Then I have EntityB
public class EntityB {
int id;
int BColumn1;
int BColumn2;
...
}
Now, I want to request column AColumn1 from EntityA and column BColumn1 from EntityB, while having the object EntityB inside the EntityA. How can I achieve this ?
How can I modify the following to get a partial EntityA with an EntityB inside ?
public List<EntityA> findAll() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<EntityA> criteria = cb.createQuery(EntityA.class);
Root<EntityA> root = criteria.from(EntityA.class);
criteria.select(root);
return em.createQuery(criteria).getResultList();
}
Thanks !
Edit
#Tassos Bassoukos Yes, that's what I ended up doing, but it would get really messy when the request gets more complex. Ex.: Pull customers with their orders, with items for each orders. There would be so much java to achieve this, I though it could be automated so my object are automatically populated.
public List<EntityA> findAll() {
ArrayList<EntityA> result = new ArrayList<>();
Query q = em.createQuery("select eA, eB, from EntityA eA, EntityB eB where eA.key = eB.key");
#SuppressWarnings("unchecked")
List<Object[]> abc = q.getResultList();
for (Object[] array : abc) {
EntityA eA = (EntityA) array[0];
EntityB eB = (EntityB) array[1];
eA.setEntityB(eB);
result.add(pe);
}
return result;
}
First, why do you want a partial entity? That does not make sense from an OO perspective. Is there an actual, specific requirement for this?
Secondly, do you want entities or columns of entities? You can do both with CriteriaBuilder, but you need to be clear on a) what you want to achieve, b) why you want to achieve it.
Thirdly, there's JOIN FETCH.

Entity Framework best practice for "include" in Repository

I have a Repository pattern for product entity and I have a method that retrieves a product by id. Each product has a category, among other complex properties. In some cases I want to retrieve the products without the category (lazy loading) but in some cases I want to return both entities (products and categories). Is there any better option that having two methods? this is what I coded:
Product GetById(int id)
{
// without includes
...
}
Product GetByIdFull(int id)
{
// with includes
...
}
You can do something like this:
public Product Get(int id, params Expression<Func<TEntity, object>>[] propertiesToInclude)
{
var query = context.Products;
foreach (var expression in propertiesToInclude)
{
query = query.Include(expression);
}
return query.SingleOrDefault(p => p.id == id);
}
The calling code could optionally specify the properties to be included using a lambda like so:
var justProduct = repo.Get(productId);
var productAndCategory = repo.Get(productId, p => p.Category);