I'm trying to use Criteria Api for for making queries on database. I found this article:
http://docs.oracle.com/javaee/6/tutorial/doc/gjivm.html
The problem is this code :
Root<Pet> pet = cq.from(Pet_);
I can't import Pet_ class. Do i need to create that class or?
This is my code:
public class DnevnikFacade extends AbstractFacade<Dnevnik> {
#PersistenceContext(unitName = "zadaca_4_1PU")
private EntityManager em;
CriteriaQuery criteriaQuery;
CriteriaBuilder criteriaBuilder;
private Root <Dnevnik> dnevnik ;
private List<Predicate> filteri;
#Override
protected EntityManager getEntityManager() {
criteriaBuilder = em.getCriteriaBuilder();
criteriaQuery = criteriaBuilder.createQuery();
dnevnik = criteriaQuery.from(Dnevnik.class);
return em;
}
public DnevnikFacade() {
super(Dnevnik.class);
}
public List<Dnevnik> dohvatiDnevnikPremaFilterima(){
criteriaQuery.select(dnevnik).where(filteri.toArray(new Predicate[]{}));
return em.createQuery(criteriaQuery).getResultList();
}
public void filterStatus(String status){
filteri.add(criteriaBuilder.equal(dnevnik.get(Dnevnik_.status), status));
}
}
And that Dnevnik_status is the problem. Status is a column in table Dnevnik. What am i doing wrong, can somebody help me?
what does that class_ mean? How can i resolve it? Thanks.
Related
I'm updating a Predicate, basically I want to convert the following query using the criteria API.
select t, length(name) lens
from train t
left join line l on l.id = t.lineId
where l.code = '14'
order by lens, name
Sample result:
other columns
name
lens
...
AA-2
4
...
AA-3
4
...
AA-7
4
...
AA-9
4
...
AA-10
5
...
AA-17
5
...
BB-1
9
...
BB-3
9
...
BB-20
9
This is what I have done so fast:
1- In the service class
public Page<Train> getTrains(Pageable pageable, FilterRequest filterRequest) {
if (filterRequest == null || CollectionUtils.isEmpty(filterRequest.getTrainsFilters())) {
return trainRepository.findAll(pageable);
}
TrainSpecification trainSpecification = new TrainSpecification(filterRequest);
// add a field lens in train => length(name) and add it to sortField in pageable
// sortFields = [lens, name]
Page<Train> trains = trainRepository.findAll(trainSpecification, pageable);
return trains;
}
2- In the Specifcation class
#AllArgsConstructor
#Data
public class TrainSpecification implements Specification<Train> {
private transient FilterRequest filterRequest;
private static final String CODE = "code";
#Override
public Predicate toPredicate(Root<Train> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
Predicate[] predicatesLinesTrains = getTrainsLinesPredicates(root, criteriaBuilder);
return criteriaBuilder.and(predicatesLinesTrains);
}
private Predicate[] getTrainsLinesPredicates(Root<Train> root, CriteriaBuilder criteriaBuilder) {
// I think that update should be done on the root here but couldn't figure out how
final Join<Train, Line> trainLineJoin = root.join("line", JoinType.LEFT);
Predicate[] predicatesLine = new Predicate[0];
if (!CollectionUtils.isEmpty(this.filterRequest.getTrainsFilters())) {
predicatesLine = this.filterRequest.getTrainsFilters()
.stream()
.filter(filterCriteria -> filterCriteria.getValue() != null)
.map(filterCriteria ->
{
switch (filterCriteria.getMatchMode().toUpperCase(Locale.ROOT)) {
case "IN":
return criteriaBuilder.in(root.get(filterCriteria.getName()))
.value(filterCriteria.getValue());
case "EQUAL":
return criteriaBuilder.equal(trainLineJoin.get(CODE), filterCriteria.getValue());
default:
throw new OperationNotSupportedException(filterCriteria.getMatchMode());
}
}
).toArray(Predicate[]::new);
}
return predicatesLine;
}
}
3- The FilterRequest class
#Data
#AllArgsConstructor
#NoArgsConstructor
public class FilterRequest {
private List<FilterCriteria> activitiesFilters;
private List<FilterCriteria> trainsFilters;
private String sortField;
private String sortOrder;
}
4- The FilterCriteria class
#Data
#NoArgsConstructor
#AllArgsConstructor
public final class FilterCriteria {
#NotBlank
private String name;
private Object value;
private String matchMode;
}
According to SQL request, I have to create a field in train. This field should be updated when the database is queried. I can then add that field as a sortable parameter in pageable. I can't figure out how to do that for the moment.
Thoughts
I create a view (train_name_view) and use that with the criteria API
I create a field lens in train and use that to sort.
I look for more elegant way to update the Criteria API to get it done
Any idea on which approach is the best.
I finally solve the issue by using Criteria API.
I updated the toPredicate my Specification with the code
public Predicate toPredicate(Root<Train> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
customSortByName(root, query, criteriaBuilder);
Predicate[] predicatesLinesTrains = getTrainsLinesPredicates(root, criteriaBuilder);
return criteriaBuilder.and(predicatesLinesTrains);
}
private void customSortByName(Root<Train> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
if (this.filterRequest.getSortOrder().equalsIgnoreCase(ASC)) {
query.orderBy(criteriaBuilder.asc(criteriaBuilder.length(root.get(this.filterRequest.getSortField()))),
criteriaBuilder.asc(root.get(this.filterRequest.getSortField())));
} else if (this.filterRequest.getSortOrder().equalsIgnoreCase(DESC)){
query.orderBy(criteriaBuilder.desc(criteriaBuilder.length(root.get(this.filterRequest.getSortField()))),
criteriaBuilder.desc(root.get(this.filterRequest.getSortField())));
}
}
The customSortByName correspond to the SQL query
SELECT name
FROM train
order by length(name), name
i'm testing my web-app with junit and mockito (for business layer).
i have an entity:
#Entity
#Table(name = "brand")
#XmlRootElement
#NamedQueries({
#NamedQuery(name = "Brand.findAll", query = "SELECT b FROM Brand b"),
#NamedQuery(name = "Brand.findByOid", query = "SELECT b FROM Brand b WHERE b.oid = :oid"),
#NamedQuery(name = "Brand.findByName", query = "SELECT b FROM Brand b WHERE b.name = :name")})
public class Brand implements Serializable {
...
and a session bean
#Stateless
public class BrandFacade extends AbstractFacade<Brand> {
#PersistenceContext(unitName = "MyWheelJSFPU")
private EntityManager em;
public void setEm(EntityManager em) {
this.em = em;
}
...
#Override
public List<Brand> findAll(){
return em.createNamedQuery("Brand.findAll", Brand.class).getResultList();
}
...
now i want to test .findAll
public class BrandFacadeTest {
#Mock
private EntityManager mockedEntityManager;
#Mock
private TypedQuery mockedQuery;
private BrandFacade brandFacade;
public BrandFacadeTest() {
}
#BeforeClass
public static void setUpClass() {
System.out.println("Start BrandFacadeTest");
}
#AfterClass
public static void tearDownClass() {
}
#Before
public void initDependencies() {
brandFacade=new BrandFacade();
brandFacade.setEm(mockedEntityManager);
System.out.println("mockEmCreated");
}
/**
* Test of findAll method, of class BrandFacade.
*/
#Test
public void testFindAll() {
System.out.println("findAll");
List<Brand> brands=new ArrayList<>();
when(mockedEntityManager.createNamedQuery("Brand.findAll", Brand.class)).thenReturn(mockedQuery);
when(mockedQuery.getResultList()).thenReturn(brands);
int initNumber=brandFacade.findAll().size();
//creating Brand
Brand b1 = new Brand(1, "mo");
brandFacade.create(b1);
verify(mockedEntityManager, times(1)).persist(any());
brands.add(b1);
assertEquals("error",initNumber+1, brandFacade.findAll().size());
}
...
at this line
when(mockedEntityManager.createNamedQuery("Brand.findAll", Brand.class)).thenReturn(mockedQuery);
it returns a java.lang.nullpointerexception...why??? what's the problem?
i made exactly the same for another entity and it work!
If you want to use the #Mock annotation, you must run the unittest either with MockitoJUnitRunner, or set the following in your test case #Before clause:
MockitoAnnotations.initMocks(BrandFacadeTest);
See here: http://docs.mockito.googlecode.com/hg/1.9.5/org/mockito/Mockito.html#mock_annotation
I'm trying to use JPA2 type-safe criteria queries with Hibernate 5.0.7.Final.
...
criteria.where( builder.equal( root.get(SingularAttribute.attr), value ));
//where parameters are
//criteria.where( builder.equal( root.get(Person_.name), "Can" ));
...
The root.get always throw NullPointerException.
The metamodel class Person_ for Person is generated by org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.
A similar problem was asked in JPA/Hibernate Static Metamodel Attributes not Populated -- NullPointerException but this time both classes are in the same package.
Stack trace:
java.lang.NullPointerException
at org.hibernate.jpa.criteria.path.AbstractPathImpl.get(AbstractPathImpl.java:123)
My code:
Interface that i use to make sure they will have getId();.
package it.unibz.db.hibernate.model;
public interface ModelInterface<PK extends Serializable> extends Serializable {
PK getId();
}
Model class
package it.unibz.db.hibernate.model;
#Entity
#Table(name ="person")
public class Person implements ModelInterface<Integer> {
#Id
private Integer id;
private String name;
public Integer getId() {
return id;
}
//other getter and setters
}
Generated metamodel Person_ class
package it.unibz.db.hibernate.model;
#Generated(value = "org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor")
#StaticMetamodel(Person.class)
public abstract class Person_ {
public static volatile SingularAttribute<Person, String> name;
public static volatile SingularAttribute<Person, Integer> id;
}
Generic DAO class that i inherit with PersonDao
public class GenericDao<E extends ModelInterface<PK>, PK extends Serializable> implements DaoInterface<E, PK> {
private Class<E> type;
public GenericDao(Class<E> type) {
this.type = type;
//called as super(ClassName.class); eg. super(Person.class);
}
public List<E> readBy(SingularAttribute column, String value) throws Exception {
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<E> criteria = builder.createQuery(type);
Root<E> root = criteria.from(type);
criteria.select(root);
criteria.where( builder.equal( root.get(column), value ));
List<E> entityList = em.createQuery(criteria).getResultList();
em.close();
return entityList;
}
}
Some of my dependencies
hibernate-c3p0 5.0.7.Final
hibernate-entitymanager 5.0.7.Final
postgresql 9.4.1207.jre7
hibernate-jpamodelgen 5.0.7.Final
EDIT:
Running this code in the main method works
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
criteria.select(root);
criteria.where( builder.equal( root.get(Person_.name), "Can" ));
List<Person> entityList = em.createQuery(criteria).getResultList();
//do stuff with entityList
but the same code covered in a method throws NullPointerException.
public List<Person> readBy(SingularAttribute column, String value) throws Exception {
log.debug("Reading entity by");
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
criteria.select(root);
criteria.where( builder.equal( root.get(column), value ));
List<Person> entityList = em.createQuery(criteria).getResultList();
em.close();
return entityList;
}
So it seems that the problem is passing SingularAttribute parameter to the method readBy(SingularAttribute column, String value).
I tested this code in main and this prints false
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
System.out.println(root.get(Person_.name) == null); //false
meanwhile this throws InvocationTargetException caused by NullPointerException at root.get(column).
//invoked as personDao.test(Person_.name) from main
public void test(SingularAttribute column) {
EntityManager em = HibernateUtil.getEntityManager();
CriteriaBuilder builder = em.getCriteriaBuilder();
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);
Root<Person> root = criteria.from(Person.class);
System.out.println(root.get(column) == null); //InvocationTargetException
}
Is this what it's supposed to do? How can i pass SingularAttribute object to a method as a parameter?
Calling HibernateUtil.getEntityManager() in main before method call somehow works. It even works when i call literally a empty block of a method init().
It could be related with initialization of classes. Here's the code snippet.
public class HibernateUtil {
private static EntityManagerFactory emFactory;
private static EntityManager em;
private static final Logger log = LoggerFactory.getLogger(HibernateUtil.class);
private static final String PERSISTENCE_UNIT = "pt";
static{
log.info("Creating entity manager factory");
emFactory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
}
//calling this from main before PersonDao's method calls somehow works...
public void init(){} //does nothing
public static EntityManager getEntityManager(){
if(em != null && em.isOpen()){
closeEntityManager();
}
log.debug("Creating new entity manager");
em = emFactory.createEntityManager();
return em;
}
public static void close() throws Exception {
if(em != null && em.isOpen()){
closeEntityManager();
}
log.info("Closing entity manager factory");
emFactory.close();
}
private static void closeEntityManager(){
log.info("Closing last entity manager");
em.close();
}
}
First of all, sorry for my english.
Im making, for a friend, a desktop application with JPA(EclipseLink) that access a SQLite database.
I already created the database and the entities in Eclipse. But i also created a class called UniversalDAO which is an utility class used by all the entities to access and persist the database:
package model.DAO;
import java.util.ArrayList;
import javax.persistence.*;
import model.entities.Entities;
public class UniversalDAO {
private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("TheDatabase");
private static EntityManager em = emf.createEntityManager();
private UniversalDAO (){}
public static void close(){
em.close();
emf.close();
}
public static Entities getOne(Class<? extends Entities> table, Object primaryKey) {
return em.find(table, primaryKey);
}
public static ArrayList<Entities> getAll(Class<? extends Entities> table) {
ArrayList<Entities> ret = new ArrayList<>();
for(Object obj : em.createQuery("SELECT o FROM " + table.getName() + " o").getResultList())
ret.add((Entities) obj);
return ret;
}
public static ArrayList<Entities> getWithCondition(Class<? extends Entities> table, String condition) {
ArrayList<Entities> ret = new ArrayList<>();
for(Object obj : em.createQuery("SELECT o FROM " + table.getName() + " o WHERE " + condition).getResultList())
ret.add((Entities) obj);
return ret;
}
public static void insert(Entities row) {
em.getTransaction().begin();
em.persist(row);
em.flush();
em.getTransaction().commit();
}
public static void update(Entities row) {
em.getTransaction().begin();
em.merge(row);
em.flush();
em.getTransaction().commit();
}
public static void delete(Class<? extends Entities> table, Object primaryKey) {
em.getTransaction().begin();
Entities row = em.find(table, primaryKey);
em.remove(row);
em.flush();
em.getTransaction().commit();
}
}
To group all the entites and use them in this class i created an empty interface called Entities.
This is how one of the entities looks like:
package model.entities;
import java.util.ArrayList;
import javax.persistence.*;
#Entity
#Table(name="emails")
public class EntityEmail implements Entities {
#Id
#Column(name="id_email")
#GeneratedValue(strategy=GenerationType.SEQUENCE)
private int idEmail;
#Column(name="email")
private String email;
#Column(name="description")
private String description;
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name="people_emails",
joinColumns=#JoinColumn(name="id_email", referencedColumnName="id_email"),
inverseJoinColumns=#JoinColumn(name="id_person", referencedColumnName="id_person"))
private ArrayList<EntityPerson> people;
public EntityEmail() {
}
public int getIdEmail() {
return this.idEmail;
}
public void setIdEmail(int idEmail) {
this.idEmail = idEmail;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public ArrayList<EntityPerson> getPeople() {
return people;
}
public void setPeople(ArrayList<EntityPerson> people) {
this.people = people;
}
}
Like you can appreciate im not a professional and i still have a lot to learn.
So, i was wondering if this approach is correct or if i should have one DAO for each entity.
It looks like you try to invent Generic DAO pattern. If so, you're essentially on the right way.
Generic DAO pattern works as follows:
Create a generic base class that all your DAOs will extend:
public abstract class GenericDao<E, ID extends Serializable> {
...
// Implement common operations that are relevant to all entities here:
public E findById(ID id) { ... }
public void save(E entity) { ... }
// etc
...
}
Create concrete DAO implementations by extending GenericDao:
public class EntityEmailDao extends GenericDao<EntityEmail, Integer> {
// This class may contain operations that are relevant to specific entity:
public E findByEmail(String email) { ... }
}
Since GenericDao is generic, you don't need to make your entities extend any common interface
There are plenty of exisiting implementations of this pattern around, take a look, for example, here.
I am trying to use FullTextEntityManager (and Spring) but getting a 'Session is closed' exception. I am able to query fine the first time, but the 2nd time, the exception is thrown. Here's my config:
#Service
#Transactional(readOnly = true, propagation=Propagation.SUPPORTS)
public class SearchServiceImpl extends BaseService implements SearchService {
public List<StrainSearchResultsListItem> advancedSearch(Pageable page,String species) {
return searchRepository.advancedSearch(page, species);
}
Repo impl:
#Repository
#Transactional(readOnly = true)
public class SearchRepositoryImpl implements SearchRepository {
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
protected FullTextEntityManager getFullTextEntityManager() {
if (fullTextEntityManager == null) {
fullTextEntityManager = Search.getFullTextEntityManager(getEntityManager());
}
return fullTextEntityManager;
}
As soon as I call fullTestQuery.getResultList() the second time, it hurls with a 'Session is closed' exception.
FullTextQuery fullTextQuery =
getFullTextEntityManager()
.createFullTextQuery(booleanQuery, Strain.class);
fullTextQuery.getResultList()
Any ideas are appreciated.
thanks
It might be that you forgot to enable TransactionManagement in your spring configuration file. #EnableTransactionManagement to a spring configuration file to enable transaction management.
Your entity class should be like this-
#Entity
#Table(name="keywordsentity")
#Indexed
#AnalyzerDef(
name="fulltext",
tokenizer=#TokenizerDef(factory=StandardTokenizerFactory.class),
filters={
#TokenFilterDef(factory=LowerCaseFilterFactory.class),
#TokenFilterDef(factory=SnowballPorterFilterFactory.class,
params={#Parameter(name="language", value="English") })
}
)
public class Keywordsentity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#JsonProperty
//index = Index.YES, analyze=Analyze.YES, store = Store.YES
#Field
#Analyzer(definition="fulltext")
private String keywordname;
And Your service class should be like this
#Service
public class KeywordService {
#PersistenceContext(type = PersistenceContextType.EXTENDED, name = "keywordPU")
private EntityManager em;
private FullTextEntityManager ftem;
public void updateFullTextIndex() throws Exception {
getFullTextEntityManager().createIndexer().startAndWait();
}
protected FullTextEntityManager getFullTextEntityManager() {
if (ftem == null) {
ftem = Search.getFullTextEntityManager(em);
}
return ftem;
}
#Transactional
public List<Keywordsentity> search(String summary, String description)
{
String searchString = summary.concat(" ").concat(description);
System.out.println("searchString-----------------------------"+searchString);
QueryBuilder qb = getFullTextEntityManager().getSearchFactory().buildQueryBuilder().forEntity(Keywordsentity.class).get();
//lucene query
org.apache.lucene.search.Query query = qb
.keyword()
.onField("keywordname").matching(searchString)
.createQuery();
Query fullTextQuery = getFullTextEntityManager().createFullTextQuery(query, Keywordsentity.class);
System.out.println("fullTextQuery------------------================="+fullTextQuery);
List<Keywordsentity> result = new ArrayList<Keywordsentity>();
try
{
result = fullTextQuery.getResultList();
}
catch(Exception e)
{
e.printStackTrace();
}
System.out.println("size --------------------=========="+result.size());
for (Keywordsentity keywordone : result) {
System.out.println("keyword------------"+keywordone);
Map<String,String> team =new HashMap<String,String>();
Set<Teamsentity> teams= keywordone.getTeamsentity();
{
for(Teamsentity teamsentityone :teams )
{
String ids = String.valueOf(teamsentityone.getId());
team.put("id",ids);
team.put("name",teamsentityone.getName());
team.put("description",teamsentityone.getDescription());
}
System.out.println("teams =================="+teams);
}
}
return result;
}
}
Then Repository and controller should be normal way nothing else.
In dependency only one -
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-search-orm</artifactId>
<version>5.10.5.Final</version>
</dependency>