Trouble understanding how to lookup objects that have a Datastore Identity by their PK (if the PK is not identified in the model)


ebenzacar@...
 

I'm migrating an application that was writing with Kodo4 (JDO 2.2).  Most of the objects/models use implicit datastore-identity with no fields identified in the model as the PK, but over time, developers have designed in systems to use the Object Ids (PK) to retrieve the objects by their ID.  I realize that this goes against the concept of datastore-identity and over time will need to change them.

In the meantime, however, I am having trouble figuring out how to retrieve an object using it's ID (Long) that is in the DB.

@PersistenceCapable
@DatastoreIdentity(strategy= IdGeneratorStrategy.SEQUENCE, sequence="toto" )
@Sequence(name="toto", datastoreSequence = "jdo_sequence", strategy=NONTRANSACTIONAL)
public class Organization {
private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}
}



Current code does the following:

public <T> T getObject( String spId, Class<T>persistentClass ) {
Object
id = pm.newObjectIdInstance(persistentClass, spId);
Object obj =
pm.getObjectById(id);
return persistentClass.cast(obj);
}

Unfortunately, with DataNucleus, this is not allowed.  When I try to call `pm.newObjectIdInstance( clazz, Long id )`, an exception is thrown by the ExecutionContext in org.datanucleus.ExecutionContextImpl#newObjectId(java.lang.Class, java.lang.Object) that the key is not a string and the class is not a SingleFieldIdentity.   If I convert the Long to a string, an exception is thrown that it essentially isn't in the right format.

I think I've hacked around the problem a bit by doing the following but it seems hackish - especially considering that I need to use a DN Core class as part of my code and not just leverage JDO methods
DatastoreId datastoreId = new DatastoreIdImplKodo(clazz.getName(), id);
Object oId = pm.newObjectIdInstance(Organization.class, datastoreId.toString()); return clazz.cast(pm.getObjectById(oId));


Is there no way to accomplish this more cleanly?  Can I identify the class/model differently such that it is identified as a SingleFieldIdentity class?

Thanks,

Eric


Andy
 

You mean it obeys the JDO API. Since the "id" for a datastore-identity case as input to pm.newObjectIdInstance has to be the toString() form of the datastore id class then that is to be expected (that you would get back from calling pm.getObjectId()).

The JDO API is managed by the Apache JDO group, which is where you should address any improvement requests.


ebenzacar@...
 

You mean it obeys the JDO API. Since the "id" for a datastore-identity case as input to pm.newObjectIdInstance has to be the toString() form of the datastore id class then that is to be expected (that you would get back from calling pm.getObjectId()).

I understand.  So is my approach the "correct" way of retrieving an object from the datastore (rdbms) by it's id (the sequence id that was generated)?  Or is there a better approach to accomplish this?  Should I be using the DN DatastoreId implementation class directly as in my snippet above?

I'm a bit surprised that Kodo allowed me to do this by Long ID only if that is part of the JDO spec.  

Thanks,

Eric


Andy
 
Edited

Use of implementation-specific classes is always a bad idea IMHO. Imagine hardcoding Kodo-specific stuff and then finding that you need to change provider some time later ...

In the same way, reliance on things outside the JDO spec can be problematic.

You could do something like
MyClass myObj = pm.getObjectById(MyClass.class, theIdValue);
This would likely work whether you are using (single-field) application identity OR datastore identity. And you don't need to cast anything ...
I did add an enhancement to datanucleus-core for datastore-id newObjectId, so whether it needs that only you can find out


ebenzacar@...
 

You could do something like
MyClass myObj = pm.getObjectById(MyClass.class, theIdValue);
This would likely work whether you are using (single-field) application identity OR datastore identity. And you don't need to cast anything ...


Works perfectly.  Didn't realize that the solution was that straightfoward.  I had understood from the javadoc that the `theIdValue` had to be an Identity object.

Thanks,

Eric