Programmatically get a unique integer using HNibernate HiLo generator - nhibernate

I have a need to generate a unique integer which I use to identify an order to an external system. I'm using the NHibernate HiLo generator in the application, so can I access the generator programmatically to get it to return me a unique integer? I don't need to store this in any database key. I just want to use the NH functionality of generating unique integers.
I'd add a column to the HiLo table that I'd only use for this unique number sequence and not for any real database key. For example, say I added a column "Foo" to the hibernate_unique_key table.
Could I then do something to the effect:
int n = GetNextId("Foo");
Where I just pass the name of the column?

You should be able to just instantiate TableHiLoGenerator or SequenceHiLoGenerator, configure it and call Generate when you need a value.
When calling Generate(), you can pass session.GetSessionImplementation() for the first parameter and null for the second one.
Now, keep in mind that, if you aren't really storing these numbers, it might not be the best idea to use the DB to generate them. GUIDs are effectively unique, 128-bit numbers that can be generated more easily.

Related

Creating my Custom Unique Key

I have a table in my SQL Server. Currently I am using the identity column to uniquely identify each record but my changing needs required a unique key generated in a certain format (as specified by my client). I have tried to generate the unique key from my application by appending a unique integer (that is incremented on every insert) to the format specified my client is not satisfied with my current solution.
It would be great if I can be directed to a better technique to solve my problem rather then my current solution.
The format is like:
PRN-YEAR-MyAppGeneratedInt
Basically, keep the current identity column. That is the best way for you to identify and manage rows in the table.
If the client needs another unique key, then add it. Presumably, it will be a string (given that it has a "format"). You can possibly create the key as a generated column. Alternatively, you may need to use a trigger to calculate it.
In general, integers are better for identity columns, even if end users never see them. Here are some advantages:
They encode the ordering of row insertion in the database. You can, for instance, get the last inserted row.
They are more efficient for foreign key references (because numbers are fixed-length and generally shorter than strings).
They make it possible to directly address a row, when data needs to be fixed.
You can create a SEQUENCE to serve your purpose which were introduced in SQL Server 2012. A real detailed explanation about SEQUENCE can be found here.
Hope this helps :)
As per you specified in the comments the format let me also give you an example that how you can solve your problem using a sequence:
First create a sequence like:
CREATE SEQUENCE SeqName
AS int
START WITH 1
INCREMENT BY 1
CYCLE
CACHE
Next you can use this sequence to generate your desired unique key in you app program.
Get the next value for sequence "SELECT NEXT VALUE FOR SeqName;"
Create a string using the value like :String key= "PRN"+year+SeqValue;
Finally store this string as your unique key in your Insert statement.
You can write the application code as per you need :)
You could create a Computed Column and just append the identity
('Custom_'+CONVERT(varchar(10),iden))

Domain Driven Design Auto Incremented Entity Key

Just starting with Domain Driven Design and I've learned that you should keep your model in a valid state and when creating a new instance of a class it's recomended to put all required attributes as constructor parameters.
But, when working with auto incremented keys I just have this new ID when I call an Add method from my persistent layer. If I instanciate my objects without a key, I think they will be in a invalid state because they need some sort of unique identifier.
How should I implement my architecture in order to have my IDs before creating a new instance of my entity ?
Generated Random IDs
The pragmatic approach here is to use random IDs and generate them before instantiating an entity, e.g. in a factory. GUIDs are a common choice.
And before you ask: No, you won't run out of GUIDs :-)
Sequential IDs with ID reservation
If you must use a sequential ID for some reason, then you still have options:
Query a sequence on the DB to get the next ID. This depends on your DB product, Oracle for example has them).
Create a table with an auto-increment key that you use only as key reservation table. To get an ID, insert a row into that table - the generated key is now reserved for you, so you can use it as ID for the entity.
Note that both approaches for sequential IDs require a DB round-trip before you even start creating the entity. This is why the random IDs are usually simpler. So if you can, use random IDs.
DB-generated IDs
Another possibility is to just live with the fact that you don't have the ID at creation time, but only when the insert operation on the DB succeeds. In my experience, this makes entity creation awkward to use, so I avoid it. But for very simple cases, it may be a valid approach.
IN adition to theDmi's comments
1) You can in your factory method make sure your entity gets stored to the database. This might or might not be applicable to your domain but if you are sure that entity is going to be saved that might be a valid approach
2) You can separate the ID from the primary key from the database. I've worked with a case there something was only an order if the customer payed and at that point it would be identified by it's invoice id (a sequentual ID). that doesn't mean in the database i would need an column ID which was also the primary key of the object. You could have a primary key in the database (random guid) and till have an ID (int?) to be sequentual and null if it hasn't be filled yet.

How do I create a unique public id column which is not primary key

I read somewhere that it is bad to use your db table's primary key as a public identifier online. However, I would like my users to link to a specific object in the table.
How do I create a unique identifier column to my table that is non-related to the primary key (which is a auto-increment integer)?
My initial idea is to use a php script to generate random hexadecimal values of suitable length (there will be about 100 000-200 000 items i the table at most I think) and then inserting them. But then I don't know if it would be unique...
You can use a GUID (Globally Unique IDentifier) to uniquely identify a record. The number of possible GUIDs is so high the chances of duplicating one is next to nothing. Similarly, the chances of someone guessing the GUID is so low that generally they are safe to display to the user (for example www.yoursite.com?id=21EC20203AEA1069A2DD08002B30309D).
If you're using php you can use the com_create_guid method. *Note: This method is only supported in PHP5. For PHP4, look at uniqueid.

How does hibernate populate ids of auto generated fields?

Say i have an entity with an auto generated primary key. Now if i try to save the entity with values of all other fields which may not be unique.
The entity gets auto populated with the id of the row got inserted. How did it get hold of that primary key value?
EDIT:
If the primary key column is say identity column whose value is totally decided by the database. So it does an insert statement without that column value and the db decides the value to use does it communicate back its decision (I dont think so)
Hibernate use three method for extracting the DB auto generated field depending on what is support by the jdbc driver or the dialect you are using.
Hibernate extract generated field value to put it back in the pojo :
Using the method Statement.getGeneratedKeys (Statement javadocs)
or
Inserting and selecting the generated field value directly from the insert statement. (Dialect Javadocs)
or
Executing a select statement after the insert to retrieve the generated IDENTITY value
All this is done internally by hibernate.
Hope it`s the explication you are looking for.
This section of the Hibernate documentation describes the auto generation of ids. Usually the AUTO generation strategy is used for maximum portability and assuming that you use Annotations to provide your domain metadata you can configure it as follows:
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private long id;
Anyway the supplied link should provide all the detail you need on generated ids.
When you create an object with the, say, sequence-derived surrogate primary key, you pass it to the Hibernate session with that field set to the value that Hibernate interprets as "not assigned", by default 0. This field is not populated with the assigned value until the corresponding record is not inserted into the database table. You can trigger insertion by either explicitly calling flush() on the hibernate session or performing a database read in the same session. After that you can check the value of that field and it will be assigned rather than 0.

Hibernate and IDs

Is it possible in hibernate to have an entity where some IDs are assigned and some are generated?
For instance:
Some objects have an ID between 1-10000 that are generated outside of the database; while some entities come in with no ID and need an ID generated by the database.
You could use 'assigned' as the Id generation strategy, but you would have to give the entity its id before you saved it to the database. Alternately you could build your own implementation of org.hibernate.id.IdentifierGenerator to provide the Id in the manner you've suggested.
I have to agree w/ Cade Roux though, and doing so seems like it be much more difficult than using built in increment, uuid, or other form of id generation.
I would avoid this and simply have an auxiliary column for the information about the source of the object and a column for the external identifier (assuming the external identifier was an important value you wanted to keep track of).
It's generally a bad idea to use columns for mixed purposes - in this case to infer from the nature of a surrogate key the source of an object.
Use any generator you like, make sure it can start at an offset (when you use a sequence, you can initialize it accordingly).
For all other entities, call setId() before you insert them. Hibernate will only generate an id if the id property is 0. Note that you should first insert objects with ids into the db and then work with them. There is a lot of code in Hibernate which expects the object to be in the DB when id != 0.
Another solution is to use negative ids for entities which come with an id. This will also make sure that there are no collisions when you insert an new object.