I want to map one column, without using a column name.
I am using a count entity, and the want to use mulple different queries with the same entity :
#Entity
public class CountDTO extends Number {
#Id
// below causes an error in my test, hsql not same syntax
#Column(name = 'COUNT')
private Long count;
In my prod (oracle) database I can just do select count() as COUNT from ... however, the same syntax doesn't work using hypersql in-memory db ?
Is their an oracle/hsql compatible way to map a single column alias in HQL ?
Your issue is that COUNT is a reserved keyword for HSQL, but not for Oracle.
According to the HSQL documentation, it might still be possible to use COUNT as identifier, if you either
Mask it as described in the Hibernate documentation or in the JPA spec (cf. chapter 2.13 from the JPA 2 spec; you'll need to accept their license agreement). Note that the JPA spec speaks of double quotes whereas the Hibernate documentation mentions backticks (which will be converted to the appropriate character according to the database dialect in use).
From the hibernate documentation:
You can force Hibernate to quote an identifier in the generated SQL by
enclosing the table or column name in backticks in the mapping
document. Hibernate will use the correct quotation style for the SQL
Dialect. This is usually double quotes, but the SQL Server uses
brackets and MySQL uses backticks.
From the JPA 2 spec:
Using annotations, a name is specified as a delimited identifier by
enclosing the name within double quotes, whereby the inner quotes are
escaped, e.g., #Table(name="\"customer\"").
Configure HSQL to allow it by executing SET DATABASE SQL NAMES FALSE (however, this should already be the default setting and it will only allow "the use of most keywords", not all - edit: COUNT will still be disallowed as per documentation)
My recommendation would be to avoid using identifiers if possible as you never know what problems may arise elsewhere (e.g. one might think Hibernate would be able to mask keywords itself) and use something like COUNT1 instead as column name.
The above part of the JPA spec also explains why Hibernate does not mask the name itself:
By default, the names of database objects must be treated as
undelimited identifiers and passed to the database as such.
The JPA spec also mentions a <delimited-identifiers/> option "to specify that all database identifiers in use for a persistence unit be treated as
delimited identifiers", but this seems to be only usable with an XML mapping file.
Related
I have a situation where I'm using Hibernate (5.2.16) to map a table and one of the column values is constructed via a database function that takes the values of two other properties.
For some background, this is a SDE spacial table with a ST_GEOMETRY column. As far as I can tell, this isn't compatible with the two types of spacial APIs supported by Hibernate, but even if it was, I'm not doing any spacial manipulation, so I don't really need them, I just want to insert and update the geometry column.
I have absolutely no control over the structure of the table because it's dictated by another group using another tool (GIS).
Things I've tried:
Using a Hibernate UserType. The problem with this is that I only see a way to get and set the value with a PreparedStatement, without the ability to dictate actual SQL used.
basic-custom-type
Using a Hibernate ColumnTransformer. This gives me direct control over the SQL used, but I can't use the values of two other properties in the SQL.
mapping-column-read-and-write
#Column(name="LATITUDE")
private BigDecimal latitude;
#Column(name="LONGITUDE")
private BigDecimal longitude;
#ColumnTransformer(
read="sde.st_astext(shape)",
write="sde.st_transform(sde.st_point(LONGITUDE,LATITUDE, 4326), 3857)"
)
#Generated(value=GenerationTime.ALWAYS)
#Column(name="SHAPE")
private String shape;
I get:
org.hibernate.AnnotationException: #WriteExpression must contain exactly one value placeholder ('?') character: property [shape] and column [SHAPE]
I've looked at Generated columns, but those are for values generated by the database.
mapping-generated
I've looked at Formula columns, but those are for values calculated and usable in Java, but aren't inserted or updated. mapping-column-formula
#Formula(value="sde.st_astext(shape)")
private String shape;
It's useful for some things, but I can't insert or update this.
I'm hoping that I've missed something. At this point I'm considering non-Hibernate/JPA solutions. This would be relatively easy with raw SQL and JDBC, but the rest of the table would be annoying and not match the rest of my code. I'd also have to do my own dirty checking and stuff.
You can use the Hibernate database generated value. It allows you to call database functions to generate entity properties.
This is a database-specific answer, but given your GIS problem domain and the dominance of PostGIS it may be relevant (if you use PostgreSQL and your DBA is OK with an upgrade).
PosgreSQL 12 introduces generated columns which you could define using something similar to the following:
#Column(columnDefinition = "GEOMETRY GENERATED ALWAYS AS st_transform(st_point(LONGITUDE,LATITUDE, 4326), 3857)) STORED")
I am having #Where at #Table level.
I need to get rows with EffDate field less than current date.
#Entity
#Table(name="party")
#Where(clause="EffDate < " + currentdate())
public class Party implements Serializable {
.......
}
I understand #Where takes constant expression which needs to be provided on compile time. But I need to compare with current date from Java and not from Database.
Any Idea how can I do that.
You can use the SQL function/constant for the current timestamp (depending on the type of database it might be called e.g. current_timestamp) (note however, that since this will be plain SQL, it will use the timestamp from the database server, not the server where the Java application runs on:
#Where(clause="EffDate < current_timestamp")
Write a Hibernate filter and enable it by default for all Sessions in the application. Depending on which framework you use for transaction management, you can add an interceptor/hook that enables the filter when transactions are started.
#Where annotation will not work, since it accepts constant expressions. Instead, I use findOnByEffectiveDateLessThanEquals from JPARepository.
http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation
I want to map in JPA 2.1 (on Hibernate 5.0.2 with MySQL database if that's relevant) a single table to two classes. I know that's done with SINGLE_TABLE inheritance + #DiscriminatorColumn and #DiscriminatorValue.
However, I wanted to discriminate based on a boolean column (well, boolean field in the mapping, I'm not sure how the database handles that). DiscriminatorType only contains 3 values (String, Char, and Integer) none of which seem particularly correct for my requirement. I could, I suppose, change my discriminator column to a more standard type, but I really do only need a boolean distinction and do not care how does the database store that info.
While a good workaround for MySQL 5.5 (which I would imagine looks something like use Char and write "0" and "1" as values, due to how it stores values it'll cast correctly) would be appreciated, I feel like database agnostic solution is in order.
My JPA Entity contiens a non id field named counter, the value of this field is getted from Sql server sequence.
How can i represente this requirement in my JPA mapping of the entity ?
I note that i can't add/modify the dabatabase objects ( triger/ function / procedure ), the solution must be bassed on JPA
Thanks !
JPA does not define #GeneratedValue on non-ID fields. However some JPA implementations (e.g the one I use DataNucleus JPA) do allow it, hence if using one of those implementations then you could just annotate the field as SEQUENCE.
I have a simple jpa entity 'ApplicationForm' with a one to many list in it:
#OneToMany(cascade=CascadeType.REMOVE, mappedBy="textQuestion")
private List<Dictionary> questions;
The variable Dictionary contained in ApplicationForm is just another plain entity with just the text of the question.
The corresponding database table mapped by Dictionary is:
'locale' 'text' 'formId'
en my question 123
it mia domanda 123
I was wondering if it's possible with jpa or hibernate, to build a query for retrieving an ApplicationForm entity with a Dictionary for a specific locale, for example 'it' only.
That would be easy enough to do with standard sql, but I cannot translate in hql.
If not possible, could you suggest an alternative way ? I have tried to manually iterate the Dictionary questions list and remove the not required locale, but is not really elegant, and also I got a jpa/hibernate error.
I hope I made myself clear, and code supplied is enough.
thanks
I was wondering if it's possible with jpa or hibernate, to build a query for retrieving an ApplicationForm entity with a Dictionary for a specific locale, for example 'it' only.
Not with standard JPA. But Hibernate allows to apply arbitrary filters to a collection load during a given session. From the Hibernate Annotations Reference Guide:
2.4.8. Filters
Hibernate has the ability to apply
arbitrary filters on top of your data.
Those filters are applied at runtime
on a given session. First, you need to
define them.
#org.hibernate.annotations.FilterDef
or #FilterDefs define filter
definition(s) used by filter(s) using
the same name. A filter definition has
a name() and an array of
parameters(). A parameter will allow
you to adjust the behavior of the
filter at runtime. Each parameter is
defined by a #ParamDef which has a
name and a type. You can also define a
defaultCondition() parameter for a
given #FilterDef to set the default
condition to use when none are defined
in each individual #Filter. A
#FilterDef(s) can be defined at the
class or package level.
We now need to define the SQL filter
clause applied to either the entity
load or the collection load. #Filter
is used and placed either on the
entity or the collection element
#Entity
#FilterDef(name="minLength", parameters=#ParamDef( name="minLength", type="integer" ) )
#Filters( {
#Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),
#Filter(name="minLength", condition=":minLength <= length")
} )
public class Forest { ... }
When the collection use an association
table as a relational representation,
you might want to apply the filter
condition to the association table
itself or to the target entity table.
To apply the constraint on the target
entity, use the regular #Filter
annotation. However, if you wan to
target the association table, use the
#FilterJoinTable annotation.
#OneToMany
#JoinTable
//filter on the target entity table
#Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length")
//filter on the association table
#FilterJoinTable(name="security", condition=":userlevel >= requredLevel")
public Set<Forest> getForests() { ... }
See also
Chapter 17. Filtering data In the Hibernate Core Reference Documentation.
Hibernate3 Filters