I am building a web app using GAE Java. I have a class that uses a Long ID (generated by appengine) as its primary key.
I now want to create a new class that would be the parent class to this original class (a one to many relationship) however the child needs to have a primary key of type "key", not the Long ID I have now.
What is the best way to change the primary key to be type "key" instead of long for the existing persisted entities? Should I create a new class with primary key of type "key" and instantiate and persist new objects that copy the field values from the old ones? Or can I somehow just update the existing class?
Thanks
In fact, the Key of a persisted Entity is considered to be immutable. Changing the key will, without a doubt, be equivalent to changing the used instance. What I suggest you is to link your initial object to a child of you created parent.
You could store the existing Long IDs in a list in the parent class: that would create the necessary one-to-many parent-child relationship.
You would have to manage consistency yourself though (which may not be too difficult if your site doesn't have very high traffic), and the parent and child classes would not be in the same entity group (implications for transactions).
Changing the key means changing the Entity itself (and also its entity group).
Ultimately, the solution that works for you will depend on the specifics of your problem. For example, is there already a lot of existing data? Is this a live application (i.e., is it already being used)?
Another solution could be to migrate your app over to a different (better suited) data model, and do so account-by-account (by locking out the account for a brief period of time). This way only a few individuals will be affected by the change (if they happen to access the app when you are migrating their account) rather than the whole app being down.
Related
I have two consecutive operations that need to happen.
First, I insert a new record (I'm using JPA), to use as a historical record, and then I run an update to a record that is always used as the most "current" with information coming in on the call.
The problem is that the object has a composite key, which I need to insert it, but I don't want it returned in the JSON that I return after the update. JPA has a real problem with altering the composite keys, but I found the .detach method which has worked for me in the past. The fields I want to be null are marked as #Transient in the actual object, and no error is thrown. It performs the insert fine, but the update fails if I try to move the primary keys at ALL. Even after the insert is called, and even using the .detach method. Any ideas what I'm missing?
I would think I could do it like so:
em.merge(contract); //Object to be saved
em.detach(contract); // allows me to manipulate it
policy.setContractNum(policy.getId().getContractNum());
policy.setCustNum(policy.getId().getCustNum());
returnPolicyAsList.add(policy);
customer.setPolicies(returnPolicyAsList);
status.setFamCustomer(customer);
status.setStatus(Message.SUCCESS);
status.setStatusMessage(Message.SUCCESS);
return status;
You seem not to quite be in tune with JPA's model of the world. An entity's primary key is its identity. As such, you should never modify the primary key of a persistent entity.
That conflicts a bit with Java's view, which attributes a separate identity to each object. You work with the Java view with entities that are not persistent -- i.e. those that are new, detached, or removed. That's why you can twiddle an entity's PK once you detach it, but you have to understand that doing so changes its identity from JPA's viewpoint. If you later try to merge such an entity then JPA sees only its new identity, not its old one.
If you need to change an entity's PK (generally a bad idea) then you should delete it, change the PK, and then persist it again. On the other hand, if your PK comprises information that may change over time, then you really ought to choose a different PK. Indeed, JPA works most smoothly when you use surrogate PKs instead of PKs comprising business data.
I've been using JPA 2.0 for a while but, sad to admit, I haven't had enough time to learn it properly. It seems like I lack the basics of how to work with Entity Manager.
Moving one step at a time, I'd like to first ask you about maintaining relationships between mapped entities. Of course I know how to create mappings between entities, different types of available associations (OneToOne, etc.) and how databases work in general. I'm purely focused on maintaining it via Entity Manager, so please do not send me to any kind of general knowledge tutorial :-).
The questions are:
Am I right that as a programmer I'm responsible for maintaining (creating/updating/removing) relationships between instances of entities?
Do I have to always update (set to null, remove from collection, etc.) instances by hand?
Plain SQL can set entities to NULL on deleting, but it seems like JPA can't do such a simple thing. It also seems like a burden to do it manually. Is there a way to achieve that with JPA?
If I have OneToMany relationship and set to NULL the entity on the Many side of the relationship. Then I persist the changes in a Set by saving the entity on the One side. Do I then have to update the entities in the Many side and set association to NULL in each instance? Seems pure silliness for one-directional bindings!
Thanks in advance!
The main thing you need to investigate is the different options you have when mapping on entity. For example in the next piece of code the cascade all option will instruct jpa to delete the child list when the parent is deleted.
#OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.ALL }, mappedBy = "parent")
private Set<Child> events = new HashSet<Child>();
Yes. You maintain the object tree and modify it to look like what
you want.
Yes and no. If you want the entity to reference null, then yes.
For instance, if you are removing one Entity, then you should clean
up any references to it held by other entities that you are not
removing. A practical example: its good practice to let an Employee
know his/her Manager has been let go. If the Employee is going to
stay, it should either have its manager reference nulled out or set
to a different manager, before the current manager can be removed.
If the employee is going to be removed as well, then cascade remove
can cascade to all the Manager's subordinates, in which case you do
not need to clean up their references to the manager - as they are
going away too.
I don't quite understand what SQL is setting to null. Deleting
removes the row in the database, so there isn't anything to set to
null. Cleaning up a reference shouldn't be that difficult in the
object model, as JPA has a number of events to help such as
preremove preupdate etc. In the end though, the problem is with
your java objects. They are just java objects, so if you want
something done, your application will need to do it for the most
part. JPA handles building them and pushing them to the database,
not changing the state for you.
Yes and no. If you set up a bidirectional relationship, you must
maintain both sides as mentioned above. If you set the child's
parent reference to null, you should let the parent know it no
longer has a child, wouldn't you? Your parent will continue to
reference its child for as long as that Parent instance exists. So
even though the database is updated/controlled through the side that
owns a relationship, the object model will be out of synch with the
database until it is refreshed or somehow reloaded. JPA allows for
multiple levels of caching, so it all depends on your provider setup
how long that Parent instance will exist referencing a Child that no
longer exists in the database.
In my applications I have a set of object which stay alive during the whole application lifecycle and I need to create an historical database of them.
These objects are instances of a hierarchy of Java / Scala classes annotated with Hibernate annotations, which I use in my application to load them at startup. Luckily all the classes already contain a timestamp, which means that I do not need to change the object model to be able to create historical records.
What is the most suitable approach:
Use Hibernate without annotations and providing external xml mappings, which are the same as the one of annotations besides the primary key ( which is now a composite key consisting of the previous primary key + the timestamp)
Use other classes for historical records ( this sounds very complicated, as I do have a hierarchy of classes and not a single class, and I would have to subclass my HistoricalRecordClass for every type of record, as I want to build it back). Still use Hibernate
Use a completely different approach (Please not I do not like ORMS, it is just a matter of convience)
Some considerations:
The goal of storing historical records is that the user, through a single GUI, might access both the real-time values of certain data or the historical value, just by specifying a date.
How do you intend to use the historical records? The easiest solution would be to serialize them as JSON and log them to a file.
I've never combined hibernate xml mappings in conjunction with hibernate annotations, but if it worked, it sounds more attractive than carrying two parallel object models.
If you need to be able to recreate the application state at any point in time, then you're more or less stuck with writing them to a database (because of the fast random access). You could cheat and have a "history" table that has a composite key of id + timestamp + type, then a "json" field where you just marshal the thing down and save it. That would help with a) carrying one history table instead of a bunch of clone tables, and b) give you some flexibility if the schema changes (i.e. leverage the open schema nature of JSON)
But since it's archive data with a different usage pattern (you're just reading/writing the records whole), I'd think about some other means of storing it than with the same strict schema as the live data.
It's a nice application of the "write once" paradigm... do you have Hadoop available? ;)
I am starting to use JPA and I always get confused with the term of entities and their usage, I have read a lot but I still don't quite get it.
I read the Oracle documentation of it but it does not really explain its role in the transaction.
What are JPA enities? does they actually hold the data for each row, I mean, are they stored instances that hold the row data? or they just map tables of the db and then insert and delete in them?
for example if I use this:
entity.setUserName("michel");
Then persisting it, then changing the user name, and persisitig it again (i.e merging it)
Does this change the previously entered user name? or does it create a new row in the db?
An Entity is roughly the same thing as an instance of a class when you are thinking from a code perspective or a row in a table (basically) when you are thinking from a database perspective.
So, it's essentially a persisted / persistable instance of a class. Changing values on it works just like changing values on any other class instance. The difference is that you can persist those changes and, in general, the current state of the class instance (entity) will overwrite the values the row for that instance (entity) had in the database, based on the primary key in the database matching the "id" or similar field in the class instance (entity).
There are exceptions to this behavior, of course, but this is true in general.
It's a model. It's a domain object that can be persisted. Don't over think it. Akin to a Rails model. And remember, models (in this paradigm) are mutable!
My problem is pretty much obvious:
I had a class named TaskDescription which corresponded to a kind (table) in App Engine Datastore.
Then I've renamed it to TaskContent and all stored data is seems to be lost now (because class name which is the so-called kind name is a part of the path to the stored data).
I realize that almost the same problem will occur every time I rename a single field in any entity-class.
Nothing is perfect in this world and I have doubts that it's possible to create all and absolutely correct entities from scratch and never change them after that.
So, how to deal with this issue?
Two ways:
Leave Entities as they are and change the mapping: in objectify you can set the entity to class name mapping: e.g. #Entity(name="EntityName").
Change Entities in the datastore: as datastore is schemaless this can not be done with a simple command. For Entity name change you need to create a new entity, copy all properties and delete the old entity. People usually use a MapReduce jobs to perform datastore maintenance. Here's MapReduce for java.
For field name changes objectify has explicit support for migrating schemas (there is no schemas, but they still call it that way).