NamedNativeQuery throws PSQLException: ERROR: relation "mytable" does not exist [duplicate] - java

I have many EntityManager, one per schema that I have (I use entity-mappings file to map EMs with schemas). It works.
When I use #NamedQuery it's working like a charm but when I use #NamedNativeQuery schema is not used. I have to qualify with it SELECT foo FROM schema.table.
Is it the right behaviour ?
I think it's not possible to parameter #NamedNativeQuery to dynamically pass schema (I believe only columns can be dynamics not tables or schemas or anything else) so how can I use #NamedNativeQuery with dynamic schema please ?

Prefix your table name with "{h-schema}", e.g.SELECT foo FROM {h-schema}table
(courtesy of getting hibernate default schema name programmatically from session factory?)

Excerpts from documentation :
NamedNativeQuery : Specifies a named native SQL query. Query names are scoped to the persistence unit.
NamedQuery : Specifies a static, named query in the Java Persistence query language. Query names are scoped to the persistence unit.
It isn't specified directly that NamedNativeQuery is static, but both are same scoped & can't be altered afterwards & it's the desired behaviour.
Named queries are mean to be accessed by multiple modules - application wide, identified by unique name, so they are static & constant. You can try building a query string dynamically & can create a native query from it, instead of named native query.

Related

Spring Boot: keywords supported for JPA

I wanted to perform the Spring JPA repository where wanted to apply the and operation among 2 columns where one column cloud have multiple values in it.
SQL query for the same:
select * from table_name where col1='col1_val' and col2 IN
('col2_val_a','col2_val_b','col2_val_c');
I know that for and operation I can extend the JpaRepository and create the method with like this for:
List<MyPoJoObject> findByCol1AndCol2(String col1_val,String col2_val);
and for IN operation we can use : findByCol2In(Collection<String> col2_val)
But i did not know how i can club both the mentioned JPA default method into one, as per my sql statement mentioned before.
You can use the following method named:
List<MyPoJoObject> findByCol1AndCol2In(String col1_val, Collection<String> col2_val);
On this link repository-query-keywords you can find repository query keywords that you can use and combine them as well.
You can certainly combined both into one method.
List<MyPoJoObject> findByCol1AndCol2In(String col1_val,String[] col2_val);
Try this. I am not sure if it will accept Collection<String>. I will try that and update the answer.
HTH.
If you want to perform this logic for more than two columns then your method name becomes verbose.
Instead of stuck with Spring naming why can't you write your own JPA query.
Example:
#Query("select pojo from MyPoJoObject as pojo where pojo.col1 = :col1_val and pojo.col2 in :col2_val")
List<MyPoJoObject> findByColumns(String col1_val, List<String> col2_val);

What name of generated database by liferay?

Where are tables that generated database by Liferay through service.xml?. I don't see it in my Postgres. There are so many tables, I tried to find it but it not found. Anyone can help me, thanks
Unless you explicitly specify the table name in the entities that you declare in service.xml, the table names are constructed with the namespace and entity name.
<service-builder package-path="com.liferay.docs.guestbook">
<namespace>GB</namespace>
<entity name="Guestbook" local-service="true" uuid="true">
...
would generate GB_Guestbook as table name.
From the very well documented DTD:
<namespace>
The namespace element must be a unique namespace for this component.
Table names will be prepended with this namespace. Generated JSON
JavaScript will be scoped to this namespace as well (i.e.,
Liferay.Service.Test.* if the namespace is Test).
<entity> Child of service-builder
An entity usually represents a business facade and a table in the
database. If an entity does not have any columns, then it only
represents a business facade. The Service Builder will always generate
an empty business facade POJO if it does not exist. Upon subsequent
generations, the Service Builder will check to see if the business
facade already exists. If it exists and has additional methods, then
the Service Builder will also update the SOAP wrappers.
If an entity does have columns, then the value object, the POJO class
that is mapped to the database, and other persistence utilities are
also generated based on the order and finder elements.
...
(and you'll find more hints, e.g. explicit table names, in that document)
Notes:
If you declare that the entities are stored in an external (non-Liferay) datasource, no tables will be created.
Also, some versions of Liferay automatically updated the database structure on deployment of a new plugin version (with updated persistence layers), while others don't do this automatically (it's a developer feature anyways, not good for large - production - amount of data)

Using #Entity Class When Table Doesn't Exist

I have several database tables that my Spring MVC/JPA application refers to using the #Entity and #Table Annotations. I've run into the issue where if my application switches between database connections, some tables that exist on database 1 may not exist in database 2 (as we are following the SDLC cycle and promoting table additions/changes after they get the "OK"), thus resulting in an SQL Exception when the application server starts.
Does spring offer a way to mark specific #Entity Classes as "Optional" or "Transactional" so there are no database Exceptions returned because of nonexistant tables?
In my opinion, there is no option to do that.
You can add automatic update of schema in Hibernate, but you mentioned that you are doing this manually.
Hibernate is validating the schema, when he establishes connection. You use #Entity, so he looks for that table and throws an error if there is no with the name specified.

Load Entity from View in JPA/Hibernate

I have an application which uses Spring and Hibernate. In my database there are some views that I need to load in some entities. So I'm trying to execute a native query and load the class withthe data retrieved from the view:
//In my DAO class (#Repository)
public List<MyClass> findMyEntities(){
Query query = em.createNativeQuery("SELECT * FROM V_myView", MyClass.class);
return query.getResultList();
}
and MyClass has the same fields as the column names of the view.
The problem is that Hibernate can't recognize MyClass because it's not an entity (it's not annotated with #Entity)
org.hibernate.MappingException: Unknown entity
If I put MyClass as an entity the system will put try to create/update a table for that entity, because I have configured it :
<property name="hibernate.hbm2ddl.auto" value="update"/>
So I come into these questions:
Can I disable "hibernate.hbm2ddl.auto" just for a single entity?
Is there any way to load the data from a view into a non-entity class?
If not, what would be the best way in my case for loading the data from a view into a class in hibernate?
Thanks
Placed on your class
#Entity
#Immutable
#Subselect(QUERY)
public MyClass {....... }
Hibernate execute the query to retrieve data, but not create the table or view. The downside of this is that it only serves to make readings.
You may use axtavt solution. You may also just execute your query, and transform the List<Object[]> it will return into a List<MyClass> explicitely. Or you may map your view as a read-only entity, which is probably the best solution, because it would allow for associations with other tables, querying through JPQL, Criteria, etc.
In my opinion, hibernate.hbm2ddl.auto should only be used for quick n' dirty prototypes. Use the hibernate tools to generate the SQL file allowing to create the schema, and modify it to remove the creation of the view. Anyway, if it's set to update, shouldn't it skip the table creation since it already exists (as a view)?
You can use AliasToBeanResultTransformer. Since it's a Hibernate-specific feature, you need to access the underlying Hibernate Session:
return em.unwrap(Session.class)
.createSQLQuery("...")
.setResultTransformer(new AliasToBeanResultTransformer(MyClass.class))
.list();

JPA - Setting entity class property from calculated column?

I'm just getting to grips with JPA in a simple Java web app running on Glassfish 3 (Persistence provider is EclipseLink). So far, I'm really liking it (bugs in netbeans/glassfish interaction aside) but there's a thing that I want to be able to do that I'm not sure how to do.
I've got an entity class (Article) that's mapped to a database table (article). I'm trying to do a query on the database that returns a calculated column, but I can't figure out how to set up a property of the Article class so that the property gets filled by the column value when I call the query.
If I do a regular "select id,title,body from article" query, I get a list of Article objects fine, with the id, title and body properties filled. This works fine.
However, if I do the below:
Query q = em.createNativeQuery("select id,title,shorttitle,datestamp,body,true as published, ts_headline(body,q,'ShortWord=0') as headline, type from articles,to_tsquery('english',?) as q where idxfti ## q order by ts_rank(idxfti,q) desc",Article.class);
(this is a fulltext search using tsearch2 on Postgres - it's a db-specific function, so I'm using a NativeQuery)
You can see I'm fetching a calculated column, called headline. How do I add a headline property to my Article class so that it gets populated by this query?
So far, I've tried setting it to be #Transient, but that just ends up with it being null all the time.
There are probably no good ways to do it, only manually:
Object[] r = (Object[]) em.createNativeQuery(
"select id,title,shorttitle,datestamp,body,true as published, ts_headline(body,q,'ShortWord=0') as headline, type from articles,to_tsquery('english',?) as q where idxfti ## q order by ts_rank(idxfti,q) desc","ArticleWithHeadline")
.setParameter(...).getSingleResult();
Article a = (Article) r[0];
a.setHeadline((String) r[1]);
-
#Entity
#SqlResultSetMapping(
name = "ArticleWithHeadline",
entities = #EntityResult(entityClass = Article.class),
columns = #ColumnResult(name = "HEADLINE"))
public class Article {
#Transient
private String headline;
...
}
AFAIK, JPA doesn't offer standardized support for calculated attributes. With Hibernate, one would use a Formula but EclipseLink doesn't have a direct equivalent. James Sutherland made some suggestions in Re: Virtual columns (#Formula of Hibernate) though:
There is no direct equivalent (please
log an enhancement), but depending on
what you want to do, there are ways to
accomplish the same thing.
EclipseLink defines a
TransformationMapping which can map a
computed value from multiple field
values, or access the database.
You can override the SQL for any CRUD
operation for a class using its
descriptor's DescriptorQueryManager.
You could define a VIEW on your
database that performs the function
and map your Entity to the view
instead of the table.
You can also perform minor
translations using Converters or
property get/set methods.
Also have a look at the enhancement request that has a solution using a DescriptorEventListener in the comments.
All this is non standard JPA of course.

Categories

Resources