How to display hibernate search results using QueryBuilder, Lucene Query & FullTextQuery? - java

How to display results using FullTextEntity Manager with order clause only.
EntityManager em = factory.createEntityManager();
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(em);
QueryBuilder qb = fullTextEntityManager.getSearchFactory()
.buildQueryBuilder().forEntity( Desh.class ).get();
org.apache.lucene.search.Query query = new org.apache.lucene.search.MatchAllDocsQuery();
//Also used qb.all().getQuery(); but no results
FullTextQuery fullTextQuery = fullTextEntityManager.createFullTextQuery(query, Desh.class);
System.out.println(""+ query);
System.out.println(""+ query.toString());
fullTextQuery.setSort(new Sort(new SortField("DeshName_for_sort", SortField.STRING, true)));
//Also used DESH but no results
fullTextQuery.setFirstResult(0).setMaxResults(60);
System.out.println("" + fullTextQuery);
System.out.println("" + fullTextQuery.getParameters());
int size = fullTextQuery.getResultSize();
List<Desh> result = fullTextQuery.getResultList();
System.out.println("Size e -> "+ size);
System.out.println("Size e -> "+ result.size());
for (Deshuser : result) {
System.out.println("Id: " + user.getId());
System.out.println("Person Id:" + user.getName());
}
Desh - Entity Class:
#Entity
#Table(name = "DESH")
#XmlRootElement
#Indexed
public class Desh implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "ID")
private Long id;
#Fields({ #Field(index = Index.YES, store = Store.NO), #Field(name = "DeshName_for_sort", index = Index.YES, analyze = Analyze.NO) })
#Column(name = "NAME", length = 100)
private String name;
public Desh () {
}
public Desh (Long id) {
this.id = id;
}
public Desh (Long id) {
this.id = id;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "in.hibprac.hibernatepractice.Desh[ id=" + id + " ]";
}
}
When i run above program, it returns no size. But when i return using Namedquery and Native Query it executes fine. Even when i remove sorting statements in code, it returns nothing. Could anyone guide me where the problem is?

try this :
FullTextEntityManager ftem=Search.getFullTextEntityManager(entityManager);
ftem.createIndexer().startAndWait();
to launch an indexation targetting all entities annotated with #Indexed

Related

'select count(*) from' is replaced by 'select count(where)' in spring jpa native query when using pagination

I am using a native query in JPA repository inside #Query annotation
#Query(value = " select * from message where id in(select if(coalesce(a.maxId,0)>coalesce(b.maxId,0), a.maxId, b.maxId) maxId from (select from_number, to_number, " +
" max(id) maxId,direction,type from message where direction='INCOMING' group by from_number, to_number having sum(type= :type)) as a " +
" left join ( select from_number, to_number, max(id) maxId, direction, type from message where direction = 'OUTGOING' and schedule_id is null " +
" group by from_number, to_number) as b on a.from_number=b.to_number and a.to_number=b.from_number) order by generated_time desc ", nativeQuery = true)
Page<Message> getLatestMessageFromThread(#Param("type") String type, Pageable page);
The problem is when i execute this query i am getting syntax error. When i checked the logs it is showing that the query to take count of total messages in query is like below
select count(where) from message where id in(select if(coalesce(a.maxId,0)>coalesce(b.maxId,0),
a.maxId, b.maxId) maxId from (select from_number, to_number, max(id) maxId,direction,type from
message where direction='INCOMING' group by from_number, to_number having sum(type= 'REVIEW'))
as a left join ( select from_number, to_number, max(id) maxId, direction, type from message
where direction = 'OUTGOING' and schedule_id is null group by from_number, to_number) as b
on a.from_number=b.to_number and a.to_number=b.from_number)
The count(*) is replaced by count(where)
The entity class for message table is here.
#Entity
#Table(name = "message")
public class Message implements Comparable<Message> {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private Long id;
#Column(name = "to_number")
private String toNumber;
#Column(name = "from_number")
private String fromNumber;
#Column(name = "message")
private String message;
#Enumerated(EnumType.STRING)
#Column(name = "direction")
private MessageDirection direction;
#Enumerated(EnumType.STRING)
#Column(name = "status")
private MessageStatus status;
#Enumerated(EnumType.STRING)
#Column(name = "type")
private KeywordType type;
#Column(name = "keyword_matched")
private String keywordMatched;
#Column(name = "generated_time")
private Timestamp generatedTime;
#Column(name = "scheduled_time")
private Timestamp scheduledTime;
#Column(name = "details")
private String details;
#Enumerated(EnumType.STRING)
#Column(name = "read_status")
private MessageReadStatus readStatus;
#Column(name = "delivery_code")
private String deliveryCode;
#Column(name = "delivery_description")
private String deliveryDescription;
#Column(name = "data", columnDefinition = "json")
private String messageData;
#ManyToOne
#JoinColumn(name = "schedule_id")
private Schedule schedule;
public Message() {
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getToNumber() {
return toNumber;
}
public void setToNumber(String toNumber) {
this.toNumber = toNumber;
}
public String getFromNumber() {
return fromNumber;
}
public void setFromNumber(String fromNumber) {
this.fromNumber = fromNumber;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public MessageDirection getDirection() {
return direction;
}
public void setDirection(MessageDirection direction) {
this.direction = direction;
}
public MessageStatus getStatus() {
return status;
}
public void setStatus(MessageStatus status) {
this.status = status;
}
public KeywordType getType() {
return type;
}
public void setType(KeywordType type) {
this.type = type;
}
public Timestamp getGeneratedTime() {
return generatedTime;
}
public void setGeneratedTime(Timestamp generatedTime) {
this.generatedTime = generatedTime;
}
public Timestamp getScheduledTime() {
return scheduledTime;
}
public void setScheduledTime(Timestamp scheduledTime) {
this.scheduledTime = scheduledTime;
}
public Schedule getSchedule() {
return schedule;
}
public void setSchedule(Schedule schedule) {
this.schedule = schedule;
}
public String getKeywordMatched() {
return keywordMatched;
}
public void setKeywordMatched(String keywordMatched) {
this.keywordMatched = keywordMatched;
}
public String getDetails() {
return details;
}
public void setDetails(String details) {
this.details = details;
}
public MessageReadStatus getReadStatus() {
return readStatus;
}
public void setReadStatus(MessageReadStatus readStatus) {
this.readStatus = readStatus;
}
public String getDeliveryCode() {
return deliveryCode;
}
public void setDeliveryCode(String deliveryCode) {
this.deliveryCode = deliveryCode;
}
public String getMessageData() {
return messageData;
}
public void setMessageData(String messageData) {
this.messageData = messageData;
}
public String getDeliveryDescription() {
return deliveryDescription;
}
public void setDeliveryDescription(String deliveryDescription) {
this.deliveryDescription = deliveryDescription;
}
}
Why it is getting replaced. How can i write the query in correct way ?
The solution is to use countQuery annotation parameter :
public interface Repository extends JpaRepository<Entity, Long> {
String QUERY = "FROM entity " +
" WHERE name ILIKE :name ";
#Query(
value = "SELECT * " + QUERY,
countQuery = "SELECT count(*) " + QUERY,
nativeQuery = true
)
Page<KDeploymentView> findBy(
#Param("name") String name,
Pageable p
);

Why JPA entity throws exception when rowKey attribute is the primary key?

I'm using JavaEE to build a very simple Java full stack app, so I'm using JSF with Prime Faces 6.2 to render an xthml in the frontend and EJB, JPA with Hibernate and postgresql in the backend, however, When I set rowKey="#{person.id}" from a dataTable component from Prime Faces. Next exception is thrown.
"00:13:36,307 ERROR [io.undertow.request] (default task-55) UT005023: Exception handling request to /javaee-app/faces/listPersons.xhtml: javax.servlet.ServletException ... Caused by:java.lang.NullPointerException"
listPersons.xhtml
Prime Faces DataTable Component(opening tag and its attributes)
<p:dataTable id="persons"
value="#{personBean.persons}"
var="person"
editable="true"
rowKey="#{person.id}"
selection="#{personBean.personSelected}"
selectionMode="single">
The exception thrown that appears when trying to render the page is this.
However, if I set rowKey="#{person.name}" or even rowKey="#{person.email}" in stead of rowKey="#{person.id}" the problem disappears and xthml page is rendered correctly.
<p:dataTable id="persons"
value="#{personBean.persons}"
var="person"
editable="true"
rowKey="#{person.name}"
selection="#{personBean.personSelected}"
selectionMode="single">
with rowKey="#{person.name}" or rowKey="#{person.email}" xhtml page is rendered correctly"
Postgresql Database person
MODEL/ENTITY
#Entity
#Table(name = "person")
#NamedQueries({
#NamedQuery(name = "Person.findAll", query = "SELECT p FROM Person p"),
#NamedQuery(name = "Person.findById", query = "SELECT p FROM Person p
WHERE p.id = :id")
, #NamedQuery(name = "Person.findByName", query = "SELECT p FROM
Person p WHERE p.name = :person_name")
, #NamedQuery(name = "Person.findByLastname", query = "SELECT p FROM
Person p WHERE p.lastname = :lastname")
, #NamedQuery(name = "Person.findByEmail", query = "SELECT p
FROM Person p WHERE p.email = :email")
, #NamedQuery(name = "Person.findByPhone", query = "SELECT p
FROM Person p WHERE p.phone = :phone")})
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 60)
#Column(name = "person_name")
private String name;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 60)
private String lastname;
#Basic(optional = false)
#NotNull
#Size(min = 1, max = 60)
private String email;
#Size(max = 60)
private String phone;
#OneToMany(mappedBy = "person", fetch = FetchType.EAGER)
private List<Users> users;
public Person() { }
public Person(Integer id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public List<Users> getUsers() {
return users;
}
public void setUsers(List<Users> users) {
this.users = users;
}
#Override
public int hashCode() {
int hash = 0;
hash += (id != null ? id.hashCode() : 0);
return hash;
}
#Override
public boolean equals(Object object) {
if (!(object instanceof Person)) {
return false;
}
Person other = (Person) object;
if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
return false;
}
return true;
}
#Override
public String toString() {
return "Person [id = " + id + ", name=" + name
+ ", lastName=" + lastname + " email=" + email + ", phone=" + phone + "]";
}
Any idea to solve this problem guys? Thanks in advance
I'm also adding the images of the errors generated in the application server, in my case Wildfly 8.2
picture1 Wildfly 8.2
picture2 Wildfly 8.2
The id is of type Integer:
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
Where as the getter returns int:
public int getId() {
return id;
}
Change getId to return Integer.

delete query with where clause in HQL

I am new to hql and trying to delete the complete row in case of a match based on email.
Following is what I have tried.
Still I get a Persistence Exception.
public void unsubscribeEmailList(EmailListDto dataList) {
EmailList e =new EmailList(dataList);
Query q =sessionFactory.getCurrentSession().createQuery("delete from EmailList where email=:e");
q.setParameter("e", dataList);
int i=q.executeUpdate();
System.out.println(i);
}
Class EmailList is
#Entity
#Table(name = "email_list")
public class EmailList implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String email;
public EmailList(EmailListDto dto)
{
this.email=dto.getEmail();
}
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#Column(name = "email", nullable = false)
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
Try use this:
q.setParameter("e", e.getEmail());
public void unsubscribeEmailList(EmailListDto dataList) {
EmailList e =new EmailList(dataList);
Query q =sessionFactory.getCurrentSession().createQuery("delete from EmailList where email = :e");
q.setParameter("e", e.egetEmail() );
int i=q.executeUpdate();
System.out.println(i);
}
...
#NamedQueries(
{
#NamedQuery(name = "FindAllJobsEngineersParticipateInInterval",
query = "SELECT je.id FROM Stage1JobEngineer AS je " +
"JOIN je.job AS s1j " +
"WHERE "
+ " :absenceStartDateTime <= :absenceEndDateTime "
+ " AND :absenceStartDateTime <= s1j.endTime AND :absenceEndDateTime >= s1j.startTime " +
" AND je.engineer.id IN (:engineerIds) ")
})
#Entity
#Table(name = "ho_stage1_job_has_engineers")
public class Stage1JobEngineer extends CreatedByUserEntity implements Serializable {
...
...
// dao service call :
Query query = getSession().getNamedQuery( "FindAllJobsEngineersParticipateInInterval" );
query.setParameter( "absenceStartDateTime", startDate )
.setParameter( "absenceEndDateTime", endDate )
.setParameterList( "engineerIds", Arrays.asList(1L, 2L, 33L) );
List<Long> queryResult = query.list();
List<Long> result = queryRes != null ? queryResult : new ArrayList<>();
...

How do I update multiple tables inside a named query?

I am using Eclipselink v2.3.3
I am getting this error
Error compiling the query [Credential.updateExistingCredentialNoPW: UPDATE Credential c SET c.active = :active, c.employee.address.streetAddress = :stadd, c.employee.address.city = :city, c.employee.address.province = :prov, c.employee.address.zip = :zip WHERE c.id = :id], line 1, column 46: invalid navigation expression [c.employee], cannot navigate association field [employee] in the SET clause target.
when I try to run my code.
Here are the affected named queries that prevents running my code
#NamedQuery(name = "Credential.updateExistingCredentialNoPW",
query = "UPDATE Credential c "
+ "SET c.active = :active, "
+ "c.employee.address.streetAddress = :stadd, "
+ "c.employee.address.city = :city, "
+ "c.employee.address.province = :prov, "
+ "c.employee.address.zip = :zip "
+ "WHERE c.id = :id"),
#NamedQuery(name = "Credential.updateExistingCredential",
query = "UPDATE Credential c "
+ "SET c.password = :pw, "
+ "c.active = :active, "
+ "c.employee.address.streetAddress = :stadd, "
+ "c.employee.address.city = :city, "
+ "c.employee.address.province = :prov, "
+ "c.employee.address.zip = :zip "
+ "WHERE c.id = :id"),
#NamedQuery(name = "Credential.updateSalary",
query = "UPDATE Credential c "
+ "SET c.employee.salary.value = :val WHERE c.id = :id")
Here is the class where I put all the named queries specified above
public class Credential implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(generator = "CRED_GEN", strategy = GenerationType.IDENTITY)
#Column(name = "CREDENTIAL_ID")
private long id;
// unique & not nullabe username
#Column(nullable = false, unique = true)
private String username;
#Column(nullable = false, name = "USER_KEY")
private String password;
#Column(nullable = false)
private boolean active;
#Column(nullable = false)
private int userLevel;
#OneToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
private Employee employee;
public Credential() {
}
public Credential(String username, String password, boolean active,
int userLevel, Employee employee) throws NoSuchAlgorithmException {
this.username = username;
this.setPassword(password);
this.active = active;
this.userLevel = userLevel;
this.employee = employee;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public int getUserLevel() {
return userLevel;
}
public void setUserLevel(int userLevel) {
this.userLevel = userLevel;
}
public boolean isActive() {
return active;
}
public void setActive(boolean active) {
this.active = active;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public String getPassword() {
return password;
}
public void setPassword(String password) throws NoSuchAlgorithmException {
this.password = Cryptography.getHash(password);
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
Am I doing it wrong?
It is not possible to update multiple tables with single sql query.
See https://forums.oracle.com/forums/thread.jspa?threadID=2223393.
So it's also not possible with Eclipselink.
You'll have to split this it two queries, or better use setters.
You can't. Either use a SQL query, or use Java code:
Credential c = em.find(Credential.class, credentialId);
c.setActive(active);
c.getEmployee().getAddress().setStreet(street);
...

Hibernate - fetch only the latest versions of elements in contained collection

I have an entity :
#Entity
#DiscriminatorValue("News")
public class News extends TVProduction {
private int audience;
private Collection<Reportage> reportages;
public News() {
super();
setAudience(0);
}
#Column(name = "audience")
public int getAudience() {
return audience;
}
public void setAudience(int audience) {
this.audience = audience;
}
#OneToMany
#JoinTable(name = "Reportages_News",
joinColumns = #JoinColumn(name = "news_id"),
inverseJoinColumns = #JoinColumn(name = "reportage_id")
)
public Collection<Reportage> getReportages() {
return reportages;
}
public void setReportages(Collection<Reportage> reportages) {
this.reportages = reportages;
}
}
And Reportage class looks like this:
#Entity
#Table(name = "Reportage")
public class Reportage {
private Long id;
private String subject;
private int version;
private String content;
private Reporter reporter;
public String getSubject() {
return subject;
}
public void setSubject(String subject) {
this.subject = subject;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
#SuppressWarnings("unused")
private void setId(Long id) {
this.id = id;
}
#ManyToOne
#JoinColumn(name = "reporter_fk")
public Reporter getReporter() {
return reporter;
}
public void setReporter(Reporter reporter) {
this.reporter = reporter;
}
}
What I want is to have only the highest versions of Reportages fetched while fetching News. I tried to annotate Reportage with:
#Loader(namedQuery = "fetchFinal")
#NamedNativeQuery(name = "fetchFinal", query = "SELECT t.* FROM" +
"(SELECT id, subject, max(version) maxVersion, content, reporter" +
"FROM reportage GROUP BY id) x" +
"JOIN reportage t ON x.id = t.id AND x.maxVersion = t.version AND t.id = ?"
)
but It doesn't work, saying:
Initial SessionFactory creation failed.org.hibernate.cfg.NotYetImplementedException: Pure native scalar queries are not yet supported
Any idea how to get it done?
How about:
select * from reportage t where t.version = (select max(t2.version) from reportage t2)
UPDATE:
Have not tried this myself:
#NamedNativeQuery(name = "fetchFinal", query = "SELECT t.* FROM" +
"(SELECT id, subject, max(version) maxVersion, content, reporter" +
"FROM reportage GROUP BY id) x" +
"JOIN reportage t ON x.id = t.id AND x.maxVersion = t.version AND t.id = ?",
resultClass=Reportage.class)
= add Resultclass
UPDATE2
If that doesn't work this certainly will (since I've done this myself); using Criteria:
Criteria crit = getSession().createCriteria(Reportage.class);
DetachedCriteria dc = DetachedCriteria.forClass(Reportage.class);
dc.setProjection(Projections.max("version"));
crit.add(Property.forName("version").eq(dc));
return crit.list();

Categories

Resources