I am using JPA 2 for an enterprise application, and my DBA's just hit me with a twist.
They want me to use the group's centralized object ID generator for all my tables. This means rather than using table values or a sequence table, I will need to call a web service to get a batch of ~50 ids.
Then, as I persist any new object, I would need to inject this id first, and save that to the table.
So how would I manipulate the #Id column of an entity to handle this.
Is it as simple as setting a key before I persist? I suspect that would throw some sort of unmanaged entity with ID set error.
Update:
The better method is to actually specify a Sequence strategy on Generated fields and specify a custom Sequence class.
JPA will then call this class's nextId() method every time it inserts a new object.
This method allows full graphs to be persisted without intervening on each entity manually.
Figured it out. Amazingly complex ;) - just remove the GeneratedValue annotation from the key field.
It is intended for Native Ids like SSN or email, but works regardless of source.
#Entity
public class Client{
#Id
#Column(name="CLNT_ID")
private long key;
#Column(name="CLNT_NUM")
private String clientNumber;
...
}
Related
I have set up my own mechanism for assigning identities to my domain objects, and so when persisting them, there really isn't much value for me to keep track of what MongoDB assigns to them. However, I name the identity fields for my domain classes id because, well, it's concise and understandable. The problem is that, according to the documentation, Spring will automatically map this field to MongoDB's assigned ObjectID. How do I prevent this from happening without having to rename my id field, or defining a custom identity field annotated with #Id just for the sake of working around this?
Use #MongoId instead of #Id
#MongoId(targetType = FieldType.STRING)
protected String id;
It will store String even if the "shape" is an ObjectId
Well, you can't do that with Spring data I am afraid. Mongodb (and in turn, Spring data) needs a field to uniquely identify each document. If you have an id field already, and if it's unique for each and every object then yes, you can annotate it with #Id and mongo will take care of the rest.
If not, you will have to create a new field and map it to _id.
I'm working on a desktop application in Java6 using H2 as the db and Hibernate 3.6.
Because of a construct with a third-party library involving JNI and some interesting decisions made a priori, I am unable to pass around long identifiers in their index code, and can only pass int. These indexes are generated quickly and repeatedly(not my choice), and get handed around via callbacks. However, I can split my expected dataset along the lines of a string value, and keep my id size at int without blowing out my id's. To this end, I'm keeping a long value as pk on the core object, and then using that as a one-to-one into another table, where it maps the int id back to the core entity, which when combined with the string, is unique.
So I've considered embedded compound keys and such in hibernate, but what I REALLY want is to just have this "extra" id that is unique within the context of the extra string key, but not necessarily universally unique.
So something like(not adding extraneous code/annotations):
#Entity
public class Foo{
...
#Id
public Long getId(){...}
...
#OneToOne
#PrimaryKeyJoinColumn
public ExtraKey getExtra(){...}
}
#Entity
public class ExtraKey{
...
#Id
public Long getFooId(){...}
...
public Integer getExtraId(){...}
...
public String getMagicString(){...}
}
In that case, I could really even remove the magicString, and just have the fooId -> extraId mapping in the table, and then have the extraId + magicString be in another where magicString is unique. However, I want hibernate to allow the creation of new magicString's at whim(app requirement), ideally one per row in a table, and then have hibernate just update the extraId associated to that magicString via incrementation/other strategy.
Perusing all of the hibernate manuals and trying a few tests on my own in a separate environment has not quite yielded what I want(dynamically created named and sequential id's basically), so I was hoping for SO's input. It's entirely possible I'll have to hand-code all of it myself in the db with sequences or splitting a long and doing logic on the upper and lower, but I'd really rather not, as I might have to maintain this code someday(really likely).
Edit/Addendum
As a sneaky way of getting around this, I'm just adding the extraId to the Foo object(ditching the extraKey class), and generating it from another object singleton, that at load time, does a group by select over the backing Foo table, returning magicKey, and the max(extraId). When I create a new Foo, I ask that object(multithread safe) to hand me the next extraId for the given magicKey and push that into Foo, and store it, thus updating my effective extraId for each magicKey on next app reload without an extra table. It costs me one group by query on the first request for a new extraId, which is suboptimal, but it's fast enough for what I need, simple enough to maintain in the future, and all contained in an external class, so I COULD replace it in one place if I ever come up with something more clever. I do dislike having the extra "special query" in my dao for this purpose, but it's easy enough to remove in the future, and well-documented.
Maybe I still didn't understand your problem properly, but I think you can consider using Hibernate's hilo algorithm. It will generate unique identifier for the whole database, based on a table that Hibernate creates and manages. More details here:
http://docs.jboss.org/hibernate/core/3.5/reference/en/html/mapping.html#mapping-declaration-id
This is a problem about historical data handling.
Suppose you have a class MyClass like the following one:
class MyClass {
String field1;
Integer field2;
Long field3;
getField1() {...}
setField1(String ...) {...}
...
}
Now, suppose I need to make MyClass able to store and retrieve old data, what's the best way to do this?
The requirements are to persist the classes through Hibernate, too. And to have at most two tables per "entity": only one table or one table for the "continuity" class (the one which represents the entity which evolves over the time) and another table for the historical data (as it's suggested here)
Please note that I have to be able to assign an arbitrary valid time to the values of the fields.
The class should have an interface like:
class MyClass {
// how to store the fields????
getField1At(Instant i) {...}
setField1At(Instant i, String ...) {...}
...
}
I'm currently using the JTemporal library, and it has a TemporalAttribute<T> class, which is like a map: you can do things like T myAttr.get(Instant i) to get the version of myAttr at Instant i. I know how to persist a TemporalAttribute in a table with Hibernate (it's simple: I persist the SortedMap used by the TemporalAttribute and you get a table with start and end valid time and the value of the attribute).
The real problem is that here we have multiple attributes.
I have a solution in mind but it's not clear, and I'd like to hear your ideas.
Your project reminds me of Hibernate Envers.
The Envers project aims to enable easy
auditing of persistent classes. All
that you have to do is annotate your
persistent class or some of its
properties, that you want to audit,
with #Audited. For each audited
entity, a table will be created, which
will hold the history of changes made
to the entity. You can then retrieve
and query historical data without much
effort.
choose what you want to audit (on a per attribute basis)
make your own Revision Entity (that stores informations such as revision number, author, timestamp...)
Using Hibernate Envers for this decouples entities and revision data (in database and in your code).
You can do something like this simply by adding a version number to your domain class. I did something like this where the Id was a composite between an db assigned number and the version number, but I would advise against that. Use a normal surrogate key, and if you really want, make the [id, version] tuple a natural key.
You can actually version entire object graphs that way, just by ensuring that the version number is the same for all elements on the graph. You can then easily go back to any previous version.
You should write a lot of service tests to insure the integrity of the code that manages the version.
I'm using JPA 1, Hibernate and Oracle 10.2.0 and my entities are defined like this:
#Entity
#Table(name="TERMS")
public class Term implements Serializable {
#Id
#GenericGenerator(name = "generator", strategy = "guid", parameters = {})
#GeneratedValue(generator = "generator")
#Column(name="TERM_ID")
private String termId;
}
I have a situation where an XML representation of the Entity (and child entities) will be coming in through a web service to update/replace existing ones. My thought was to just delete the old ones and re-create it from the incoming XML.
However, doing a persist when my entities having existing IDs seem to make Hibernate very angry. So is this actually possible or is it better to avoid deleting them and just trying to do it with merge?
Angriness from hibernate:
org.hibernate.PersistentObjectException: detached entity passed to persist: com.idbs.omics.catalog.entity.Term
Thanks
My thought was to just delete the old ones and re-create it from the incoming XML. However, doing a persist when my entities having existing IDs seem to make Hibernate very angry..
Indeed, you cannot assign an Id when it is supposed to be generated, at least not with Hibernate that won't consider the entity as new but as detached (the JPA specification is a bit blurry on the exact rules in this case but that's how Hibernate behaves, see 5.1.4.5. Assigned identifiers for more hints).
So is this actually possible or is it better to avoid deleting them and just trying to do it with merge?
To make the delete/insert possible for the web service use case, you'd have to either:
not assign the id ~or~
use a special version of the entity without a generated identifier ~or~
use bulk operations(?)
The alternative if you're actually updating detached entities would be indeed to use a merge (but have a look at these previous questions just in case).
Which approach is better? I don't know, it think it depends on your needs. The later seems more natural if you're updating existing entities. With the former, you'd really get "new" entities (including a new value for the optimistic locking column). Depending on the exact implementation of the process, performances might also vary. And, by the way, what about concurrency (just to mention it, I'm not really expecting an answer)?
You can use EntityManager.merge to save an updated version of the entity. Be aware that this returns another object than the one you pass to it, because it basically fetches the entity from the database, updates the persistent properties from the object you pass and saves the persistent object.
See http://blog.xebia.com/2009/03/23/jpa-implementation-patterns-saving-detached-entities/ for more information on this problem.
I have a class mapped as an Entity to persist it in a database. I have an id field as the primary key so every time the object is persisted the value of the id is retrieved from the sequence "myClass_pk_seq", a code like the following one.
#Entity
#Table(name="myObjects")
public class MyClass {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence")
#SequenceGenerator(name="sequence", sequenceName="myClass_pk_seq", allocationSize=1)
#Column(name="myClassId")
private Integer id;
private Integer code;
...
}
I need to make in "code" attribute something similar to id. I need to have a sequence so I can assign to code the next value of the sequence (to reserve that value in case the user wants to reserve it but without persisting data). I mean the user will see the field, if he doesn't know what to enter he can push a button and receieve in the screen the next possible value (and he can or not accept it). How can I get the next value of a sequence defined in JPA (and increment its value) without persisting the data for a non primary key field?
I just want to have a method which call nextval on a sequence associated with "code" field, and returns the value. What's the best way to do it in JPA with annotations?
Thanks.
I just want to have a method which call nextval on a sequence associated with "code" field, and returns the value. What's the best way to do it in JPA with annotations?
Use native SQL to get the next sequence value when the user pushes the button. Either create the sequence manually or use a "fake entity" to have JPA create it for you.
If you don't want to use native SQL, insert an entity relying on the sequence and gets its id.
Both solutions sounds a bit ugly. Maybe you could simply use a random generator like a UUID generator.
Actually, you didn't mention anything about the uniqueness of the code (and the JPA annotations don't show it must be unique). Why don't you return a random int?
See another question/answers on the subject of using sequence defined elsewhere than id fields. You can create a fake entity with one field (of type Long id). Connect it to the sequence you defined in the DB. Then create a CrudRepository implementation for that entity and call its save() method with an empty instance of the fake entity object you defined. Hibernate will run for you a "select YOUR_SEQ.NEXTVAL from dual" query.