Hibernate's saveOrUpdate ignores not-null column property - oracle

I have a mapping file that specifies a given column as not-null="true". This is a mistake since the table's column is set to NULL on the Oracle database. But we did not notice that until now, more than an year after creating the mapping file, because Hibernate have been "ignoring" this. Is that possible?
To make it clearer. On the database:
CREATE TABLE db.my_table
(...)
my_column NUMBER(10,0) NULL,
(...)
On the mapping file:
<column name="MY_COLUMN" precision="10" scale="0" not-null="true">
Then on the Java code:
getHibernateTemplate().saveOrUpdate(myEntity);
getHibernateTemplate().flush();
This code is WORKING on our environment. Has always been. But some clients have had issues of ot-null property references a null or transient value and when I debugged the code it didn't make any sense. This code should never been able to run, as far as I know.
Of course it's simple to solve the clients problems, I just have to correct the mapping file so it represents my entity properly. But the real issue here is why haven't Hibernate complained about it?
I've asked some other engineers here with more experience on Hibernate but none of them have ever seen this.
So, can anyone gimme a hint?
EDIT: Just want to stress that both our test environment and my client's are running the exact same code, and in both cases the myEntity object has the myColumn property set to NULL. So, what puzzles me is why it does not yield any exception here on our environment.

It is absolutely correct behaviour.
The not-null attribute has two meanings:
support schema exporting tools
check the Entity in runtime (i.e. do not check database column setting)
See: 5.1. Mapping declaration, extract:
The mapping document also contains some extra optional attributes and
elements that affect the database schemas exported by the schema
export tool (for example, the not-null attribute).
And 5.1.11. Property, extract:
not-null (optional): enables the DDL generation of a nullability
constraint for the columns.
So, if your clients run some code, which tries:
getHibernateTemplate().saveOrUpdate(myEntity);
while the myEntity is missing some property set as not-null="true" it is correct in throwing a runtime exception. While in your test environment you most likely always set the property to some not null value.
And there is an advantage even. The DB and App are loosely coupled. So if needed, you can make more constraints on App side, while not touching the DB (e.g. you are not allowed)

I had exactly the same problem:
In my hibernate mapping file I had set not-null="true" for a special column.
On my development machine I could persist null values without any exceptions. On the customers machine we always received a PropertyValueException / DataIntegrityViolationException.
This was a dangerous behavior. Manual and automatic tests would not fail.
Solution:
On my development machine I hat to set the property hibernate.check_nullability to true. Only then I also got the exceptions on my development system.
Conclusion
This strange behavior could come from adding the hibernate validator to the classpath. This turns check_nullability to false.
See this related question: How to Enable Spring Validation
Somehow this only applies on my dev-system and not in production. This might root from a different dependency loading within different application servers.

Related

Using both basic AND association mapping for one field with Doctrine?

I have a Variable object which may belong to a group
I'm mapping the Variable field containing the FK to the Group's id and his relation association in my domain object. (using XMl).
In other words, my domain object has both a (string) field with the id and a "relation" field with the object.
The intended goal here is to retrieve a ready Group object when querying, while simply setting an id when writing
So when I create/update a Variable, I set the ID (not the relation Object).
My issue is : the value is (always) properly saved when I UPDATE, but (always) lost on INSERT.
Here's the part of my mapping :
<field name="parentId" type="string" length="36" column="parent" nullable="true"/>
<many-to-one field="parent" target-entity="App\Domain\VariablesGroup\VariablesGroup" fetch="EAGER">
<join-column name="parent" referenced-column-name="id" nullable="true"/>
</many-to-one>
Docs didn't help me much here, since those 2 mappings are described separetely, and might not be designed to be mixed this way.
--
But I'd prefer to avoid querying the Group from DB and populate the Object field when not necessary.
Since I didn't find how Doctrine handles this under the hood, I guess it might not be something supported :(
Technical precisions about this mappings-interraction (or should I say conflict ?) would be welcomed.
Well, some more testing, using inconsistent data entries in my entity seem to clearly demonstrate that such usage isn't intended.
Whild my code wouldn't allow this, if I do save my entity with groupId = 1 and Group = (group Object with ID 2), I get an alternance of values for the saved value in the "parent" column of my database.
I guess this is due to Doctrine skipping the "useless" update, and proceeding to the one which effectively changes the data value.
Since both values are different, the skipped update alternantes.
If my assumptions are right, Doctrine would better pop an error in such a mapping case. (as it does if you map one column to 2 fields).
Maybe I'll file a suggestion/issue, if this seem relevant.

JPA add a condition to every single query automatically

Before anything, i must say this first: This table design is not my decision. We protest but to no avail, so please don't tell me, don't create a table like that.
We have a database with each table have a flag. This flag used to indicate which environment this row belong to, production or test data.
For server side, we have one variable which currently stored in ThreadLocal to indicate which environment this request belong to, same value as the flag in database.
Our requirement is that if my request belong to test environment then we must select only record belong to this environment. We would need to add a condition to every query we made to database, something like:
SELECT t FROM TABLE t WHERE t.flag = :environment
But we have to update every single query, update every object to set this flag before insert/update into database. This will require a lot of effort as our system already built long ago, not on progress. Also this will bring a lots of risk if someone forgot to add this to any new query.
So is there anyway to insert a condition to check this flag value for every query without have to manually edit the query string? Like an interceptor or something to put this condition in?
Which JPA provider?
With Hibernate, you could try using a #Filter.
Multitenancy could be another option, but probably an overkill in your scenario.
Finally, since you flagged the question with Oracle, perhaps the easiest approach would be to provide dedicated schemas (per environment) with views for every single table in your db, filtered by the flag column. Not sure if you're allowed to do that, though.
With some of the above, you would need a global entity listener to populate the flag field of your entities before they are persisted.

Using Oracle's GUID()-generated ID's in Grails/Hibernate

I trying to use Grails Scaffolding to throw a quick CRUD application together around some legacy database tables. It is an Oracle database, and the primary key value is intended to be populated by Oracle's GUID() function.
Based on this earlier StackOverflow question, I tried specifying "guid" as the Hibernate generator for this column in my Grails domain class:
...
static mapping = {
table name: "OWNER"
version false
columns {
id column: "OWNER_OID", generator: "guid"
name column: "NAME"
...
}
}
...
When I run my Grails app, viewing and even editing records works just fine. However, when I try to create a new record, things blow up with the Oracle error message "ORA-02289: sequence does not exist".
I enabled SQL logging for my datasource, and see Grails/Hibernate trying to execute the following during a save operation:
select hibernate_sequence.nextval from dual
This doesn't look right at all, and doesn't match the generated SQL from that earlier StackOverflow question linked above. Does anyone see something I am missing here, or otherwise know how to make Grails/Hibernate populate a primary key column with Oracle GUID values?
Whew... after another day of wrestling with this, I think I have my arms around the thing. This answer covers a bit more ground than the original question description, but that's because I found yet more problems after getting past the Hibernate generator issue.
Issue #1: Getting an Oracle GUID() value
As covered by Adam Hawkes' answer, the "guid" Hibernate generator is unmaintained and only works for older versions of the Oracle dialect.
However, if you use the Hibernate generator "assigned" (meaning that you want to set primary keys manually rather than have Hibernate auto-generate them), then you can insert values pulled from an Oracle SYS_GUID() call.
Even though Hibernate's newer Oracle dialects don't support "guid" seamlessly, they still understand the SQL necessary to generate these values. If you are inside of a Controller, you can fetch that SQL query with the following:
String guidSQL = grailsApplication.getMainContext().sessionFactory.getDialect().getSelectGUIDString()
If you are inside of a domain class instead, you can still do this... but you will need to first inject a reference to grailsApplication. You probably want to do this in a Controller, though... more on this below.
If you're curious, the actual String returned here (for Oracle) is:
select rawtohex(sys_guid()) from dual
You can execute this SQL and fetch the generated ID value like this:
String guid = grailsApplication.getMainContext().sessionFactory.currentSession.createSQLQuery(guidSQL).list().get(0)
Issue #2: Actually using this value in a Grails domain object
To actually use this GUID value in your Grails domain class, you need to use the Hibernate generator "assigned". As mentioned earlier, this declares that you want to set your own ID's manually, rather than letting Grails/GORM/Hibernate generate them automatically. Compare this modified code snippet to the one in my original question above:
...
static mapping = {
table name: "OWNER"
version false
id column: "OWNER_OID", generator: "assigned"
name column: "NAME"
...
}
...
In my domain class, I changed "guid" to "assigned". I also found that I needed to eliminate the "columns {}" grouping block, and move all my column information up a level (weird).
Now, in whichever Controller is creating these domain objects... generate a GUID as described above, and plug it into the object's "id" field. In a Controller generated automatically by Grails Scaffolding, the function will be "save()":
def save() {
def ownerInstance = new Owner(params)
String guidSQL = grailsApplication.getMainContext().sessionFactory.getDialect().getSelectGUIDString()
ownerInstance.id = grailsApplication.getMainContext().sessionFactory.currentSession.createSQLQuery(guidSQL).list().get(0)
if (!ownerInstance.save(flush: true, insert: true)) {
render(view: "create", model: [ownerInstance: ownerInstance])
return
}
flash.message = message(code: 'default.created.message', args: [message(code: 'owner.label', default: 'Owner'), ownerInstance.id])
redirect(action: "show", id: ownerInstance.id)
}
You might think to try putting this logic directly inside the domain object, in a "beforeInsert()" function. That would definitely be cleaner and more elegant, but there are some known bugs with Grails that prevent ID's from being set in "beforeInsert()" properly. Sadly, you'll have to keep this logic at the Controller level.
Issue #3: Make Grails/GORM/Hibernate store this properly
The plain truth is that Grails is primarily intended for virgin-new applications, and its support for legacy databases is pretty spotty (in fairness, though, it's a bit less spotty than other "dynamic" frameworks I've tried). Even if you use the "assigned" generator, Grails sometimes gets confused when it goes to persist the domain object.
One such problem is that a ".save()" call sometimes tries to do an UPDATE when it should be doing an INSERT. Notice that in the Controller snippet above, I have added "insert: true" as a parameter to the ".save()" call. This tells Grails/GORM/Hibernate explicitly to attempt an INSERT operation rather than an UPDATE one.
All of the stars and planets must be in alignment for this to work right. If your domain class "static mapping {}" block does not set the Hibernate generator to "assigned", and also set "version false", then Grails/GORM/Hibernate will still get confused and try to issue an UPDATE rather than an INSERT.
If you are using auto-generated Grails Scaffolding controllers, then it is safe to use "insert: true" in the Controller's "save()" function, because that function in only called when saving a new object for the first time. When a user edits an existing object, the Controller's "update()" function is used instead. However, if you are doing your own thing in your own custom code somewhere... it will be important to check on whether a domain object is already in the the database before you make a ".save()" call, and only pass the "insert: true" parameter if it really is a first-time insert.
Issue #4: Using natural keys with Grails/GORM/Hibernate
One final note, not having to do with Oracle GUID values, but related to these Grails issues in general. Let's say that in a legacy database (such as the one I've been dealing with), some of your tables use a natural key as their primary key. Say you have an OWNER_TYPE table, containing all the possible "types" of OWNER, and the NAME column is both the human-readable identifier as well as the primary key.
You'll have to do a couple of other things to make this work with Grails Scaffolding. For one thing, the auto-generated Views do not show the ID field on the screen when users are creating new objects. You will have to insert some HTML to the relevant View to add a field for the ID. If you give the field a name of "id", then the auto-generated Controller's "save()" function will receive this value as "params.id".
Secondly, you have to make sure that the auto-generated Controller's "save()" function properly inserts the ID value. When first generated, a "save()" starts off by instantiating a domain object from the CGI parameters passed by the View:
def ownerTypeInstance = new OwnerType.get( params )
However, this does not handle the ID field you added to your View. You will still need to set that manually. If on the View you gave the HTML field a name of "id", then it will be available in "save()" as "params.id":
...
ownerTypeInstance = new OwnerType()
ownerTypeInstance.id = params.id
// Proceed to the ".save()" step, making sure to pass "insert: true"
...
Piece of cake, huh? Perhaps "Issue #5" is figuring out why you put yourself through all this pain, rather than just writing your CRUD interface by hand with Spring Web MVC (or even vanilla JSP's) in the first place! :)
Support for using SYS_GUID() is dependent upon the Oracle dialect that you are using. Looking at the hibernate source on GitHub it appears that the dialect was only setup to use the Oracle-generated guid in Oracle9Dialect.java and Oracle8iDialect.java. Therefore, it won't work with the 9i or 10g dialects.
You should submit a patch to hibernate which will add the required function(s) to enable the same functionality as the other dialects.

Spring Roo Oracle and Underscore

I have a question concerning spring roo and databases.
I have a field called personName, in oracle to column is create as person_Name
I there a way to avoid the underscore. I suppose naming my column personname would fix this, but can I ask spring not to add the underscore ?
If you need a general solution (instead of "fixing" some single points (abaloghs answer)), you can specify a Naming Strategy for your JPA provider.
For an example see: JPA (Hibernate) and custom table prefixes
Roo by default refers to the JPA implementation to determine column names. You can override the defaults with the --column property:
entity --class Foo
field string --fieldName FooBar --column fooBar
Bonjour,
by the way, I do not think that it is possible to reverse engineer a database with underscores in table names :
the corresponding domain classes will be created and compiled since Java accept undersocres in class names
the tests will be performed without raising any issue
everything will be scaffold for the GUI
you will succesfully deploy it on tomcat and your application page will show up in your browser
You may fill the form to create a new instance of your object
But if you click on SAVE --> internal error
If you have a look at the tomcat log, you will fid the well known exception : javax.servlet.jsp.JspTagException: No message found under code ...
The reason is that your class name has been truncated in the message_xx.properties files.
Everything before the underscore is dropped and thus, no message is found in order to display that your record has been successfully saved.
It would be nice that the ROO shell raise an error when the jpa entity is created and not at runtime ...

Hibernate+Oracle+Clob: Content of attributes get switched

Has anyone heard of this error before:
I have a Java 5 application, that uses Hibernate 3.3.2 to access an Oracle Database 10g, the JDBC driver is the Oracle light driver version 10.2.0.4.0 (the most recent version, I think).
The database access happens during a transaction that is managed via the AOP-tools of spring.
There is one database table mapped to one Java entity, the mapping is done via annotations. There are two attributes in this entity that are CLOB in the database. They are annotated according to JPA with "Lob" and are Java Strings. Everthing works fine unless both attributes have values with more than 4000 characters: After the commit the values are switched on the database, that is attribute A contains the value of attribute B and vice versa.
This is not a joke!
The Eclipse debugger tells me that the Java entity has the correct values until the transaktion closes (I did not debug into the spring transaction handling).
This error does not occur if both Clobs are annotated with the Hibernate annotation 'Type(type = "clob")' (in which case they have to be of the type java.sql.Clob and not String, of course).
I'm not 100% sure but could you try to set the connection property SetBigStringTryClob to true (see How To Handle CLOBs Easily in JDBC?).
If you are using Spring, something like this:
<property name="hibernateProperties">
<props>
<prop key="hibernate.connection.SetBigStringTryClob">true</prop>
</props>
</property>
Meanwhile I found a solution to the problem: The SQL-dialect was wrong, someone set it to Oracle9 instead of the correct version, which is this:
name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"
Setting the correct SQL-dialect solves the problem :-)
I have exactly the same problem. Two CLOB on a table. On the insert only one is set and everything is fine. On the update I set the second one and after commit the values on table are swapped. Both contains more than 4000 characters. Debugged and the values on the bean are correct.
The sad thing is that i have already org.hibernate.dialect.Oracle10gDialect in my properties.
(Hibernate version 4.2.2.Final)
//UPDATE
for the moment as a workaround I have set the first column as updatable=false in the JPA annotation so that during the generation of the update query by hibernate there is only one CLOB column now. I can do this as that in this particular case I don't need to change the value after the insert, but it's not a general solution.
The only thing that worked for us was to use hql queries for the update. Each query updated a single CLOB (so we needed two separate queries):
Query query = em.createQuery("update SomeTable as someTable set value = :value where id = :id");
query.setParameter("value", value);
query.setParameter("id", id);
if (query.executeUpdate() != 1) {
throw new Exception("Value update had no effect");
}

Resources