Hibernate query for multiple associations - java

I have the following structure in JAVA.
public class Article {
private long id;
private Source source;
}
public class Source {
private long id;
private Type type;
}
public class Type {
private long id;
private String sourceType;
}
How do I query all articles with Type.id = somevalue using Hibernate Criteria. Right now I can only query until Source class like this
Criteria query = currentSession().createCriteria(Article.class)
.createAlias("source", "s")
.add(Restrictions.eq("s.id", Long.parseLong(typeId)));

Try this
Criteria query = currentSession().createCriteria(Article.class)
.createAlias("source", "s")
.createAlias("s.type","t")
.add(Restrictions.eq("t.id", Long.parseLong(typeId)));

Related

spring-jpa - creating query similar to in clause for nested entity id using ExampleMatcher for QueryByExampleExecutor

I was trying out Spring ExampleMatcher for creating a query that requires use of in clause and between clause.
public class A{
private Long id;
private B b;
private D d;
private Date created;
}
public class B {
private Long id;
private C c;
private Long sequence;
}
public class C {
private Long id;
private String externalName;
}
public class D {
private Long id;
}
I need to create a query that matches in clause on A.b.c.externalName, equal clause on A.d.id and between operator on A.b.sequence fields.
Is it possible to do create a query using ExampleMatcher that fulfills above scenario.
Sample HQL : SELECT a FROM A a WHERE a.d.id = :subscriberId AND a.b.c.externalName IN :externalNames and a.b.sequence between (:startSequence, :endSequence)
Please help !

JPA - How to query using Specification and #EmbeddedId?

I'm using a JPA query that uses a specification to retrieve entities. When I execute the query, I'm getting the error:
org.springframework.data.mapping.PropertyReferenceException: No property name found for type Task!
I've looked at the answers to similar questions that have been asked on this site previously & tried to model my code to follow the patterns that were recommended but the code is still failing.
When I step through the code with a debugger, the expanded path in the criteria builder is returning the embedded ID class, but when the specification is actually used in the query it looks like the attribute is being applied to the base entity class.
Am I missing something obvious?
Here is the entity class:
#Entity
#Table(name = "TASKS")
public class Task implements Serializable {
#EmbeddedId
private TaskId id;
...more attributes, getters and setters
}
Here is the embedded ID entity class:
#Embeddable
public class TaskId implements Serializable {
#Column(name = "NAME", length = 100)
private String name;
...more attributes, getters and setters
}
Here is the specification builder that matches on the embedded id 'name' attribute:
public class HasTaskNameSpec {
private HasTaskNameSpec() {
}
public static Specification<Task> equals(String name) {
return (root, query, criteriaBuilder) -> {
return criteriaBuilder.equal(root.get("id").get("name"), taskName);
};
}
}
The query is executed on the repository as follows:
List<Task> results = taskRepository.findAll(HasTaskNameSpec.equals("foo"));
The repository itself is very simple:
public interface TaskRepository extends JpaRepository<Task, TaskId>, JpaSpecificationExecutor<Task> {
List<Task> findByIdName(String name);
Page<Task> findByIdName(String name, Pageable page);
}
** EDIT added methods to repository as was suggested below **
Ahh, the root cause was totally in our codebase. There was a sort order being specified on the page that didn't include the embedded "id" attribute. The above code works.
'root.get({embeddedIdName}).get({subPropertyName})' is used to query on embeddedId using specification.
#Embeddable
public class ProjectId implements Serializable{
private static final long serialVersionUID = 1L;
#Column(name = "PROJECT_NAME")
private String projectName;
#Column(name = "ORGANIZATION")
private String organization;
......
......
}
#Entity
#Table(name = "projects")
public class Project {
#EmbeddedId
private ProjectId projectId;
#Column(name = "STARTED_TIME")
private Timestamp startedTime;
#Column(name = "ACTIVE")
private String active;
#Column(name = "DESCRIPTION")
private String description;
......
......
}
In the above snippet, ProjectId is an embedded id. To query on projectName, we should use below snippet.
expression = root.get("projectId").get("projectName");
Demo application link.
Take a look at this link which has a similar query.
EmbbededId Lookup
The final answer suggests that you can add a method to your TaskRepository thus.
public interface TaskRepository extends JpaRepository<Task, TaskId>, JpaSpecificationExecutor<Task> {
public List<Task> findByIdName(String name);
}

Hibernate mapping of internationalized database

I want to get international content from database based on locale provided in hibernate query. This is a question about hibernate mapping but please feel free to propose better database design if mine is wrong.
My DB design (simplified):
db design
So I have table with non translatable data and additional table with translated content but with additional field "locale" for distinction of language.
My java classes looks like this:
public class Car {
private Long id;
private Long length;
private Long weight;
private CarTranslated carTranslated;
// getters and setters
public class CarTranslated {
private Long id;
private Long carId;
private String desc;
// getters and setters
I want to be able to get one car with single query. With regular jdbc I would use something like this sql query:
public Car getById(Long id, Locale locale) {
Car c = new Car();
String sql = "select c.car_id, c.length, c.weight, ct.id, ct.descryption,
ct.car_id as "Translated car_id" from car c join car_translated ct on
(c.car_id = ct.car_id) where c.car_id ="+ id+" and ct.locale ='"+locale+"'";
// code to set fields of the object using ResultSet
return c;
}
What would be a hibernate annotation mapping and query for this setup? I tried several attempts but to no avail. Currently my best attempt was as below:
Mapping:
#Entity
#Table(name="CAR")
public class Car {
#Id
#Column(name="car_id")
private Long carId;
#Column (name="weight")
private Long carWeight;
#Column (name="length")
private Long carLength;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name ="CAR_ID")
private CarTranslated localized;
// getters and setters
#Entity
#Table(name="CAR_TRANSLATED")
public class CarTranslated {
#Id
#Column (name="id")
private Long id;
#Column (name="car_id")
private Long carId;
#Column (name="descryption")
private String desc;
#Column(name="locale")
private Locale locale;
DAO:
public Car getCarById(Locale locale, Long id) {
Car car = new Car();
try {
Session session = HibernateUtils.getSessionFactory().openSession();
Criteria cr = session.createCriteria(Car.class)
.add(Restrictions.eq("carId", id));
Criteria cr1 = session.createCriteria(CarTranslated.class)
.add(Restrictions.eq("locale", locale));
car = (Car) cr.uniqueResult();
car.setLocalized((CarTranslated) cr1.uniqueResult());
} catch (Exception e) {
System.out.println(e.getMessage());
}
return car;
}
This is a work-around and I'm wondering what would be a proper way to do this?
You should have an annotation on both columns when mapping to a FK. (JavaDoc)

java.lang.AbstractMethodError during createQuery

I am attempting to retrieve a list of results from my database, by following an example in this answer. Howeverm, I keep getting the following error:
java.lang.AbstractMethodError: org.hibernate.ejb.EntityManagerImpl.createQuery(Ljava/lang/String;Ljava/lang/Class;)Ljavax/persistence/TypedQuery;
Here is my code, to denote how I am calling this:
#Entity
#Table(name = "MY_TABLE")
public class CoolsEntity implements Serializable {
#Id
#Column(name = "ID", columnDefinition = "Decimal(10,0)")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
#Column(name = "COOL_GUY_NAME")
private String name;
public String getId() {
return id;
}
public void setId(final String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name= name;
}
}
This code below generates the error:
final String sql = "select c from CoolsEntity c";
final TypedQuery<CoolsEntity> query = em.createQuery(sql, CoolsEntity.class);
final List<CoolsEntity> results = query.getResultList();
return results;
However, if I do something like this, I can see the results:
final String sql = "select c from CoolsEntity c";
final Query query = em.createQuery(sql);
#SuppressWarnings("unchecked")
final List<CoolsEntity> results = query.getResultList();
return results;
All of the references to em are imported through this package:
import javax.persistence.EntityManager
Shouldn't the two queries above generate the same result? Am I missing a cast to the List interface to allow this to work in the typed query?
You have an AbstractMethodError exception which is thrown when an application tries to call an abstract method.
You have quite a mix of Hibernate and JPA versions.
TypedQuery was introduced in JPA 2.0 and Hibernate implements this specification since 3.5.X
Suggesstion : Use implementation from Hibernate version 3.6.3 (or higher).
you are probably using two differnet version of interface EntityManager and implementation EntityManagerImpl.

Spring Data Mongo - How to query by #DBRef field's id

I am new to Spring Data Mongo so I must be doing something wrong because I can't manage to execute such a simple query. This is my model:
#Document(collection="brands")
public class Brand{
#Id
private int id;
private String name;
...
//getters-setters
}
#Document(collection="models")
public class Model{
#Id
private int id;
private String name;
#DBRef
private Brand brand;
...
//getters-setters
}
I would like to get all models from a brand, so I implement the DAO as follows:
#Repository
public interface IModelDAO extends MongoRepository<Model, Integer>{
#Query(value="{ 'brand.$id' : ?0 }")
public List<Model> findByBrandId(Integer id);
}
If I execute this mongodb query in the shell it works: db.modelss.find({ 'brand.$id' : 1 })
But, the Java application throws the following exception:
Caused by: java.lang.IllegalAccessError
at org.springframework.data.mapping.PropertyReferenceException.detectPotentialMatches(PropertyReferenceException.java:134)
Apparently it is looking for a field $id in Brand class, and since it doesn't exist it fails. So I change the query to the following, so that it navigates to the id field:
#Query(value="{ 'brand.id' : ?0 }")
Now, it doesn't throw an exception but it doesn't find anything in the DB.
Debugging the MongoTemplate.executeFindMultiInternal() method in can see that in
DBCursor cursor = null;
try {
cursor = collectionCallback.doInCollection(getAndPrepareCollection(getDb(), collectionName));
cursor's query is query={ "brand" : 134}. So it makes sense it doesn't find anything. Changing the query value during debugging to query={ "brand.$id" : 134} it works.
So, why isn't the query correctly translated?
The problem was caused by the #Id int type. Changing it to Integer solved it:
#Document(collection="brands")
public class Brand{
#Id
private Integer id;
private String name;
...
//getters-setters
}
#Document(collection="models")
public class Model{
#Id
private Integer id;
private String name;
#DBRef
private Brand brand;
...
//getters-setters
}
try this;
Query que = new Query();
que.addCriteria(Criteria.where("user.$id").is(new ObjectId("123456789012345678901234")));

Categories

Resources