Note that there are some explanatory texts on larger screens.

plurals
  1. POUpdating objects in GAE
    primarykey
    data
    text
    <p>I have a problem that I can't be able to solve. I've tried to search on the web for solutions, but I didn't find any generic solution. I want to update an object, whatever it's class may be, in the datastore. For that, here's the code I'm using for the project</p> <p>I'm using DataNucleus and Google AppEngine.</p> <p>Here's my jdoconfig.xml</p> <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt; &lt;jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig"&gt; &lt;persistence-manager-factory name="transactions-optional"&gt; &lt;property name="javax.jdo.PersistenceManagerFactoryClass" value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/&gt; &lt;property name="javax.jdo.option.ConnectionURL" value="appengine"/&gt; &lt;property name="javax.jdo.option.NontransactionalRead" value="true"/&gt; &lt;property name="javax.jdo.option.NontransactionalWrite" value="true"/&gt; &lt;property name="javax.jdo.option.RetainValues" value="true"/&gt; &lt;property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/&gt; &lt;/persistence-manager-factory&gt; &lt;/jdoconfig&gt; </code></pre> <p>My PMF class</p> <pre><code>public final class PMF { private static final PersistenceManagerFactory pmfInstance = JDOHelper.getPersistenceManagerFactory("transactions-optional"); private PMF() {} public static PersistenceManagerFactory get() { return pmfInstance; } public static PersistenceManager getPersistenceManager() { return pmfInstance.getPersistenceManager(); } } </code></pre> <p>My BaseModel class, wich is a superclass for all the models of the project</p> <pre><code>@Inheritance(strategy = InheritanceStrategy.SUBCLASS_TABLE) @PersistenceCapable(detachable = "true", identityType = IdentityType.APPLICATION) public abstract class BaseModel implements Serializable { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) protected Key id; public boolean equals(Object obj) { try { return obj instanceof BaseModel ? this.getId().getId() == ((BaseModel) obj).getId().getId() : false; } catch (Exception e) { return false; } } } </code></pre> <p>Here's the class (<code>Project</code>) I want to save</p> <pre><code>@PersistenceCapable(detachable = "true", identityType = IdentityType.APPLICATION) public class Project extends BaseModel implements BeanModelTag { private static final long serialVersionUID = 3318013676594981107L; @Persistent private String name; @Persistent private String description; @Persistent private Date deadline; @Persistent private Integer status; @Persistent private Key manager; @Persistent private Set&lt;Key&gt; team; } </code></pre> <p>For that, I tried several things. This method below saves a NEW instance of Project with success, but when I call to for updating an already detached object, only the field <em>deadline</em> is updated, the other attributes aren't updated (and yet, I went in debug mode to check out if the other attributes where changed, and yes, they were, but only deadline get's saved).</p> <pre><code>public void save(BaseModel object) { PersistenceManager pm = PMF.getPersistenceManager(); try { pm.makePersistent(object); } finally { pm.close(); } } </code></pre> <p>So, I tried the following code</p> <pre><code>public void update(Project object) { PersistenceManager pm = PMF.get().getPersistenceManager(); try { pm.currentTransaction().begin(); Project p = pm.getObjectById(Project.class, object.getId()); p.setName(object.getName()); p.setDeadline(object.getDeadline()); p.setDescription(object.getDescription()); p.setTeam(p.getTeam()); p.setStatus(object.getStatus()); pm.currentTransaction().commit(); } catch (Exception e) { e.printStackTrace(); pm.currentTransaction().rollback(); } finally { pm.close(); } } </code></pre> <p>And it worked. Ok, it works in this way, but I need a generic method for all my models, so I tried this</p> <pre><code>public void update(BaseModel object) { PersistenceManager pm = PMF.get().getPersistenceManager(); try { pm.currentTransaction().begin(); BaseModel ob = pm.getObjectById(object.getClass(), object.getId()); for (Field f : ob.getClass().getDeclaredFields()) { if (!f.toString().contains("final")) { f.setAccessible(true); for (Field g : object.getClass().getDeclaredFields()) { g.setAccessible(true); if (f.getName().equals(g.getName())) { f.set(ob, g.get(object)); } g.setAccessible(false); } } f.setAccessible(false); } pm.makePersistent(ob); pm.currentTransaction().commit(); } catch (Exception e) { e.printStackTrace(); pm.currentTransaction().rollback(); } finally { pm.close(); } } </code></pre> <p>But it doesn't work at all, nothing gets saved, and yet when I System.out the attributes manually, they are changed. I tried with and without <code>pm.makePersistent(ob);</code> with no luck. I don't know what to do. I have 120 models in this project that inherits from <code>BaseModel</code> and I can't find a way to make an update that works with my model.</p> <h2>----------- Edit -----------</h2> <p>Thanks for the answer. Here's my solution for now. Of course, that printStrackTree will get out of there.</p> <pre><code>public void update(BaseModel object) { PersistenceManager pm = PMF.get().getPersistenceManager(); try { pm.currentTransaction().begin(); BaseModel ob = pm.getObjectById(object.getClass(), object.getId()); for (Field f : ob.getClass().getDeclaredFields()) { if (!Pattern.compile("\\bfinal\\b").matcher(f.toString()).find()) { f.setAccessible(true); for (Field g : object.getClass().getDeclaredFields()) { g.setAccessible(true); if (f.getName().equals(g.getName())) { f.set(ob, g.get(object)); JDOHelper.makeDirty(ob, f.getName()); } g.setAccessible(false); } f.setAccessible(false); } } pm.makePersistent(object); pm.currentTransaction().commit(); } catch (Exception e) { e.printStackTrace(); pm.currentTransaction().rollback(); } finally { pm.close(); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload