0

In a Google App Engine app, I have this model:

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Message {

    @PrimaryKey
    @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
    private Long id;

    @Persistent
    private Date timestamp;

    @Persistent
    private String text;

    @Unowned
    @Persistent(defaultFetchGroup = "true")
    private User sender;

    ...
}

The model has an @Unowned relation to a sender, since a user can exist independently of a message.

What I want to do is persist Message objects with partial User objects (e.g. I'm only interested in storing the user id and username). In my endpoint class I'm storing messages just fine, however, if I don't include all fields for the given user in the relationship, the user object is updated with the fields missing (e.g. user in question no longer has a password etc.). What is the best way of achieving what I want, without 'corrupting' the original object?

PS My endpoints method is dead simple. Basically just calling pm.makePersistent(message); on the message (given as a method parameter).

oyvindhauge
  • 3,496
  • 2
  • 29
  • 45

1 Answers1

1

You are using the @Unowned annotation which means that only a reference to the actual User entity will be stored in the sender variable under your Message class.

When you access the sender variable, the Datastore will execute a get query to retrieve the User entity that is linked to the message.

You can confirm this for yourself by navigating to your project's Datastore dashboard (https://console.cloud.google.com/datastore for production, and http://localhost:8080/_ah/admin for local) and browsing the Message entities.

You should see the field where the User is stored named something like user_id_OID with a value of Key(User/XXXXX).

As a side note, Google recommends moving away from JDO/JPA to Objectify or the Datastore API.

Warning: We think most developers will have a better experience using the low-level Datastore API, or one of the open-source APIs developed specifically for Datastore, such as Objectify. JDO was designed for use with traditional relational databases, and so has no way to explicitly represent some of the aspects of Datastore that make it different from relational databases, such as entity groups and ancestor queries. This can lead to subtle issues that are difficult to understand and fix.

See here: https://cloud.google.com/appengine/docs/java/datastore/jdo/overview-dn2

Brett
  • 101
  • 6
  • 1
    Thanks! Although you didn't really address my question, I found your side note interesting. I did not know Google was advising against using JDO. I'll have a look at Objectify. – oyvindhauge Jul 14 '16 at 14:36
  • I could've worded it differently, but what I was trying to say is that the "User" entity in this case is a separate entity from the "Message" - You should create and maintain the "User" entity separately from the "Message" entity. i.e. you will need to Persist the User separately as well. – Brett Jul 14 '16 at 14:40
  • Yes, I'm already doing this. Users live completely separately from messages (user objects are created at registration). However, if I give a message object a user (intentionally leaving out properties of the specific user), the original user object is modified. – oyvindhauge Jul 14 '16 at 14:47
  • I see. Why would you leave out certain properties when persisting the user? So that certain fields are hidden when retrieving a Message? Maybe look into using the **@ApiResourceProperty(ignored=AnnotationBoolean.TRUE)** annotation instead? – Brett Jul 14 '16 at 14:52
  • Just to add: The original User object will be modified since it is only a reference to the original object. – Brett Jul 14 '16 at 14:58
  • That's right, I'm trying to leave out/hide specific fields for the sender when the message is fetched again at some point in the future (e.g. why would i store the user's password with the sender of a message. This feels very wrong to me). But I understand what you are saying about reference. It makes sense. I guess my best option here would be to explicitly leave out desired user properties in the fetch method, and not when persisting the message. – oyvindhauge Jul 14 '16 at 16:13
  • 1
    Just a comment on you repeating Google's "message" ... JDO was NOT designed for use with traditional relational databases. It was written database agnostic, as Google have been told many times. There is nothing in JDO that is RDBMS-centric. There is plenty in JPA that is RDBMS centric. – Neil Stockton Jul 16 '16 at 09:51