I have a database showing the relationship much more like this
I want to get information out of two table gmail and bloggerwith conditions blog[blogger] and user[gmail] value exists in table md_parse_blogger
I want to know how to make a correct syntax where,please help me
public List showDatawebA(String blog, String url) {
String sql = "FROM MdParse g,MdBlogger b,MdParseBlogger pb"
+ " WHERE pb.mdBlogger=:blog and pb.mdParse=:url";
Query createQuery = currentSession.createQuery(sql);
createQuery.setParameter("blog", blog);
createQuery.setParameter("url", url);
return createQuery.list();
}
With mdBlogger,mdGmail is attribute class MdParseBlogger,
public class MdParseBlogger implements java.io.Serializable {
private MdParseBloggerId id;
private MdBlogger mdBlogger;
private MdParse mdParse;
...........
}
ERROR
Exception in thread "main" org.hibernate.QueryParameterException: Position beyond number of declared ordinal parameters. Remember that ordinal parameters are 1-based! Position: 2
at org.hibernate.engine.query.spi.ParameterMetadata.getOrdinalParameterDescriptor(ParameterMetadata.java:89)
at org.hibernate.engine.query.spi.ParameterMetadata.getOrdinalParameterExpectedType(ParameterMetadata.java:109)
at org.hibernate.internal.AbstractQueryImpl.determineType(AbstractQueryImpl.java:507)
at org.hibernate.internal.AbstractQueryImpl.setParameter(AbstractQueryImpl.java:479)
at dbUtility.DBTable.showDataweb(DBTable.java:76)
at dbUtility.DBTable.main(DBTable.java:83)
Picked up _JAVA_OPTIONS: -Xmx512M
You mixed named and ordinal parameters. It should be either
String sql ="FROM MdGmail g,MdBlogger b,MdParseBlogger pb"
+ " WHERE pb.mdBlogger=? and pb.mdGmail=?";
Query createQuery = currentSession.createQuery(sql);
createQuery.setParameter(1, blog);
createQuery.setParameter(2, url);
Or
String sql ="FROM MdGmail g,MdBlogger b,MdParseBlogger pb"
+ " WHERE pb.mdBlogger=:blog and pb.mdGmail=:url";
Query createQuery = currentSession.createQuery(sql);
createQuery.setParameter("blog", blog);
createQuery.setParameter("url", url);
Related
I have an issue with mapping retrieved data via JDBi3 using PostgreSQL query in my DAO interface.
In my Dropwizard app I have Book DTO class which is has Many-To-Many relation with Author and Category DTO classes and have a problem with mapping queried rows onto BookDTO class. Here are the code snippets of DTO classes:
class BookDTO {
private Long bookId;
// other fields are left for code brevity
private List<Long> authors;
private List<Long> categories;
// empty constructor + constructor with all fields excluding Lists + getters + setters
}
class AuthorDTO {
private Long authorId;
// other fields are left for code brevity
private List<Long> books;
// empty constructor + constructor with all fields excluding List + getters + setters
}
class CategoryDTO {
private Long categoryId;
// other fields are left for code brevity
private List<Long> books;
// empty constructor + constructor with all fields excluding List + getters + setters
}
...and since I am using JDBi3 DAO interfaces for performing CRUD operations this is how my method for querying all books in database looks like:
#Transaction
#UseRowMapper(BookDTOACMapper.class)
#SqlQuery("SELECT book.book_id AS b_id, book.title, book.price, book.amount, book.is_deleted, author.author_id AS aut_id, category.category_id AS cat_id FROM book " +
"LEFT JOIN author_book ON book.book_id = author_book.book_id " +
"LEFT JOIN author ON author_book.author_id = author.author_id " +
"LEFT JOIN category_book ON book.book_id = category_book.book_id " +
"LEFT JOIN category ON category_book.category_id = category.category_id ORDER BY b_id ASC, aut_id ASC, cat_id ASC")
List<BookDTO> getAllBooks();
...and this is map method of BookDTOACMapper class look like:
public class BookDTOACMapper implements RowMapper<BookDTO> {
#Override
public BookDTO map(ResultSet rs, StatementContext ctx) throws SQLException {
final long bookId = rs.getLong("b_id");
// normally retrieving values by using appropriate rs.getXXX() methods
Set<Long> authorIds = new HashSet<>();
Set<Long> categoryIds = new HashSet<>();
long authorId = rs.getLong("aut_id");
if (authorId > 0) {
authorIds.add(authorId);
}
long categoryId = rs.getLong("cat_id");
if (categoryId > 0) {
categoryIds.add(categoryId);
}
while (rs.next()) {
if (rs.getLong("b_id") != bookId) {
break;
} else {
authorId = rs.getLong("aut_id");
if (authorId > 0) { authorIds.add(authorId); }
categoryId = rs.getLong("cat_id");
if (categoryId > 0) { categoryIds.add(categoryId); }
}
}
final List<Long> authorIdsList = new ArrayList<>(authorIds);
final List<Long> categoryIdsList = new ArrayList<>(categoryIds);
return new BookDTO(bookId, title, price, amount, is_deleted, authorIdsList, categoryIdsList);
}
}
Problem I encounter is that when invoking my GET method (defined in Resource class which invokes getAllBooks() method from BookDAO class) displays inconsistent results while the query itself returns proper results.
Many questions that I've managed to find on Stackoverflow, official JDBi3 Docs API and Google Groups are considering One-To-Many relationship and using #UseRowReducer annotation which contains class which impelements LinkedHashMapRowReducer<TypeOfEntityIdentifier, EntityName> but for this case I could not find a way to implement it. Any example/suggestion is welcome. :)
Thank you in advance.
Versions of used tools:
Dropwizard framework 1.3.8
PostgreSQL 11.7
Java8
This will be too long for a comment:
This is basically a debugging question. Why?
while (rs.next()) {
if (rs.getLong("b_id") != bookId) {
break;
} else {
The firstif after the while is eating the row after the current (the one that wass current when the row mapper is called). You are skipping the processing there (putting the data in the Java objects) for the bookId, authorId, etc. That's why you get
inconsistent results while the query itself returns proper results.
So you need to revisit how you process the data. I see two paths:
Revisit the logic of the processing loop to store the data when stopping the processing for given bookId. It is possible to achieve this with scrollable ResultSets - i.e. request a scrollable ResultSet and before the brake; call rs.previous(). On the next call to the row mapper the processing will start from the correct line in the result set.
Use the power of the SQL/PostgreSQL and do it properly: https://dba.stackexchange.com/questions/173831/convert-right-side-of-join-of-many-to-many-into-array Aggregate and shape the data in the database. The database is the best tool for this job.
Also take your time and check the other answers of https://dba.stackexchange.com/users/3684/erwin-brandstetter. They give invaluable insights in the SQL and PostgreSQL.
As zloster mentioned in his answer I've chosen 2nd option (by this answer for Many-To-Many relationships) which was to use edit my PostgreSQL query #SqlQuery annotation above List<BookDTO> getAllBooks(); method. Query now uses array_agg aggregate function in SELECT statement to group my results in an ARRAY and now looks like this:
#UseRowMapper(BookDTOACMapper.class)
#SqlQuery("SELECT b.book_id AS b_id, b.title, b.price, b.amount, b.is_deleted, ARRAY_AGG(aut.author_id) as aut_ids, ARRAY_AGG(cat.category_id) as cat_ids " +
"FROM book b " +
"LEFT JOIN author_book ON author_book.book_id = b.book_id " +
"LEFT JOIN author aut ON aut.author_id = author_book.author_id " +
"LEFT JOIN category_book ON category_book.book_id = b.book_id " +
"LEFT JOIN category cat ON cat.category_id = category_book.category_id " +
"GROUP BY b_id " +
"ORDER BY b_id ASC")
List<BookDTO> getAllBooks();
Therefore map(..) method of BookDTOACMapper class had to be edited and now looks like this:
#Override
public BookDTO map(ResultSet rs, StatementContext ctx) throws SQLException {
final long bookId = rs.getLong("b_id");
String title = rs.getString("title");
double price = rs.getDouble("price");
int amount = rs.getInt("amount");
boolean is_deleted = rs.getBoolean("is_deleted");
Set<Long> authorIds = new HashSet<>();
Set<Long> categoryIds = new HashSet<>();
/* rs.getArray() retrives java.sql.Array and after it getArray gets
invoked which returns array of Object(s) which are being casted
into array of Long elements */
Long[] autIds = (Long[]) (rs.getArray("aut_ids").getArray());
Long[] catIds = (Long[]) (rs.getArray("cat_ids").getArray());
Collections.addAll(authorIds, autIds);
Collections.addAll(categoryIds, catIds);
final List<Long> authorIdsList = new ArrayList<>(authorIds);
final List<Long> categoryIdsList = new ArrayList<>(categoryIds);
return new BookDTO(bookId, title, price, amount, is_deleted, authorIdsList, categoryIdsList);
}
Now all results are consistent and here's a screenshot of query in pgAdmin4.
I have the hql query that I am executing but receive an error that I don't really understand the cause of.
This is my code:
#Override
public List<StaffRequest> getStaffLeaveRequest(String userID, Date startDate, Date endDate)
{
Session currentSession = sessionFactory.getCurrentSession();
List<StaffRequest> results =
currentSession.createQuery("select new com.timesheet_Webservice.CustomEntity.StaffRequest(lr.leave_ID, lr.leave_Employee, concat(s.staff_First_Name, ' ', s.staff_Last_Name), "
+ "(lr.leave_Days*8.5), lr.leave_Comments, '1805', concat(pro.project_Pastel_Prefix, ' - ', pro.project_Description), lr.leave_Start, lr.leave_End, lr.leave_IsApproved, "
+ "(select lt.leaveType_Description from LeaveType lt where lt.leaveType_ID = lr.leave_Type)) "
+ "from Staff s, Project pro, Leave lr "
+ "where lr.leave_Employee = s.staff_Code and pro.project_Code = 1805 and lr.leave_Approved = :userID and lr.leave_IsApproved = 0 and s.staff_IsEmployee <> 0 "
+ "and lr.leave_Start between :startDate and :endDate "
+ "order by concat(s.staff_First_Name, ' ', s.staff_Last_Name)")
.setParameter("userID",userID).setParameter("startDate", startDate).setParameter("endDate", endDate).getResultList();
return results;
}
I get this error on the webpage when trying to execute it:
org.hibernate.exception.SQLGrammarException: could not extract
ResultSet
And also this console error:
ERROR: You have an error in your SQL syntax; check the manual that
corresponds to your MariaDB server version for the right syntax to use
near 'Leave leave2_ where leave2_.Leave_Employee=staff0_.Staff_Code
and project1_.Proj' at line 1
It seems to indicate some fault at the where clause, but I don't see anything particularly wrong.
UPDATE:
Entity classes
Project
#Entity
#Table(name="project")
public class Project {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="Project_Code")
public int project_Code;
#Column(name="Project_Customer")
public int project_Customer;
//A lot more attributes...
}
Staff
#Entity
#Table(name="staff")
public class Staff
{
#Id
#Column(name="Staff_Code")
public String staff_Code;
...
}
1) As you using java.util.Date for Leave.leave_Start, you should annotate with proper #Temporal value:
#Temporal(TemporalType.TIMESTAMP)
#Column(name="Leave_Start")
Date leave_Start;
2) When setting your query date parameters, try using:
.setDate("startDate", startDate)
or
.setParameter("startDate", startDate, TemporalType.TIMESTAMP)
Ok, after much testing I discovered the reason for the error. For some unknown reason the query seems to have a problem with the name of the referenced table 'leave' and produces the error whenever I try to retrieve data from it. If I however rename the table to something as simple as 'leaves' then the query executes successfully. Anyone might know why this is?
Apparently JPA follows some rule or convention of variable names and does not accept "_" and for some reason does not accept intermediate capital letters... It worked for me by changing all variables to lowercase
I have a field in one of my tables that has a field to store urls and the POJO for that table is as follows:
public class ContentDefinition
{
private String contentName;
private int contentId;
private String contentType;
private String contentUrl;
}
I am trying to write a query to check if the contentUrl field contains url that ends with the string address-book.
I am using the following query:
String hql = " from ContentDefinition WHERE contentUrl LIKE '%'address-book'%'";
Query query = getCurrentSession().createQuery(hql);
List<ContentDefinition> resultsList = query.list();
but I am getting an exception:
org.hibernate.hql.ast.QuerySyntaxException: unexpected token: address near line 1, column 130
Is there any solution, my url can be anything, but always ends with /address-book
String hql = " from ContentDefinition WHERE contentUrl LIKE :addressBook ";
Query query = getCurrentSession().createQuery(hql);
query.setParameter("addressBook","address-book");
List<ContentDefinition> resultsList = query.list();
String hql = " from ContentDefinition WHERE contentUrl LIKE '%address-book%' ";
Change above line. Rest of code looks good. I have tested a similar code.
Read upon chapter SQL LIKE Operator.
The doc says:
The LIKE operator is used in a WHERE clause to search for a specified pattern in a column.
where animalType like '%cats%'
Which means, you should change your query from:
String hql = " from ContentDefinition WHERE contentUrl LIKE '%'address-book'%'";
to
String hql = " from ContentDefinition WHERE contentUrl LIKE '%address-book%'";
I have got a working query, which I need to modify by filtering with constant enum value.
Now it looks this way:
public static final String venueQuery =
"select distinct v from package.Venue v "
+ "<some joins here> "
+ "WHERE v.venueType = package.enums.VenueType.VOUCHER_PROVIDER ";
Changing data this way causes
org.hibernate.hql.internal.ast.QuerySyntaxException: unexpected token
Column definition is like this:
#Enumerated(EnumType.STRING)
#Column(name = "venue_type")
private VenueType venueType;
Enum definition looks this way:
public enum VenueType {
RESTAURANT, BAR, CAFE, FUN_CLUB, VOUCHER_PROVIDER
}
I am sure that other parts of query works fine, because after removing it, no exceptions are thrown.
Are there tricks for setting constant enum value in HQL query?
The preferred way would be to go about adding parameters to the query and pass the enum instance as the parameter value, but if you don't (or can't) make it a parameterized query, you can still do it with String concatenation like this:
public static final String venueQuery =
"select distinct v from package.Venue v "
+ "<some joins here> "
+ "WHERE v.venueType = '" + VenueType.VOUCHER_PROVIDER.name() +"'";
If you want it a compile time constant query String:
public static final String venueQuery =
"select distinct v from package.Venue v "
+ "<some joins here> "
+ "WHERE v.venueType = 'VOUCHER_PROVIDER'";
I have several entities that have transient properties that I would like to populate from the sql query. I have tried several things but have not found the correct combination yet.
here is an example entity
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
long id;
#Size(max=1000)
String image_url;
#Transient
boolean liked;
#Transient
long numLikes;
**getters and setters** for persistent properties
public boolean isLiked() {
return liked;
}
public void setLiked(boolean liked) {
this.liked = liked;
}
public long getNumLikes() {
return numLikes;
}
public void setNumLikes(long numLikes) {
this.numLikes = numLikes;
}
I have tried using the #Basic anotation and setting it's fetch method to eager
#Basic(fetch = FetchType.EAGER)
on the getters but that didn't seem to do anything. I've seen it set to lazy as well.
Am I missing anything in here that would cause a column name not be mapped to one of these transient properties?
here is my impl code.
SQLQuery query = getCurrentSession().createSQLQuery("" +
"SELECT * ,count(likes1.liked) as numLikes " +
"FROM aboutme " +
"left JOIN " +
"(" +
" select liked, likedObject_id " +
" from likes " +
" where liked = 1" +
") as likes1 ON aboutme.id = likes1.likedObject_id " +
"left join " +
"(" +
" select likedObject_id, liked " +
" from likes " +
" where liked = 1 and profile_id = :id" +
") as likes2 on likes2.likedObject_id = aboutme.id " +
"WHERE aboutme.profile_id = :id " +
"group by aboutme.id");
query.addEntity(AboutMe.class);
query.setParameter("id",id);
return query.list();
I've tried using the
SQLQuery query = ..."Select count(value that returns properly) as {object.numLikes}..."
query.addEntity("object",Object.class),
I get an error here that says it can't find the column name for property [property] for alias [alias]
What am I doing wrong?
Transient properties are probably not the way to go for what I am trying to do. what I need to figure out is how to map these derived columns to an object that I can return to the front end. how do I set up an object that hibernate can map these aliased columns to properties?
I figured it out. You can set the transient property though it's kind of a pain.
using the addScalar Method on the SQLQuery object you can set the transient properties. However if it is done this way you have to set ALL the properties in the object this way (Hibernate doesn't autofill any properties)
Also you will have to use the setResultTransformer Method also on the SQLQuery object. So to finish off my previous example I would have to add the following code in my impl.
// query.addEntity(AboutMe.class); <- this contradicts the setResultTransformer
query.setParameter("id",id);
query.addScalar("id",StandardBasicTypes.LONG);
query.addScalar("image_url",StandardBasicTypes.LONG);
query.addScalar("liked",StandardBasicTypes.LONG);
query.addScalar("numLikes",StandardBasicTypes.LONG);
query.setResultTransformer(Transformers.aliasToBean(Object.class));
where Object is the class that I am wanting to use that has all these properties declared.
Hibernate will never populate your transient fields and what is most important transient fields are not even part of the java serialization process. What I would try if you really need this - is the ResultTransformer.alliasToBean which is "injecting" the values into the class with reflection.
setResultTransformer(Transformers.aliasToBean(Yourclass.class));
Just a quick idea, not sure whether it will work.