Usually during my work hours i spend a lot of time querying the db(oracle) and parsing blob from various table where the streams that we receive are stored.
There are various type of stream so i was trying to made a simple webapp where i write the select statement and it returns all the stream parsed accordingly.
My problem is that using jpa and executing the simple native query:
select B_BODY from TABLE_B where TRANSACTION_ID = 'GG-148c-01502790743907855009';
the statement doesn't return anything but querying directly the database return the record.
this is my java code:
#Transactional(readOnly = true)
public List<Object[]> retrieveBlobs(String squery) {
squery = squery + " and rownum <= "+maxResults;
Query query = em.createNativeQuery(squery);
List<Object[]> resultList = query.getResultList();
return resultList;
}
this is the sql generated:
Hibernate:
select
B_BODY
from
TABLE_B
where
TRANSACTION_ID ='GG-148c-01502790743907855009'
and rownum <= 100
i know that this way might seems weird but our team spend a lot of time trying to tokenize the stored streams(the code that identify how to parse the stream is also stored in the tables).Useless to say this application is going to be used only internally.there is a way to just execute the query as it is and retrieve the correct output?
Well, I tried to reproduce your problem on MariaDB (with mysql-connector-java + hibernate) but selecting a lob with native query was working properly.
You can try to create entities which will be holding your blob and check if this would help. Just make a standard entity with #Lob annotation over your lob column.
#Entity
#NamedQueries(
#NamedQuery(name = FIND_ALL, query = "SELECT m FROM LobEntity m")
)
public class LobEntity {
public static final String FIND_ALL = "PhpEntity.findAll";
#Id
#Column(name = "id")
private String id;
#Lob
#Column(name = "lob")
private byte[] lob;
//Use Blob class if you want to use streams.
//#Column(name = "lob")
//#Lob
//private Blob lob;
}
Related
I've run into some code which behaviour is not clear for me.
We have first entity:
#Data
#Entity
#Table(name = "Info")
public class Info {
#OneToOne
#JoinColumn(name = "data_id")
private Data data;
}
and second one:
#Data
#Entity
#Table(name = "Data")
public class Data {
#Id
private Long dataId
}
And we have next method for retrieving data:
#Query(value = "SELECT * FROM Info i inner join Data d on d.data_id=i.data_id",
nativeQuery = true)
List<Info> getInfo() {}
As nativeQuery = true is present I expect this method make just one SQL select and retrieve me data. But If I take a look at logs actually there are 2 selects:
SELECT * FROM Info i inner join Data d on d.data_id=i.data_id;
SELECT * FROM Data d where d.data_id = 123;
Why this is happening ? How to fix it to make only one select and retrieve all data ?
It's not possible to specify native query fetches without Hibernate specific APIs. I would suggest you to use a normal JPQL/HQL query:
#Query(value = "FROM Info i join fetch i.data")
List<Info> getInfo();
This will do the same as your native query but at the same time just run only a single query.
I've a database with many thousands of tables that have been (and continue to be) created with a naming strategy - one table per calendar day:
data_2010_01_01
data_2010_01_02
...
data_2020_01_01
All tables contain sensor data from the same system in the same shape. So a single entity (lets call it SensorRecord) will absolutely map to all tables.
I'd imagined something like this would work:
#Query(nativeQuery = true, value = "SELECT * FROM \"?1\"")
Collection<SensorRecord> findSensorDataForDate(String tableName);
But it does not, and reading around the topic seems to suggest I am on the wrong path. Most posts on dynamic naming seem to state explicitly that you need one entity per table, but generating thousands of duplicate entities also seems wrong.
How can I use JPA (JPQL?) to work with this data where the table name follows a naming convention and can be changed as part of the query?
Parameters are only allowed in the where clause.
You can create custom repository method returns collection of SensorRecord dto. No need to map so many entities. You should get List<Object []> as query result and manually create dto objects.
#Autowired
EntityManager entityManager;
public List<SensorRecord> findSensorDataForDate(LocalDate date) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy_MM_dd");
String tableName = "data_" + date.format(formatter);
Query query = entityManager.createNativeQuery(
"select t.first_column, t.second_column from " + tableName + " t");
List<Object[]> queryResults = query.getResultList();
List<SensorRecord> sensorRecords = new ArrayList<>();
for (Object[] row : queryResults) {
SensorRecord record = new SensorRecord();
record.setFirstParameter((Integer) row[0]);
record.setSecondParameter((String) row[1]);
sensorRecords.add(record);
}
return sensorRecords;
}
Could it be just syntax error?
This has worked for me:
#Query(value = "select * from job where job.locked = 1 and job.user = ?1", nativeQuery = true)
public List<JobDAO> getJobsForUser(#Param("user") String user);
I have write a materialized view for full text search against memberstable:
CREATE MATERIALIZED VIEW member_search_index AS
SELECT member.memberid,
member.firstname,
member.lastname,
...
to_tsvector((COALESCE(member.lastname, ' '::character varying))::text) AS document
FROM member
GROUP BY member.memberid;
CREATE INDEX idx_member_search ON member_search_index USING gin(document);
I have created entity and mapped it like this:
#Entity
#Table(name = "MemberSearchIndex")
public class MemberSearch {
#Id
private long memberId;
private String firstName;
private String lastName;
...
}
And here's SQL call I am trying to make:
Query sqlQuery = entityManager.createNativeQuery("SELECT * FROM member_search_index WHERE document ## to_tsquery('doe:*')", MemberSearch.class);
In this example I have hard coded value that I am passing to query doe and the query is returning me 0 elements (it should return 1)
So:
Am I doing mapping correctly?
How to pass parameter to a native query like this? I tried like this .setParameter(1, searchQuery) but I got exception where [1] couldn't be found.
You can use JPQL query instead of native SQL. It will look like this:
Query query = entityManager.createQuery("
SELECT ms
FROM MemberSearch ms
WHERE SQL('to_tsvector(''english'', ?) ## to_tsquery(''english'', ?)', ms.document, ?1)
");
query.setParameter(1, "'doe:*'");
query.getResultList();
I am currently working on a project to transfer some legacy jdbc select statements over to using Hibernate and it's criteria api.
The two relevant table columns and the SQL query looks like:
-QUERIES-
primaryId
-QUERYDETAILS-
primaryId
linkedQueryId -> Foreign key references queries.primaryId
value1
value2
select *
from queries q
where q.primaryId not in (SELECT qd.linkedQueryId
FROM querydetails qd
WHERE (qd.value1 LIKE 'PROMPT%'
OR qd.value2 LIKE 'PROMPT%'));
My entity relationships look like:
#Table("queries")
public class QueryEntity{
#Id
#Column
private Long primaryId;
#OneToMany(targetEntity = QueryDetailEntity.class, mappedBy = "query", fetch = FetchType.EAGER)
private Set<QueryDetailEntities> queryDetails;
//..getters/setters..
}
#Entity
#Table(name = "queryDetails")
public class QueryDetailEntity {
#Id
#Column
private Long primaryId;
#ManyToOne(targetEntity = QueryEntity.class)
private QueryEntity query;
#Column(name="value1")
private String value1;
#Column(name="value2")
private String value2;
//..getters/setters..
}
I am attempting to utilize the criteria api in this way:
Criteria crit = sessionFactory.getCurrentSession().createCriteria(QueryEntity.class);
DetachedCriteria subQuery = DetachedCriteria.forClass(QueryDetailEntity.class);
LogicalExpression hasPrompt = Restrictions.or(Restrictions.ilike("value1", "PROMPT%"),
Restrictions.ilike("value2", "PROMPT%"));
subQuery.add(hasPrompt);
Criterion subQueryCrit = Subqueries.notIn("queryDetails", subQuery);
crit.add(subQueryCrit);
List<QueryMainEntity> entities = (List<QueryMainEntity>) crit.list();
System.out.println("# of results = " + entities.size());
I am getting a NullPointerException on the crit.list() line that looks like
Exception in thread "main" java.lang.NullPointerException
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getProjectedTypes(CriteriaQueryTranslator.java:362)
at org.hibernate.criterion.SubqueryExpression.createAndSetInnerQuery(SubqueryExpression.java:153)
at org.hibernate.criterion.SubqueryExpression.toSqlString(SubqueryExpression.java:69)
at org.hibernate.loader.criteria.CriteriaQueryTranslator.getWhereCondition(CriteriaQueryTranslator.java:380)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:114)
at org.hibernate.loader.criteria.CriteriaJoinWalker.<init>(CriteriaJoinWalker.java:83)
at org.hibernate.loader.criteria.CriteriaLoader.<init>(CriteriaLoader.java:92)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1687)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)
Now, I think its pretty safe to say I'm using the Criteria Api/Detached Query Api incorrectly, but I'm not sure what the 'correct' way to do it is since the Hibernate Docs only briefly cover criteria api subqueries.
I realize this is a pretty long question, but I figure its appear to put it all the relevant aspects of the question (query I'm attempting to represent via Criteria API, tables, entities).
Give this a shot:
DetachedCriteria d = DetachedCriteria.forClass(QueryDetailEntity.class, "qd");
d.setProjection(Projections.projectionList().add(Projections.property("qd.query")));
d.add(Restrictions.or(Restrictions.like("qd.value1", "PROMPT%"), Restrictions.like("qd.value2", "PROMPT%")));
criteria = session.createCriteria(QueryEntity.class, "q");
criteria.add(Subqueries.propertyNotIn("q.primaryId", d));
criteria.list();
The use of the following are property names, not column names:
qd.query
qd.value1
qd.value2
q.primaryId
As a side note, if this is not a dynamically generated query, have you given thought to using HQL instead?
i have declared an entity the following way:
public class MyEntity {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
#Persistent
private String text;
//getters and setters
}
Now I want to retrieve the objects using the id. I tried to manage it from the Google Appengine Data Viewer with "SELECT * FROM MyEntity Where id = 382005" or via a query in a servlet. I get no results returned. But i know for sure that the object with the id exists (i made a jsp which queries all objects in the db and displays them in the db).
So what is wrong in my query? Am I querying the wrong field? The Google Appengine Data Viewer names the field "ID/name" and it has the value "id=382005". Do I have to query with this names? I've tried but it didn't work out :(
You can use below since you are querying using the primary key:
MyEntity yourEntity = entityManager.find(MyEntity.class, yourId);
Note, this should work as well, but it's easier to use find() if you are searching based on the primary key:
Query query = entityManager.createQuery(
"SELECT m FROM MyEntity m WHERE id = :id");
query.setParameter("id", yourId);
MyEntity yourEntity = (MyEntity) query.getSingleResult();