Hibernate `assigned` strategy returns 0 with sequence and trigger - oracle

I've Table uses Trigger and sequence to set its PK column.
The Hibernate mapping strategy for its Pk is assigned..
This yields in session.save(obj) returns object with id=0
How to make it returns the correct assigned PK value.
session.getIdentifier() doesn't work!

assigned means: Nobody generates the ID, the ID is set explicitely in the entity before persisting it.
What you want to do is impossible. Hibernate would have to insert an entity without knowing its ID, then the database would generate the ID, and Hibernate would have to reload the entity from the database to know its ID. But how would it reload the entity without knowing its ID?
The native generator does the same thing, and it works because the database provides a getLastGeneratedId() method which allows getting the IOD that the database has generated. But you can't do that with Oracle and a trigger.
Remove the trigger from the database, use the sequence generator, and everything will be fine.

Related

Spring Boot entity with Pk using Oracle DB Sequence in a trigger

I need a help on persisting an entity in a Oracle DB table that uses trigger and sequence for PK.
By now, I tried these from other stackoverflow questions:
#Id
#GeneratedValue(generator="increment")
#GenericGenerator(name="increment", strategy="increment")
This approach works. It finds the max value of PK and increment the value in 1. But, this doesn't update the Db sequence causing "constraint violation" error at some point.
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="id_sequence")
#SequenceGenerator(name="id_sequence", sequenceName="MY_DB_SEQ")
This approach doesn't work for me either. Sadly, the Db sequence is not accessible and causing error when it is trying to run internally "select MY_DB_SEQ.nextval from dual". Why is not accesible? Go and ask DB admin :)
It looks like the only option I have is passing null in the Entity PK attribute so that the DB trigger, which uses the a DB sequence to get the nextval when the ID is null, assigns the PK value in DB record.
How can I pass a null value for #Id? Of course this is throwing error because is needed. Is there any other annotation I can use for this?
If this is not possible, what other ways I should try?
Thanks for your help.
UPDATE
I couldn't find another way for this, having a DB Seq that is not accessible for user, and when it requires to pass NULL to PK in order to have DB use the trigger which check NULL value in PK to run seq nexval.
After granting access to DB Seq, this approach of course works.
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="id_sequence")
#SequenceGenerator(name="id_sequence", sequenceName="MY_DB_SEQ")
Did you create the sequence in the database as below?
CREATE SEQUENCE id_seq INCREMENT BY 1 START WITH 0 MINVALUE 0 MAXVALUE 100 NOCYCLE NOCACHE;
if not create first.
or else add the below properties in the application but it's not good practice.
spring.jpa.hibernate.ddl-auto = update
As of now, I couldn't find any solution to pass NULL to PK in Entity.
In DB, the DB Sequences were granted access. Spring Boot can now read the sequence and gran the next value.

Operations on certain tables won't finish

We have a table TRANSMISSIONS(ID, NAME) which behaves funny in the following ways:
The statement to add a foreign key in another table referencing TRANSMISSIONS.ID won't finish
The statement to add a column to TRANSMISSIONS won't finish
The statement to disable/drop a unique constraint won't finish
The statement to disable/drop a trigger won't finish
TRANSMISSION's primary key is ID, there is also a unique constraint on NAME - therefore there are indexes on ID and NAME. We also have a trigger which creates values for column ID using a sequence, so that INSERT statements do not need to provide a value for ID.
Besides TRANSMISSIONS, there are two more tables behaving like this. For other tables, the above-mentioned statements work fine.
The database is used in an application with Hibernate and due to an incorrect JPA configuration we produced high values for ID during a time. Note that we use the trigger only for "manual" INSERT statements and that Hibernate produces ID values itself, also using the sequence.
The first thought was that the problems were due to the high IDs but we have the problems also with tables that never had such high IDs.
Anyways we suspected that the indexes might be fragmented somehow and called ALTER INDEX TRANSMISSIONS_PK SHRINK SPACE COMPACT, which ran through but showed no effect.
Also, we wanted to call ALTER TABLE TRANSMISSIONS SHRINK SPACE COMPACT which didn't work because we needed to call first ALTER TABLE TRANSMISSIONS ENABLE ROW MOVEMENT which never finished.
We have another instance of the database which does not behave in such a funny way. So we think it might be that in the course of running the application the database got somehow into an inconsistent state.
Does someone have any suggestions what might have gone out of control/into an inconsitent state?
More hints:
There are no locks present on any objects in the database (according to information in v$lock and v$locked_object)
We tried all these statements in SQL Developer and also using SQLPlus (command-line tool).

Disabled Trigger still working

We are using an Oracle 10 DB which uses several triggers to retrieve values from sequences which are used as primary keys. One of these triggers is disabled but it seems that it is still firing because the records in the table are inserted successfully with a valid primary key.
How is that possible? Why is this "before insert" trigger still working although it is disabled?
I think the trigger calls the sequence to get a PK value only if the insert statement does not provide one (PK is null). The application that does the insert probably calls the sequence and provides a value for the PK.
Maybe you can test it yourself by inserting a record into the table with PK value is null. If you get an error the trigger is disabled.

Maximum number of columns in a LINQ to SQL object?

I have 62 columns in a table under SQL 2005 and LINQ to SQL doesn't handle the updates though the reading would work just fine, I tried re-adding the table to the model, created a new data model but nothing worked, I'm guessing I've hit the maximum number of columns limit on an object, can anyone explain that ?
I suspect there is some issue with an identity or timestamp column (something autogenerated on the SQL server). Make sure that any column that is autogenerated is marked that way in the model. You might also want to look at how it is handling concurrency. If you have triggers that update any values on the row after it is updated (changing values) and it is checking all columns on updates, this would cause the update to fail. Typically I create my tables with a timestamp column -- LINQ2SQL picks this up when I generate the model and uses it alone for concurrency.
Solved, either one of the following two
-I'm using a UniqueIdentifier column that was not set as Primary key
-Set Unique ID primary key, checked the properties of the same column in Server Explorer and it was still not showing as Primary key, refreshed the connection,dropped the same table on the model and voila.
So I assume I made a change to my model some time before, deleted the table from the model and added the same from the Server explorer without refreshing the connection and it never used to work.
Question is, does VS Server Explorer maintain it's own table schema and requires connection refresh everytime a change is made in the database ?
There is no limit to the number of columns LINQ to SQL will handle.
Have you got other tables updating successfully?
What else is different about how you are accessing the table content?

Linq insert with no primary key

I need to insert records into a table that has no primary key using LINQ to SQL. The table is poorly designed; I have NO control over the table structure. The table is comprised of a few varchar fields, a text field, and a timestamp. It is used as an audit trail for other entities.
What is the best way to accomplish the inserts? Could I extend the Linq partial class for this table and add a "fake" key? I'm open to any hack, however kludgey.
LINQ to SQL isn't meant for this task, so don't use it. Just warp the insert into a stored procedure and add the procedure to your data model. If you can't do that, write a normal function with a bit of in-line SQL.
Open your DBML file in the designer, and give the mapping a key, whether your database has one or not. This will solve your problem. Just beware, however, that you can't count on the column being used for identity or anything else if there isn't a genuine key in the database.
I was able to work around this using a composite key.
I had a similar problem with a table containing only two columns: username, role.
This table obviously does not require an identity column. So, I created a composite key with username and role. This enabled me to use LINQ for adding and deleting entries.
You might use the DataContext.ExecuteCommand method to run your own custom insert statement.
Or, you might add a primary key to a column, this will allow the objects to be tracked for inserts/updates/deletes by the datacontext. This will work even if the column isn't really an enforced primary key in the database (how would linq know?). If you're only doing inserts and never re-use a primary key value in the same datacontext, you'll be fine.

Resources