Id field in Entity - google-app-engine

I have made google app engine backend for my android client app.
I made my entity class and autogenerated end point class for it in Android studio.
This auto generated class has method:
public XXX getXXX(#Named("id") Long id)
I plan to use Query api to add as well as fetch the entity.
IndexSpec indexSpec = IndexSpec.newBuilder().setName("XXX_Index").build();
Index index = SearchServiceFactory.getSearchService().getIndex(indexSpec);
It has got me a bit confused. I understand that when I insert entity first time, app engine data store auto generates id for the entity.This id can be string.So how to make my id compatible with auto generated getXXX method which takes Long as input.
Manish

AppEngine datastore key property has two components, Name and Id. Name property can be string and Id property can be Long. You can use either Name or Id as part of your entity key.
Using JDO
you can set long property as below
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
See documentation Jdo doc

Related

Read embedded entity from python ndb client

I am using the google cloud datastore python client to write an entity into the datastore which contains an embedded entity. An example entity might look like:
data_type: 1
raw_bytes: <unindexed blob>
values: <indexed embedded entity>
I checked the data from the console and the data is getting saved correctly and the values are present.
Next, I need to run a query from a python app engine application. I have represented the above as the following entity in my app engine code:
class DataValues(ndb.Model):
param1 = ndb.BooleanProperty()
param2 = ndb.IntegerProperty()
param3 = ndb.IntegerProperty()
class MyEntity(ndb.Expando):
data_type = ndb.IntegerProperty(required=True)
raw_bytes = ndb.BlobProperty()
values = ndb.StructuredProperty(DataValues)
One of the filters in the query depends on a property in values. Sample query code is as below:
MyEntity.query().filter(MyEntity.data_type == 1).filter(MyEntity.values.param1 == True).get()
I have created the corresponding composite index in my index.yaml
The query runs successfully but the resulting entity contains the embedded entity values as None. All other property values are present.
What can be the issue here ?
Add properties of DataValues entity as properties of the MyEntity.
This is a bit of a guess, but since datastore attributes are kind of keyed by both their name (in this case values) and the name of the "field type/class" (i.e. StructuredProperty), this might fix your problem:
class EmbeddedProperty(ndb.StructuredProperty):
pass
class MyEntity(ndb.Expando):
data_type = ndb.IntegerProperty(required=True)
raw_bytes = ndb.BlobProperty()
values = EmbeddedProperty(DataValues)
Give it a shot and let me know if values starts coming back non-null.
I struggled with the same problem, wanting to convert the embedded entity into a Python dictionary. One possible solution, although not a very elegant one, is to use a GenericProperty:
class MyEntity(ndb.Model):
data_type = ndb.IntegerProperty(required=True)
raw_bytes = ndb.BlobProperty()
values = ndb.GenericProperty()
values will then be read as an "Expando" object: Expando(param1=False,...). You can access the individual values with values.param1, values.param2 etc. I would prefer having a custom model class, but this should do the job.

Failed to create a new object in app-engine: repeated primary key (id: type long)

1.- Create object id
// Allocate a key for the conference -- let App Engine allocate the ID
final Key<Conference> conferenceKey = factory().allocateId(profileKey, Conference.class);
// Get the Conference Id from the Key
final long conferenceId = conferenceKey.getId();
2.- Create objeto, add id
// Create Conference
Conference conference = new Conference(conferenceId,userId,conferenceForm);
3.- Save object:
// Save Conference and Profile Entities
ofy().save().entities(profile,conference).now();
ofy().save().entity(conference).now();
4.- Error, multiples times using same id (Datastore google)
Note: Same objects created with same ANDROID_CLIENT_ID (release mode)
What you are seeing is correct. Your screenshot shows 2 entities with ID=1, but with different Parents (ancestor paths).
A Datastore Key is formed from its full ancestor path and it is the Key that is unique - not the ID/Name. The ID/Name is only unique within the scope of its Parent. If an entity has no ancestor, then you would expect the ID to be unique.
This page gives a good overview of Keys.

Hibernate Annotation Exception when migrating from JBoss 5.1 to JBoss EAP 6

My understanding is that JBoss 5.1 uses Hibernate 3.4.0.GA. JBoss 6 uses Hibernate 4.2.18.Final.
I have an entity class with a #ManyToOne,#JoinTable reference which seems to run fine in JBoss 5.1. Please see the simplified class below.
#Entity
#Table(name = "[Professional Activity (Field Display Names)]")
public class ProfessionalActivity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
private Long id;
#ManyToOne
#JoinTable(name = "[Professional Activity User Relationship]",
joinColumns = #JoinColumn(name = "[Professional Activity ID]"),
inverseJoinColumns = #JoinColumn(name = "[User ID]"))
private User user;
}
Needless to say (but I'll say it anyway!), [Professional Activity User Relationship] is just a "Join Table" that maps Professional Activities to Users. Again, this is working great with old Hibernate. Is this a bug in Hibernate 4 or is there a better way to be annotating this? This is the stack trace I'm getting:
Exception in thread "main" javax.persistence.PersistenceException: [PersistenceUnit: efcEntityManagerLocal] Unable to build EntityManagerFactory
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:925)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:900)
at org.hibernate.ejb.HibernatePersistence.createEntityManagerFactory(HibernatePersistence.java:59)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:63)
at javax.persistence.Persistence.createEntityManagerFactory(Persistence.java:47)
at edu.emory.first.cache.service.HibernateTest.main(HibernateTest.java:15)
Caused by: org.hibernate.AnnotationException: Cannot find the expected secondary table: no Professional Activity User Relationship available for edu.emory.first.cache.model.ProfessionalActivity
at org.hibernate.cfg.Ejb3Column.getJoin(Ejb3Column.java:372)
at org.hibernate.cfg.Ejb3Column.getTable(Ejb3Column.java:351)
at org.hibernate.cfg.AnnotationBinder.bindManyToOne(AnnotationBinder.java:2741)
at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1728)
at org.hibernate.cfg.AnnotationBinder.processIdPropertiesIfNotAlready(AnnotationBinder.java:895)
at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:728)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processAnnotatedClassesQueue(Configuration.java:3625)
at org.hibernate.cfg.Configuration$MetadataSourceQueue.processMetadata(Configuration.java:3579)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1381)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1786)
at org.hibernate.ejb.EntityManagerFactoryImpl.<init>(EntityManagerFactoryImpl.java:96)
at org.hibernate.ejb.Ejb3Configuration.buildEntityManagerFactory(Ejb3Configuration.java:915)
... 5 more
Update
It looks like it might be related to the fact that my backing DB is a SQLServer Database and the table I'm trying to join is required to have either brackets, back-ticks, or quotes (when I escape them with a backslash).
Basically, these three make the SQL happy but not Hibernate:
name = "\"Professional Activity User Relationship\""
name = "`Professional Activity User Relationship`"
name = "[Professional Activity User Relationship]"
I've tried changing the Dialects from Sql2008Server, Sql2012Server, etc. to no avail. I've tried NO specified dialect in the persistence.xml and that didn't seem to change anything.
Basically I see two workarounds, although I'd rather not do either.
Create a view of the offending table and make the name with no spaces so I don't have to use the characters([,`,\") which seem to be causing the issue (i.e. Professional_Activity_User_Relationship_View).
Create an entity class for the join table, add a few ManyToOne Relationships and just increase my joins at the EntityManager query level.
Neither are optimal. Is this an issue I should raise with Hibernate? Seems like even switching to 5 didn't resolve the issue.
Update 2
I have created a JIRA ticket for this: https://hibernate.atlassian.net/browse/HHH-10660

Autogenerated id using JPA for GAE (key as encoded String)

How to declare id field as "Key as encoded String" in JPA entity (not JDO) for usage in GAE Datastore? You can find example for JDO, but not for JPA.
Can't declare id fields as Long as entity is used in child-parent relations.
So, my entity is like this:
#Entity
public class EntityClass {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
private String id;
So, it uses both JPA and JDO annotations.
So, while trying to persist entity object i'm getting an exception:
Cannot have a null primary key field if the field is unencoded and of type String. Please provide a value or, if you want the datastore to generate an id on your behalf, change the type of the field to Long.
org.datanucleus.store.appengine.FatalNucleusUserException: Invalid primary key for name.xxx.tips.db.User. Cannot have a null primary key field if the field is unencoded and of type String. Please provide a value or, if you want the datastore to generate an id on your behalf, change the type of the field to Long.
Full Stacktrace:
Cannot have a null primary key field if the field is unencoded and of type String. Please provide a value or, if you want the datastore to generate an id on your behalf, change the type of the field to Long.
org.datanucleus.store.appengine.FatalNucleusUserException: Invalid primary key for name.xxx.tips.db.User. Cannot have a null primary key field if the field is unencoded and of type String. Please provide a value or, if you want the datastore to generate an id on your behalf, change the type of the field to Long.
at org.datanucleus.store.appengine.DatastoreFieldManager.storeStringPKField(DatastoreFieldManager.java:540)
at org.datanucleus.store.appengine.DatastoreFieldManager.storeStringField(DatastoreFieldManager.java:460)
at org.datanucleus.state.AbstractStateManager.providedStringField(AbstractStateManager.java:1023)
at name.xxx.tips.db.User.jdoProvideField(User.java)
at name.xxx.tips.db.User.jdoProvideFields(User.java)
at org.datanucleus.state.JDOStateManagerImpl.provideFields(JDOStateManagerImpl.java:2715)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertPreProcess(DatastorePersistenceHandler.java:357)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObjects(DatastorePersistenceHandler.java:267)
at org.datanucleus.store.appengine.DatastorePersistenceHandler.insertObject(DatastorePersistenceHandler.java:256)
at org.datanucleus.state.JDOStateManagerImpl.internalMakePersistent(JDOStateManagerImpl.java:3185)
at org.datanucleus.state.JDOStateManagerImpl.flush(JDOStateManagerImpl.java:4513)
at org.datanucleus.state.JDOStateManagerImpl.getExternalObjectId(JDOStateManagerImpl.java:1334)
at org.datanucleus.state.JDOStateManagerImpl.getObjectId(JDOStateManagerImpl.java:1234)
at name.xxx.tips.db.User.jdoGetObjectId(User.java)
at org.datanucleus.jpa.JPAAdapter.getIdForObject(JPAAdapter.java:266)
at org.datanucleus.ObjectManagerImpl.exists(ObjectManagerImpl.java:1953)
at org.datanucleus.jpa.EntityManagerImpl.refresh(EntityManagerImpl.java:469)
Why are you using JDO annotations if using JPA ?
The annotation to use for extensions with JPA is
org.datanucleus.api.jpa.annotations.Extension
as shown here
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.datanucleus.api.jpa.annotations.Extension;
#Entity
public class ChildEntity {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Extension(vendorName="datanucleus", key="gae.encoded-pk", value="true")
private String Id;
This works for me.

Google App Engine - Adding a record only if it doesn't exist yet

In Google App Engine, consider the following datastore model:
class Update(db.Model):
content = db.TextProperty()
date = db.DateTimeProperty()
source = db.StringProperty()
To add a new record, I do something like:
db.put(Update(content=..., date=..., source=...))
How can I add a record to the datastore only if it doesn't exist yet? What is the most efficient way to do this?
db.Model.get_or_insert(key_name) lets you pass the key name of the object to get or insert (think of it like a primary key)
More information about key_name

Resources