I have a datastore kind in which the ID field is String
ofy().load().type( Scores.class ).id( playerName ).now();
This fetches null. I have confirmed the entity with the given playername exists.
This does not happen to another Kind whose ID is long.
Code for Scores class
import com.googlecode.objectify.Key;
import com.googlecode.objectify.annotation.Entity;
import com.googlecode.objectify.annotation.Id;
import com.googlecode.objectify.annotation.Parent;
#Entity
public class Scores
{
#Parent
public Key<RankerRoot> parentKey;
#Id
public String playerName;
public int value;
}
You need to be sure you are giving Objectify enough information to construct the entity's Key. So, if the entity has an ancestor, the ID/Name alone will be insufficient.
If your entity has an ancestor, you can construct the Key and then load the entity by Key, like this:
Key<Scores> scoreKey = Key.create(parentKey, Scores.class, playerName);
ofy().load().key(scoreKey).now();
Related
I have a Patient entity which extends a base Resource object. Now Resource contains a uuid and a display, which I also want to include to the patients table, so I annotate like so:
public class Resource implements Serializable {
#ColumnInfo
protected String uuid;
#ColumnInfo
protected String display;
// getters and setters
}
And in my Patient entity, there are nested objects and they also extend from Resource (e.g. a PatientIdentifier and a Person object is embedded and has their own uuid and display):
#Entity(tableName = "patients")
public class Patient extends Resource implements Serializable {
#PrimaryKey
private Long id;
// ...
#Embedded
private PatientIdentifier identifier;
#Embedded
private Person person;
// other variables
}
this results in a column name conflict - as there is a "uuid" column for a Patient, the PatientIdentifier and the Person.
I want to rename the nested objects' uuid columns after their name (e.g. "person_uuid"), similar to the #ForeignKey annotation in entity relationships, so may I know how to do that?
You can specify the column name like that :
#ColumnInfo(name = "person_uuid")
I'll explain the situation. I followed these two great tuto:
http://rominirani.com/2014/01/10/google-cloud-endpoints-tutorial-part-1/
https://cloud.google.com/developers/articles/how-to-build-mobile-app-with-app-engine-backend-tutorial
However, they explain how create API for Google Cloud Endpoint, with entities independent from each other. So the API class looks like this:
package com.example.mobileassistant;
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* Offer entity.
*/
#Entity
public class Offer {
#Id
private String offerId;
private String title;
private String description;
private String imageUrl;
.... (With Getter and Setter)
}
My question is: How to create a class with a parent entity of another? Like the entitie Wheel, with Parent Car. I can not create a relationship with its parent entity (With the annotation)!
I tried this but it did not seem to work (Foreign Key):
package com.example.mobileassistant;
import javax.jdo.annotations.ForeignKey;
import javax.persistence.Entity;
import javax.persistence.Id;
/**
* Offer entity.
*/
#Entity
public class Wheel {
#Id
private String Id;
#ForeignKey
private String parent_id;
private String title;
private String description;
.... (With Getter and Setter)
}
Actually, I have given up JDO because it don't really support parent entity, like I can read here: http://www.igorkromin.net/index.php/2013/03/14/jdo-youre-dumped-app-engine-and-bi-directional-relationships/
So I'm using now Objectify with Google Cloud Endpoint (For my Android App) and It works so perfect, especially with parent/child relationship !! You can read example here: http://blog.xebia.fr/2014/06/23/google-app-engine-cloud-endpoint-creer-notre-api-v2-et-lutiliser-avec-angularjs/
Why would it when you put it there?
See this page
http://www.datanucleus.org/products/accessplatform/jpa/annotations.html#ForeignKey
which explains clear enough that it is part of the JoinColumn, JoinTable, CollectionTable, SecondaryTable annotations.
I am totally new at this, I am sorry if it is stupid question.
I am trying to design database model for Google App Engine in JPA, but I am unable to get it right. When I find the way I can't get annotations right or I am getting error about M:N not supported in Google App Engine.
I need entity user to have multiple groups and groups have multiple users and there are users who are also group admins.
My basic model was User -> usergroup(user; group; (bool)isAdmin) <-Group
Can somebody give a clean and simple example of how to define relationships?
Please try this.
#Entity
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key id;
private String name;
#ManyToOne(fetch = FetchType.LAZY)
private UserGroup usergroup;
}
class userGroup
#Entity
public class UserGroup {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key id;
private String name;
private boolean admin;
#OneToMany(mappedBy = "usergroup", cascade = CascadeType.ALL)
private List<User> users = new ArrayList<User>();
}
please be noticed GAE have limitation on JPA you can read more here
I don't know anything about Google App Engine, but I can help with JPA though.
The problem here is the "isAdmin" column, which prevents the data model to be a simple #ManyToMany relationship with a joiner table.
With the introduction of this field, in the data model you need a Map on the User entity with key=Group and value=isAdmin, similarly you need a corresponding Map in the Group entity in order to know if each User is an admin.
This is modeled with #ElementCollection in the following way:
#Entity
#Table(name="User")
public class User
{
#Id
#GeneratedValue(strategy= GenerationType.TABLE)
private int id;
private String name;
#ElementCollection
#CollectionTable(name="Users_Groups", joinColumns={#JoinColumn(name="userId")})
#MapKeyJoinColumn(name="groupId")
#Column(name="isAdmin")
private Map<Group, Boolean> groups;
}
#Entity
#Table(name="Group")
public class Group
{
#Id
#GeneratedValue(strategy= GenerationType.TABLE)
private int id;
private String name;
#ElementCollection
#CollectionTable(name="Users_Groups", joinColumns={#JoinColumn(name="groupId")})
#MapKeyJoinColumn(name="userId", insertable=false, updatable=false)
#Column(name="isAdmin", insertable=false, updatable=false)
private Map<User, Boolean> users;
}
The important annotation is #ElementCollection, the other annotations are just to name the specific columns of the collection table and make sure they match from both entities: #CollectionTable gives the name of the table and the name of the column representing the id in the current entity. #MapKeyJoinColumn gives the name of the column representing the id of the "key" element in the Map, and #Column gives the name of the "value" element in the map.
I'm not sure if the insertable=false and updatable=false are needed in one of the entities, might avoid adding duplicate rows due to the cyclic dependency between User and Group.
Also you need to manually create the collection table, because at least EclipseLink tries to create it with two "groupId" and "isAdmin" columns. You might consider reviewing the design if it is absolutely needed a cyclic dependency between User and Group.
I am currently working with GWT, GAE and using JPA as my ORM. I have an issue where the keys that GAE is generating are too large reasonably to be used on a mobile device with RequestFactory. The amount of data in a small list is overwhelming due to the size of the ID/KEY when converted to String.
I am using String for my key's so that I can handle inheritence.
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
protected String key;
This creates a key that is very long example "agxzbWFydGJhcnNpdGVyFAsSDUVzdGFibGlzaG1lbnQYuAIM" and gets larger due to storing object type and parent in the key.
I need a way to create a smaller unique id but still have the ability to handle inheritence in GAE. I tried Long as the #Id/key but was not able to use a #OneToMany relationship on my objects due to the relationship that is built into the String/Key key.
The other option is to create a sequence for each class and use a Long property for that id. There is an example below but I am not sure how to handle a generated Long sequence in app engine.
#GeneratedValue
private Long friendlyClassSpecificKey;
Any advice would be appreciated. If there is another option other than using the sequence for each class type I am interested but if not is there an example of creating a sequence (That is not the #ID) for a specific class?
I came up with a good solution for smaller keys. I think the best way to do this cleanly is to use jpa/jdo 2 for app engine with an unowned relationship. This way you can fetch the keys from (Long) id using just their type and not have to use the parent relationship.
This is the base datstore object and notice I am using the app engine key.
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class DatastoreObject {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
public Long getId() {
return key.getId();
}
}
This class will use the #Unowned attribute supported in jpa 2 so that the inventory's key does not contain the parent establishment key. Otherwise you would have to pass the parent id in also and resolve that to a key based on type. This is because in an owned relationship the child key contains the parent key also.
#Entity
public class Establishment extends DatastoreObject {
#Unowned
#OneToOne(cascade = CascadeType.ALL)
private Inventory inventory;
}
Then in my dao base class I use the class
public class DaoBase<T extends DatastoreObject> {
protected Class<T> clazz;
#SuppressWarnings("unchecked")
public DaoBase() {
clazz = (Class<T>) ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
}
/**
* Find an object by it's shortened long id
* #param id
* #return
* #throws EntityNotFoundException
*/
public T find(Long id) {
if (id == null) {
return null;
}
EntityManager em = ThreadLocalPersistenceManager.getEntityManager();
Key key = getKey(id);
T obj = em.find(clazz, key);
return obj;
}
protected Key getKey(Long id) {
return KeyFactory.createKey(clazz.getSimpleName(), id);
}
}
When saving a Objectify Entity to the Appengine datastore, is it possible to save a custom Datastore "Key" instead of the auto generated Key hash?
You can use any String or long and annotate it as being the key, like this:
import javax.persistence.Id;
public class MyEntityClass {
#Id
private String myCustomKey;
public MyEntityClass(String keyId) {
this.myCustomKey = keyId;
}
}
Then you can retrieve it again using:
MyEntityClass object = ofy().get(new Key<MyEntityClass>(MyEntitiyClass.class, "specificKeyId"));