how to set H2 primary key id to auto_increment? - sql

i am using sql, H2, and i am trying to make so that the ID of Usertable is auto_incremented. i tried all sql commands in H2 sql interface, didnot work out.
alter table user alter column int not null auto_increment;
this common one is even not working. is there any annotation of JPA for auto_incement may be?
thanks a lot

You should use the JPA annotations #Id and #GeneratedValue for your ID.
Your SQL looks valid. Can you post the error message?

I had the same problem. I am not sure if the root-cause is the same. But there turned to be a perfectly logical explanation. So here is what I discovered.
First of all, there are at least 2 distinct ways to create auto-incremented keys.
1st way: (xml)
If you work with an xml-based configuration that holds your class info.
Then you can put something as follows in your classname.hbm.xml file.
<id name="id">
<generator class="sequence"><param name="sequence">my_id_seq</param</generator>
</id>
To import this file you will have something like the following in your hibernate.cfg.xml file: (or possibly with a resource attribute)
<!-- Mapping files -->
<mapping file="classname.hbm.xml"/>
But the important thing here is that it is now actually JAVA that will increment the keys. If you would have checked the sql that was used to generate the table, you would have noticed that it did not hold an auto-incremented field definition for the id column.
2nd way: (annotations)
A totally different way of doing things is to put everything in annotations, like you showed in your question.
#GeneratedValue(strategy=GenerationType.IDENTITY)
in your hibernate.cfg.xml file you will have something like:
<!-- Mapping files -->
<mapping class="package.subpackage.MyClassName"/>
The GenerationType.IDENTITY is indeed the default value, so you do not have to supply it per se. But anyway this time the table will be generated differently. Namely as follows:
CREATE CACHED TABLE PUBLIC.MYTABLENAME(
ID INTEGER DEFAULT
(NEXT VALUE FOR PUBLIC.SYSTEM_SEQUENCE_9DE2A0D5_28F5_488F_9E4C_2878B3CDA72F)
NOT NULL NULL_TO_DEFAULT SEQUENCE
PUBLIC.SYSTEM_SEQUENCE_9DE2A0D5_28F5_488F_9E4C_2878B3CDA72F,
...
)
Aha! That's interesting. This time the sequence generation will not be performed by JAVA it will be performed by the database itself.
What went wrong:
We are all experimenting and trying things out of course. If you first decided to do it with the xml-files and afterwards you decided to do it with annotations after all. Then of course that means you will have to regenerate your tables as well. If you forget to do so, then you will get errors like doniyor did.
How to fix it:
just add the following line to your hibernate.cfg.xml and reboot your application.
<!-- Drop and re-create the database schema on startup -->
<property name="hibernate.hbm2ddl.auto">create</property>
The table has been destroyed and regenerated.

Related

How to migrate primary key generation from "increment" to "hi-lo"?

I'm working with a moderate sized SQL Server 2008 database (around 120 tables, backups are around 4GB compressed) where all the table primary keys are declared as simple int columns.
At present, primary key values are generated by NHibernate with the increment identity generator, which has worked well thus far, but precludes moving to a multiprocessing environment.
Load on the system is growing, so I'm evaluating the work required to allow the use of multiple servers accessing a common database backend.
Transitioning to the hi-lo generator seems to be the best way forward, but I can't find a lot of detail about how such a migration would work.
Will NHibernate automatically create rows in the hi-lo table for me, or do I need to script these manually?
If NHibernate does insert rows automatically, does it properly take account of existing key values?
If NHibernate does take care of thing automatically, that's great. If not, are there any tools to help?
Update
NHibernate's increment identifier generator works entirely in-memory. It's seeded by selecting the maximum value of used identifiers from the table, but from that point on allocates new values by a simple increment, without reference back to the underlying database table. If any other process adds rows to the table, you end up with primary key collisions. You can run multiple threads within the one process just fine, but you can't run multiple processes.
For comparison, the NHibernate identity generator works by configuring the database tables with identity columns, putting control over primary key generation in the hands of the database. This works well, but compromises the unit of work pattern.
The hi-lo algorithm sits inbetween these - generation of primary keys is coordinated through the database, allowing for multiprocessing, but actual allocation can occur entirely in memory, avoiding problems with the unit of work pattern.
To use the hi-lo generator you will need to create the lookup table that will store the next value for the "Hi" part of the generated keys. You have the choice of creating a separate column for each entity table, a single column that will be used by all entities, or a combination of the two options.
If a shared column is used then each generated key will only be used by a single entity. This may be preferable if there are many entity tables, but it reduces the total number of Ids that can be generated.
For example, our project uses a HiLoLookup table with three columns:
NextEntityId BIGINT NOT NULL,
NextAuthenticationLogId BIGINT NOT NULL,
NextConfigurationLogId BIGINT NOT NULL
The log tables have a high-volume of inserts, so have been given a separate pool of Hi values. The primary key columns of our regular entity tables use the 64-bit BIGINT data type so there's is no danger of overflowing even if there are large gaps in the sequence of ids. A shared pool of ids is used to reduce administration overhead.
The hi-lo generator doesn't have built-in support for initializing itself with starting values that don't conflict with existing keys - so this will need to be performed manually.
The value to use as the starting "hi" value depends on several considerations:
The maximum existing id value - the generated ids will need to be higher than this to avoid duplicates
How many ids should be generated before requesting a new "hi" value from the db (max_lo) - a bigger value improves concurrency but increases the potential for ids to be wasted, especially if the service is restarted frequently
The max_lo value that is provided in your entity mappings is critical when determining what your starting 'hi' values should be. For example, consider a table with a maximum existing id value of 12345. The number of ids that should be generated before going back to the database is 1000. In this case, the starting hi value should be (12345 / 1000) + 1 = 13, the first generated id will be 13000. Due to a quirk in the HiLoGenerator implementation, the max_lo value provided in the entity configuration needs to be 999, not 1000.
If using .hbm mappings:
<generator class="hilo">
<param name="table">dbo.HiLoLookup</param>
<param name="column">NextEntityId</param>
<param name="max_lo">999</param>
</generator>
Apart from the traditional HiLo you may also want to look into the new enhanced id generators. These can use a table (or sequence if the database support that) similar in spirit to the way HiLo works, but with builting support for separate number series for different entities (if you want). With the enhanced id generators you also have the option of using either the HiLo algoritm, or a pooled algorithm. The benefit of "pooled" is that the id generator table shows the actual value, not just a part of it.
These are new in NHibernate 3.3. The reference documentation doesn't mention them yet, but the Hibernate documentation do. They work the same in NHibernate.
I prefer using HILO as it does not break UOW and allows me to send multiple insert statements to the server.
Now for your questions:-
Will NHibernate automatically create rows in the hi-lo table for me, or do I need to script these manually?
You will need to create your hilo table, hilo comes in two flavours, a single number across all your tables or a number for any of your tables. I prefer the latter.
If NHibernate does insert rows automatically, does it properly take account of existing key values?
You will need to set the maxhi/maxlo manually, the lo is in the mappings and the hi is in the table, so you will need to change your XML mappings to :-
<id name="Id" column="Id" unsaved-value="0">
<generator class="hilo">
<param name="column">NextHi</param>
<param name="where">TableName='CmsLogin'</param>
<param name="max_lo">100</param>
</generator>
</id>
The following SQL can then be generated (by hand):-
CREATE TABLE hibernate_unique_key (
TableName varchar(25) NOT NULL,
NextHi bigint NOT NULL
)
then add a row into the database for every table you wish to use the hilo for: e.g.
CmsLogin,123
Address, 456
Note the 123 here would start my next insert id to (123 x 100) = 12300 therefore as long as 12300 is bigger than my current identity then all should be good!
and if you dont like the default table name hibernate_unique_key then you can throw this into the mix
<param name="table">HiloValues</param>

NHibernate HiLo generation and SQL 2005/8 Schemas

I have an issue on my hands that I've spent several days searching for an answer to no avail...
We're using HiLo Id generation, and everything seems to be working fine, as long as the entity table is in the same schema as the hibernate_unique_key table.
The table structure is pretty simple. I have my hi value table in the db as dbo.hibernate_unique_key. Several entity table are also in the dbo schema, and they work without issue. Then we have tables under the "Contact" schema (such as Contact.Person and Contact.Address).
In the Person Mapping file:
<class name="Person" table="Person" schema="Contact">
<id name="Id" unsaved-value="0">
<generator class="hilo">
<param name="max_lo">100</param>
</generator>
</id>
...
When I try to insert a Person entity, I get an error of "Invalid object name 'Contact.hibernate_unique_key'. That error is certainly clear enough. So I add:
<param name="schema">dbo</param>
to my mapping file/generator element. Now, when the SessionFactory is built, I get a "An item with the same key has already been added." error. So now I'm a bit stuck. I can't leave the HiLo generator without a schema, because it picks up the schema from the Class, and I can't specify the schema because it's already been added (presumably because it's my "default_schema" as identified in my XML cfg file).
Am I completely hosed here? Must I either
A) Keep all my tables in the dbo schema or
B) Create a separate HiLo Key table for each unique schema in the DB?
Neither of those scenarios is particularly palatable for my application, so I'm hoping that I can "fix" my mapping files to address this issue.
Only one such table per database should exist. Such data table should imply the following columns (let's call this table Parameters):
HiLoId
TableName
ParamName
HiLoAssigned
In addition to be used as a HiLo assignment data table, this could be used as a parameter table. As such, the ParamName field is required. This could contain data such as:
HiLoId | TableName | ParamName | HiLoAssigned
---------------------------------------------
1 | Parameters| HiLoId | 3
2 | Customers | CustomerId| 9425
3 | Invoices | InvoiceId | 134978
And when you need some other parameters, such as a parameter for a job that would prune your tables for history, then an age parameter for record could be inserted into it.
Well, I'm a little further in the subject than what you actually asked. Just sharing some additional thoughts in database design/architecture.
Take an eye out this question, and see my answer there. This might answer your question as well, and bring further information to this answer.
Have you tried specifying the schema with the table name on all generators (including the ones already in the dbo schema? I.e.
<param name="table">dbo.hibernate_unique_key</param>
The hilo generator looks for a '.' in the table name, and qualifies it (with schema) only if one isn't there.
I don't think there's anything wrong with solution B. Behavior will be pretty much the same.

NHibernate: inserting additional calculated column

What would be your approach with NHibernate to do the following:
When Comment is inserted into DB, and its property Text is inserted into column Text (due to a mapping), insert into column TextHash a hash of this property value.
It seems trivial if I map TextHash, but how should I do this without mapping it?
I do not need it in the domain model, its a DB-level optimization (I would use computed HashBytes if not for the length limit).
There are some similar questions, such as this one:
Unmapped Columns in NHibernate?
However, IInterceptor seems like an overkill for a change in a single entity insert. And EventListeners are less than perfectly documented and also somewhat too complex for a single column.
So I have decided on the solution that I see both as most reusable and most local:
<property name="Text" type="StringWithMD5HashUserType">
<column name="Text" length="20000" not-null="true" />
<column name="TextHash" length="32" not-null="true" />
</property>
Where StringWithMD5HashUserType is ICompositeUserType that reads Text from first column, but writes both Text and its Hash (I do not add the code of StringWithMD5HashUserType because it is way too long, but essentially very simple).
Well, if you don't want to use the property, declare it private and calculate it when you set the text property. It's not exactly "without mapping it", but you won't see it when you're using the class (disclaimer: advice based on Hibernate, as opposed to NHibernate).
Other than that, you could always write a trigger, although I'd personally much rather add a private field and be done with it.
Here's a suggestion:
As far as I know you can't access a column in your DB using NHibernate if it there no mapping defined for it.
To prevent other parts of your application to see this field of your class you can define its access as field in your mapping so that it can be private an no one knows that it exists but NHibernate:
In your class:
private string _textHash
In your mapping:
<property name='_textHash' column='TextHash' access='field' />

Nhibernate many-to-one problem

I've got a problem with mapping many-to-one in the following code:
...
<property name ="CustomerID"/>
<!-- Many-to-one mapping: Customer -->
<many-to-one name="Customer"
class="Customer"
column="CustomerID"
insert="false" update="false"/>
<property name="Date" />
...
You may notice that i have mapped two CustomerID to Customer table. The reason i do this because when i want to create an Order, i just only assign value to CustomerID and other require fields then do save. many-to-one mapping, I just want to get detail of each customerID.
But, the problem is that: after i update customerID of an Order and Executre SaveOrUpdate with Session.Flush() also (I'm using HibernateTemplate), i still got the old figure when accessing to Order.Customer.
i.e:
Order = getOderByID(1);
Order.CustomerID=3 // Suppose value of CustomerId is 1. Now I changed to 3
SaveOrUpdate(Order);
Print(Order.Customer.CustomerID)// it returns 1 which is wrong. It should be 3
Pls help...
Thanks,
I would suggest you to look at this problem from an NHibernate point of view. And not from a relational database view. Let me start with what i feel you should be doing.
var customer = session.Load<Customer>(3);
var order = session.Load<Order>(1);
order.Customer = customer;
//assuming this is a one directional mapping. otherwise you might
//have to do some more steps to disassociate the order from the old
//customers collection and add it to the new customers collection
session.SaveOrUpdate(order);
Now, order.Customer.CustomerID will return 3.
As Serkan suggested, its better and more feasible to work with objects instead of primary keys.
Also, there really shouldnt be any performance impact here. Nhibernate is able to proxy a lot of the associations as long as the classes have virtual public methods. Because of this, as long as you only query for the Id of the customer, it will not generate a separate sql query. The Id is already there with the proxy object.
With regards to the original question, I have a hunch. NHibernate dynamically generates the sql query for the update and the inserts. This case here is of an update. You have explicitly set the CustomerID property to 3. But the Customer property of the order object still points to the customer object with Id 1. So, when NHibernate generates the sql query, it trys to set the value first to 1, as you asked it to. Then it also sees that the Customer is still pointing to the old object, so reset the CustomerId property to 1. I think NHibernate is getting confused with the dual mappings.
There are two things that you can do. First enable the "show_sql" property in the NHibernate configuration.
<nhibernate>
...
<add key="hibernate.show_sql" value="true" />
</nhibernate>
Check what is the sql being generated when you save the order. That will explain things better.
Second, after saving the order, do session.Refresh(order); You can read about the Refresh() method here. Its towards the end of the section 9.2. It will reload the order object with fresh values from the database. Calling order.CustomerID should show what value you have stored in the database.
I think you'd feel much happier in the long run if you try to forget about Id's of entities once you are done with the OR mapping. You are in a different level which you should think in objects only. If I were you I would remove CustomerId property all together.
If you have performance issues try to solve them in NHibernate way, caching etc.
Two things to try
Flushing the session via Session.Dispose if it's NH 2.x otherwise use Flush()
Make your IDs client assigned.
NHibernate will create the IDs for you and try to manage them unless you specifically tell it not to.

Should NHibernate assign id to entities or should it be handled by application?

I'm writing an application and started to test my domain model entities. If I Create an instance of entity Company like this var company = new Company("my company"); I should get a valid entity, meaning the company should at this moment have an Id correct?
So the problem is that at the moment I have the Id generation made in the DB defined in an hbm file like this:
<id name="ObjectIdentity" column="CompanyId" type="System.Guid" unsaved-value="00000000-0000-0000-0000-000000000000">
<generator class="guid.comb"/>
</id>
This causes a problem when writing unittests as I do not have en entity with an Id as it dosen't touch the db in the test, aka I have an invalid entity.
Now should I assign Id in the application and not let nhibernate be in charge of this or is this the wrong way to do it?
In most cases you should be letting NHibernate do its job which is to handle persistence. This is important since it allows you to easily change things (we went from identity to hilo mid-project).
I would question why you care that a newly created object has an id or not? From a business point of view a persistence ID is not relevant and shouldn't be checked with via unit tests. This as mentioned is the domain of integration tests. You should be careful in how you are using an objects persistence Id throughout the rest of your application. Remember this should NOT be treated as the objects business id/key.
You need to call Session.Save on the entity before a guid is generated. You can call Session.Save to generate the entity without actually saving it to the database. This article does a pretty decent job of explaining it
Neither NHibernate nor the Application should be handling identifiers. Leave it to the database since this is the only concrete store of your data, and it is the only part of your application that knows what IDs have already been assigned and what ones are available.
Make an identity primary key column on your database table:
CREATE TABLE dbo.sample (
id int primary key identity(1,1),
...
...
...)
map your entities like this:
<id name="ID" column="id">
<generator class="identity" />
</id>
The Primary key will be generated automatically by the database when you save a new entity for the first time. IDENTITY(1,1) means "give new rows an Identity start at '1' then each subsequent row gets incremented by 1": so 1,2,3,4,5,6,7
You need to save the entity to get an id if you're using db generated identity,
if you wish to create your own identities - it is fine.
do what suits you, just remember what you have chosen when you test.
I usually decide on each class which is more suitable for me - either DB generated or my own.
Nhibernate should generate Id's for you. Id property of the entity must be protected. The best way is to use hilo