JDO - Updating an Object - java

i am experimenting with the Google App Engine, and the persist option JDO.
I would like to know if it is possible to map a transient object to a persist object? Or something to update the persistent object with the use of an transient object?
I the coding examples i see the following piece of code to update objects:
public void updateEmployeeTitle(User user, String newTitle) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Employee e = pm.getObjectById(Employee.class, user.getEmail());
if (titleChangeIsAuthorized(e, newTitle) {
e.setTitle(newTitle);
} else {
throw new UnauthorizedTitleChangeException(e, newTitle);
}
} finally {
pm.close();
}
}
But this is not what i want, does anybody know if i can update the whole object like JPA does: object.update();
So i would like something like this:
public User update(User u) {
PersistenceManager pm = PMF.get().getPersistenceManager();
User usr;
try {
usr = pm.getObjectById(User.class, u.getId());
// copy transient object u to persist object usr.
// on update of usr all changes in object u are persistent.
} finally {
pm.close();
}
return u;
}

A "transient" object has no "identity" so there is no way to locate it in a datastore. Think carefully if you want to use transient objects, or whether it would be better to just use detached objects. JPA uses the equivalent of a "detached" object. JDO can do that too and then you just call pm.makePersistent(detachedObj);
--Andy (DataNucleus)

Related

Hibernate could not initialize proxy - no Session

My code retrieves all information related to the user:
SessionFactory sessionFactory = HibernateUtilities.configureSessionFactory();
Session session = sessionFactory.openSession();
UserDetails ud = null;
Set<Address> userAddress = null;
try {
session.beginTransaction();
ud = (UserDetails) session.get(UserDetails.class, 1);
userAddress = ud.getAddresses();
session.getTransaction().commit();
} catch (HibernateException e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
session.close();
}
System.out.println(ud.getName());
for(Address addr: userAddress){
System.out.println("State " + addr.getState());
}
The ud.getAddresses() simply returns a set of Addresses of the user.
My question is: why does the ud object still have its value (eg, name) even though the session is already closed? getAddresses() is an instance variable of the UserDetails class. But why can't I retrieve its value but I can retrieve regular instance variables of the UserDetails class?
ud.getAddresses() is an #EmbeddedCollection.
I faced the same issue in JPA/Hibernate, and there are 2 ways to solve this issue:
1/ Turn off the LAZY by default, as following:
#Entity
#Proxy(lazy = false)
public class Project {
...
}
Of course, this way is not recommended because of the performance issue, so you can go to the second way.
2/ You can put #Transactional at the beginning of your method, it can help you to remain the session, or another understanding, it pass the duty of session to Hibernate, as following:
#Test
#Transactional
public void testSaveGroup() {
Department g = new Department();
g.setName("XDG");
assertNull(g.getId());
this.groupRepo.save(g);
assertNotNull(g.getId());
System.out.println(g.getId());
Project dummyPrj = new Project(123L, "KSTA", new Date(), "NEW", "Helm AG", g);
this.projectRepo.save(dummyPrj);
// verify
List<Department> lst = this.groupRepo.findAll();
Project savedPrj = this.projectRepo.getOne(123L);
Assert.assertEquals("XDG", savedPrj.getGroup().getName());
}
My answer is late, but hope to help someone else :)
userAddress = ud.getAddresses();
session.getTransaction().commit();
for(Address addr: userAddress) {
The hibernate documentation for working with lazy associations clearly calls out this kind of access as an error. You can interact with lazily associated objects only while the session is still open. That portion of the documentation also provides alternatives to access such lazily associated members of an object and we prefer to specify the fetch mode as JOIN in the criteria used, in our applications.
All the primitive properties of the classes are loaded right away, they can't be lazy unless you're using bytecode enhancements. Only real associations like your collection can be lazy.

Object not storing in Google App Engine datastore

I'm having a problem storing an object in the datastore. I have an object, MyObject, that I'm trying to store but when the code is executed nothing happens. I go to look at the datastore dashboard and MyObject isn't there. No exceptions are thrown and there are no errors.
Here's my object
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class MyObject{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
String name;
#Persistent
String beta;
#Persistent
double loc;
public MyObject(String name1){
name = name1;
}
//getters and setters
}
and here's the code to store the object
public static void saveMyObject(MyObject a)throws Exception{
PersistenceManager pm = PMF.get().getPersistenceManager();
try{
pm.makePersistent(a);
}
catch(Exception e){
throw e;
}
finally{
pm.close();
}
}
Can anyone see what I'm missing?
It looks like you are using JDO, so you might want either to add a JDO tag or else mention that somewhere....
I would replace
try
{
pm.makePersistent(a);
}
with
try
{
MyObject myObj = new MyObject(a.getName()); // or whatever the getter is
myObj.setField2(a.getField2()); // Copy 1 data member from a
... // Make a MyObject.copy(...) method?
pm.makePersistent(myObj);
}
The key thing is that JDO uses enhancement: magic bytecode that is inserted after main Java compilation. I manipulate my persistent entity objects within the lifecycle ("scope") of enhancement to get JDO to work.
I also use transactions for writing (I don't know your JDO auto-transaction setting(s)). I always use transactions when creating and persisting a new persistent entity. You might want to try that if the change above does not work.

Why does JDO think this detached object is clean?

I am trying to learn JDO (and at the same time its GAE and Spring intricacies) by creating a small web app, and am having trouble getting updated domain objects to persist back to the database. I initially grab the entity from the DB and detach it so that I can show it to the user and allow them to change it. Once the user has made the changes and posts the form back to the app, I again grab the entity from the DB (detached), update its properties, and then call a pm.makePersistent(). The abbreviated code is as follows:
User Domain Object:
#PersistenceCapable(detachable="true")
public class User extends BaseEntity {
#Persistent
private String firstName = "";
#Persistent
private String middleInitial = "";
#Persistent
private String lastName = "";
}
DAO Read Method:
public User read(Key key) throws DataException {
PersistenceManager pm = PMF.get().getPersistenceManager();
User pkg, detached = null;
try {
pkg = (User) pm.getObjectById(User.class, key);
detached = pm.detachCopy(pkg);
detached.setIsAlreadyInDB(true);
}
catch (Exception e) {
throw new DataException("An error occured trying to read the User object. Details:\n" + e.getMessage());
}
finally {
pm.close();
}
return detached;
}
DAO Update Method:
private void update(User pkg) throws DataException {
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction tx = pm.currentTransaction();
try {
tx.begin();
pm.makePersistent(pkg);
tx.commit();
}
finally {
if (tx.isActive()) tx.rollback();
pm.close();
}
}
Now when I get down into the update method, I've proven to myself that I'm working with just the same object from my read via inspecting its hashCode(), I've changed a value using the domain object's setter method, I've even printed the changed value to the console to make sure it's getting done, and JDOHelper.isDirty() still returns false, and therefore none of the changes get persisted back to the database.
Any thoughts on what I'm missing or if I'm approaching this from the wrong angle? Thank you for helping out a JDO beginner!
JDOHelper.isDirty is for managed objects. A detached object is not managed. DataNucleus provides a helper method of its own to get the dirty fields while detached since the logic is implementation-specific
String[] dirtyFieldNames = NucleusJDOHelper.getDetachedObjectDirtyFields(obj, pm);

Why do my updates not work?

I am new to GAE, and to JDO, I am getting stuck with how to update data.
Using the code below, if I do a getAll(), then a get() on an object, then alter an attribute for that object returned by get(), then a getAll(), the second call to getAll() returns the original un-altered object.
I tried doing a flush() but that doesn't seem to help. If I restart jetty, the data is not persisted.
public class Notes {
#SuppressWarnings("unchecked")
public List<Note> getAll() {
PersistenceManager pm = PMF.instance().getPersistenceManager();
Query query = pm.newQuery("select from com.uptecs.google1.model.Note order by subject");
return (List<Note>) query.execute();
}
public void add(Note note) {
PersistenceManager pm = PMF.instance().getPersistenceManager();
pm.makePersistent(note);
pm.flush();
}
public Note get(long id) {
PersistenceManager pm = PMF.instance().getPersistenceManager();
return (Note)pm.getObjectById(Note.class, id);
}
public void update(Note note) {
PersistenceManager pm = PMF.instance().getPersistenceManager();
pm.flush();
}
}
For a good overview look at these articles:
http://www.ibm.com/developerworks/java/library/j-gaej1/
http://www.ibm.com/developerworks/java/library/j-gaej2/index.html
http://www.ibm.com/developerworks/java/library/j-gaej3.html
2 and 3 are most relevant.
public void add(Note note) {
PersistenceManager pm = getPersistenceManagerFactory()
.getPersistenceManager();
try {
pm.makePersistent(note);
} finally {
pm.close();
}
}
Have you looked at the AppEngine Getting Started Guide? They have a pretty extensive guide on using the JDO API.
Sounds like you aren't calling close() after modifying the persistent object.
I am not very familiar with JDO but don't you have to commit() or save() your data before flush? I think only these statements will persist in the database.
Perhaps actually closing your PersistenceManagers may help (never mind the memory utilisation reasons!)

Loading a collection of Enums with Google app engine datastore

I am using the Goole app engine datastore with Java and trying to load an Object with a List of Enums. Every time I load the object the List is null. The object is
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class ObjectToSave {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
#Persistent
private List<AnEnum> anEnumList;
//public getters and setters
}
The enum is simple
public enum AnEnum {
VALUE_1,
VALUE_2;
}
The code to save it is
ObjectToSave objectToSave = new ObjectToSave();
List<AnEnum> anEnumList = new ArrayList<AnEnum>();
anEnumList.add(AnEnum.VALUE_1);
objectToSave.setAnEnumList(anEnumList);
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
pm.makePersistent(objectToSave);
} finally {
pm.close();
}
The code to load it is
PersistenceManager pm = pmfInstance.getPersistenceManager();
try {
Key key = KeyFactory.createKey(ObjectToSave.class.getSimpleName(), id);
ObjectToSave objectToSave = pm.getObjectById(ObjectToSave.class, key);
} finally {
pm.close();
}
I can view the data in the datastore using http://localhost:8080/_ah/admin and can see my List has been saved but it is not there when the object is loaded.
I created my project with the Eclipse plugin and haven't made any changes to the datastore settings as far as I know. So why id my Enum list null?
Yes but your List field is not in the default fetch group at loading so hence is not loaded.
Read JDO Fetch Groups. You could add it to the DFG, or enable a custom fetch group, or just "touch" the field before closing the PM.
--Andy (DataNucleus)
How are you creating an instance of ObjectToSave? The default value of all instance variable reference types is null, so unless you have (additional) code to create an instance of List<AnEnum> and assign it to anEnumList, null would be expected.

Categories