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.
Related
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
I am using GAE with Objectify and have entities as below:
#Entity
class LevelOne {
#Id
Long id;
#Index
#Load
Ref<LevelTwo> two;
}
#Entity
class LevelTwo {
#Id
Long id;
#Index
List<Ref<LevelThree>> threes;
}
#Entity
class LevelThree {
#Id
Long id;
}
I want to find all LevelOnes that have a LevelTwo which contains a LevelThree
I use the query :
ofy().load().type(LevelOne.class).filter("two.threes", keyOfThree).list();
But I get no results. I get from the documentation on wiki that I should be expecting results if I don't use Refs and Embed the complete entities, but the redundancy would get scary!
Google App Engine's datastore does not perform joins. Ref<?>s are key references to foreign entities. You can't filter across references.
You can, however, create a synthetic index field in your LevelOne object and fill it (perhaps in an #OnSave method) with whatever data you wish - including data in other entities. However, as with denormalization in general, you'll have to be careful about how data is updated.
Is it obligatory to specify all the propertis of a attribute like this
#Column(name = "ID_COMPANY", unique = true, nullable = false)
or make just :
#Column(name = "ID_COMPANY")
and for a string we have to specify a length ?
#Column(name = "NAME", length = 30)
or just :
#Column(name = "NAME")
Because if i change the length of varchar in my database i have to change it again at my mapping class and it's little hard if i have many changes.
No, it's not obligatory.
Most of these options other than name are used only if you use Hibernate to generate your database schema. If you maintain your schema manually, you can safely omit them.
However, some of them (such as nullable or unique) may be useful for documentation purposes.
All the elements of the #Column annotation have default values. Unless your schema goes against the defaults in nullability, uniqueness, length, etc. (or your DB column does not exactly match the name of your field name), you can leave them off the annotation to prevent clutter.
Defaults can be seen on the JavaDoc here: http://docs.oracle.com/javaee/7/api/javax/persistence/Column.html
I want to use UUIDs as primary due to the fact that those primaries are globally unique which makes it (for example) easy to integrate data from a production environment into a running debug environment.
Regarding to the following article: http://iops.io/blog/storing-billions-uuid-fields-mysql-innodb SELECT/INSERT of millions of records into a table using a UUID decoded as BINARY(16) is significantly faster than using simple CHAR(36).
Now, using Hibernate #GenericGenerator annotation, I could use this native UUID generator for a primary key using UUIDs:
#Id
#GeneratedValue(generator = "system-uuid")
#GenericGenerator(name = "system-uuid", strategy = "uuid")
private String id;
On the other hand I could define a binary UUID as primary as follows:
#Id
#Getter
#Column(columnDefinition = "BINARY(16)", length = 16, updatable=false, nullable=false)
private byte[] id;
... and use #PrePersist to generate new UUIDs
#PrePersist
private void prePersist() {
if (this.id == null) {
this.generateUUID();
}
}
The problem with this solution is the representation as binary for filters within (native/named) queries:
SELECT * from object o WHERE o.id=:id
What I would really need is the ability store the UUID field as above-mentioned as BINARY within the database while representing the value as simple UUID-String.
Is there any way to do that? Is there any alternative?
Why don't you just use the special uuid type for the column?
#Type(type = "pg-uuid")
But I also have the problem with native queries when doing like that.
I have a Spring application which uses JPA (Hibernate) initially created with Spring Roo. I need to store Strings with arbitrary length, so for that reason I've annotated the field with #Lob:
public class MyEntity{
#NotNull
#Size(min = 2)
#Lob
private String message;
...
}
The application works ok in localhost but I've deployed it to an external server and it a problem with encoding has appeared. For that reason I'd like to check if the data stored in the PostgreSQL database is ok or not. The application creates/updates the tables automatically. And for that field (message) it has created a column of type:
text NOT NULL
The problem is that after storing data if I browse the table or just do a SELECT of that column I can't see the text but numbers. Those numbers seems to be identifiers to "somewhere" where that information is stored.
Can anyone tell me exactly what are these identifiers and if there is any way of being able to see the stored data in a #Lob columm from a pgAdmin or a select clause?
Is there any better way to store Strings of arbitrary length in JPA?
Thanks.
I would recommend skipping the '#Lob' annotation and use columnDefinition like this:
#Column(columnDefinition="TEXT")
see if that helps viewing the data while browsing the database itself.
Use the #LOB definition, it is correct. The table is storing an OID to the catalogs -> postegreSQL-> tables -> pg_largeobject table.
The binary data is stored here efficiently and JPA will correctly get the data out and store it for you with this as an implementation detail.
Old question, but here is what I found when I encountered this:
http://www.solewing.org/blog/2015/08/hibernate-postgresql-and-lob-string/
Relevant parts below.
#Entity
#Table(name = "note")
#Access(AccessType.FIELD)
class NoteEntity {
#Id
private Long id;
#Lob
#Column(name = "note_text")
private String noteText;
public NoteEntity() { }
public NoteEntity(String noteText) { this.noteText = noteText }
}
The Hibernate PostgreSQL9Dialect stores #Lob String attribute values by explicitly creating a large object instance, and then storing the UID of the object in the column associated with attribute.
Obviously, the text of our notes isn’t really in the column. So where is it? The answer is that Hibernate explicitly created a large object for each note, and stored the UID of the object in the column. If we use some PostgreSQL large object functions, we can retrieve the text itself.
Use this to query:
SELECT id,
convert_from(loread(
lo_open(note_text::int, x'40000'::int), x'40000'::int), 'UTF-8')
AS note_text
FROM note