Does anyone have tried to implement an app in GAE having both java and python?
I have an existing app and my front end is in java. Now I want to use the existing datastore to be interfaced by python. My problem is i don't know how to define the relationships and model that would be equivalent to the one in java. I have tried the one-to-many relationship in python but when stored in the datastore, the fields are different than the one-to-many of java.
My data classes are as follows.
//one-to-many owned
Parent Class
public class Parent{
#PrimaryKey
#Persistent
private String unitID;
//some other fields...
#Persistent
#Order(extensions = #Extension(vendorName="datanucleus", key="list-ordering", value="dateCreated desc"))
private List <Child> child;
//methods & constructors were omitted
}
Child
public class Child{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key uId;
#Persistent
private String name;
/* etc... */
}
Through some testing, I finally figured out how to do this. First is define the models or in java, it is called classes.
class Parent(db.Model):
someData = db.StringProperty(multiline=True) ....
class Child(db.Model):
someData = db.StringProperty(multiline=True) ...
Now, to set the relationship of an instance of a child to its parent, just set the parent as the ancestor of the child.
parentModel = Parent(key_name='key_of_parent')
childModel1 = Child(parent=parentModel) #set the parentModel as parent of the childModel1
childModel2 = Child(parent=parentModel) #set the parentModel as parent of the childModel2
Now you have an owned one-to-many relationship.
Related
So I am not having any luck with loading the venue and artist object when I load my even object. Basically when I create an event, I load the specific artist and specific venue and save the key in the event's artistKey and venueKey fields. However, when I load even it is always null. I have tried annotations "#Persistent(defaultFetchGroup = "true")" and also "#Persistent(mappedBy = "venue") #Element(dependent = "true")" on my venue and artist with no luck as artist/venue still come up as null when I load an event (the keys are there). When I try the defaultFetchGroup it says I cannot load a parent if it has already been persisted, which make sense I guess.
public class Event {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key id;
#Persistent
private Key artistKey;
#Persistent
private Key venueKey;
private Artist artist;
private Venue venue;
//other fields
//getters and setters
}
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Venue {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key id;
//other fields
//getters and setters
}
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Artist {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key id;
//other fields
//getters and setters
}
with relations (in GAE) you have to pay attention to whether they are owned (stored with the owning object in the datastore) or unowned (like they are in all other datastores). You can mark relations as #Unowned if the latter. GAE has some restrictions around entity groups that impact on this - see their docs
I have entities Profile, Like and Place
Places has Likes.
Likes has reference to place and Profile.
Place has 1-N relation on likes
#PersistenceCapable
public class Place {
#Persistent(mappedBy = "place")
#Element(dependent = "true")
private transient List<Like> likes;
Like has reference to Profile and reference to Place
#PersistenceCapable
public class Like implements Serializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Profile profile;
#Persistent
private Place place;
And profile class hasn't relations to this objects
#PersistenceCapable
public class Profile {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private transient Key key;
What is the best way to add Like to Place existing place with existing profile?
I use the following code to do that:
Profile profile;
Place place;
List<Like> likes;
pm = PMF.get().getPersistenceManager();
try {
place = pm.getObjectById(Place.class, placeId);
likes = place.getLikes();
profile = pm.getObjectById(Profile.class, KeyFactory.createKey(Profile.class.getSimpleName(), login));
} finally {
pm.close();
}
likes.add(new Like(place, profile));
place.setLikes(likes);
pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(place);
} finally {
pm.close();
}
and have duplicate of Profile entity. Is there way to fix it?
Why go to all that trouble of retrieving objects in a transaction, and then close the PM (so the objects become transient, as per the JDO spec) if you're going to add a new Like to the likes of Place? Would make way more sense to just say
place.getLikes().add(new Like(place, profile));
whilst still in the transaction. Indeed, reading about object lifecycles ought to be prerequisite to anybody using any persistence spec (JDO or JPA). Obviously the above is not specific to GAE either.
I am having trouble understanding how the entity groups and relationships work with GAE using JDO.
The scenario I run is basically:
PersistenceManager pm = this.pmf.get();
Player player = new Player();
player.setRanking(new Ranking());
Player persistent = pm.makePersistent(player);
// Here the detached copy is returned, and contains
// all the persistent fields (including the Ranking)
Player detached = pm.detachCopy(persistent);
// In the real code, a lot of processing goes here and manipulates
// The detached copy
// The outcome is basically an updating ranking. What I want to do is
// to assign this new ranking to the player, and persist
// it in the datastore
detached.setRanking(new Ranking());
// An exception is thrown here
pm.makePersistent(detached );
The output of the above code is an exception:
Detected attempt to establish Player(10) as the parent of Ranking(12) but the entity identified by Ranking(12) has already been persisted without a parent. A parent cannot be established or changed once an object has been persisted.
What I understand from that is that the Ranking entity is first persisted (with no parent, so as a root entity), and later on the player is persisted as the parent of the first Ranking entity. Since a parent cannot be changed, this results in an exception being thrown.
However I would like the application to work on the detached copy and manipulate it as it sees fit, and have the entities properly created when the Player entity is persisted in the datastore.
My classes are annotated as follow:
Player.java
#PersistenceCapable(detachable = "true")
#Inheritance(customStrategy = "complete-table")
public class Player implements Serializable, IPlayer {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String id;
#Persistent(defaultFetchGroup="true", dependent="true")
private Ranking ranking;
}
And Ranking.java
#PersistenceCapable(detachable = "true")
#Inheritance(customStrategy = "complete-table")
public class Ranking implements Serializable {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String id;
// If I could I'd rather get rid of this reference to the parent
#Persistent(mappedBy = "ranking", defaultFetchGroup="true")
private Player player;
}
There is something in the entity / entity group paradigm that I obviously don't get, and would be happy to get any hint you may be able to offer on this.
[EDIT]
I have put together a test case to reproduce the issue.
[/EDIT]
Sébastien
I have been trying to learn and creating a sample project using GWT/GAE/GoogleDatastore.
Am just trying to figure out what would be the best way to design the data model for a learning management system. Let's say in the traditional way the following are the entities.....
User
Role
UserCourses
Courses
Subjects
Materials
User is one to one to Role
Courses is one to many with Subjects
Subjects is one to many with Materials
Users is Many to Many with Courses using UserCourses
Can someone guide me what would be the best possible way to represent this in JDO ?
---> Extension of the question.
Thank You Shifty, but am completely stuck with unowned relationship model... trying/struggling to come out of the traditional relational model.
Let me take the simple Subjects vs Materials
Am trying out the following model,
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Subjects {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String id;
#Persistent
private List<Materials> materials;
}
public class Materials{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
#Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
private String id;
#Persistent
private String materialName;
#Persistent
private String author;
#Persistent
private String materialType;
#Persistent
private String url;
}
When i try to save the materials first and then assigning that object into subjects is having issues. As i read, you cannot assign the child to a parent which is already persisted without parent.
Sometimes it is possible to add materials without assigned to the Subjects, but can get assigned later on.
if you want to make a many-to-many relationship with GAE and JDO you have to store a list of the keys in the models.
User Model
import java.util.Set;
import com.google.appengine.api.datastore.Key;
#PersistenceCapable
public class User {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Set<Key> courses;
}
Courses Model
import java.util.Set;
import com.google.appengine.api.datastore.Key;
#PersistenceCapable
public class Courses {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Set<Key> users;
}
this way you don't need the UserCourses class.
EDIT:
If you use
#Persistent
private List<Materials> materials;
you work with a owned relationship model.
this way you can not persist the model first and then add this to the subject model and the persist the subject model.
Just add the not persistent material to the materials list of the subject model and persist the subject model. this will also save the materials.
maybe I could the question wrong but I hope this helps.
I have a parent class and I want to store a HashMap within it. However, every time I try to modify that HashMap I get the following error:
PM org.datanucleus.store.appengine.MetaDataValidator checkForIllegalChildField
WARNING: Unable to validate one-to-many relation com.monsters.server.MonUser.monsters
Any idea what that's about? Here is the code:
This is the code to the Parent class
#PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class MonUser {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent(serialized="true", mappedBy = "owner")
#Element(dependent = "true")
private HashMap<String,Monster> monsters;
...
#PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Monster {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private MonUser owner;
...
I've tried everything on the appengine page on relationships and nothing seems to help. Any info would be extremely helpful!
P.S. I've gotten it to work with ArrayLists and the like but not hashmaps, hashtables, maps, etc. If that helps at all.
Only the following Collections are supported by JDO:
java.util.ArrayList<...>
java.util.HashSet<...>
java.util.LinkedHashSet<...>
java.util.LinkedList<...>
java.util.List<...>
java.util.Set<...>
java.util.SortedSet<...>
java.util.Stack<...>
java.util.TreeSet<...>
java.util.Vector<...>
You can persist a HashMap with:
#Persistent(serialized = "true", defaultFetchGroup="true")
see JDO - HashMap within an embedded Class
To ensure persistence of changes you need to always create a new instance of HashMap see the end of:
http://gae-java-persistence.blogspot.de/2009/10/serialized-fields.html