Does Endpoints (Java) require a persistable class to have an id field?
Before endpoints, my JDO model itself did not have an id (primary key) field. Datastore has its own id field, and it generated a value upon inserting a new record. The model works, and I could insert records (with datastore successfully inserting and generating an id value).
I converted it to Endpoints (using Google Plugin for Eclipse), and made slight adjustments. The generated code is referencing an id that's not in the model. So I switched the parameter to another unique identifier (email address).
It compiles and deploys. But when I run API explorer, I can't insert. I'm getting "The class [class name] is not persistable."
But when I put an id field as primary key, now my inserts are asking for a value in id (which is not ideal for my situation).
Does endpoints require a class to have an id (unique identifier)? If so, is there a way to make appengine/datastore generate it for me? Thanks!
My assumption is yes, all such persistable classes need an id field. I add mine via Objetify with #Id. Here is the relevant documentation, also about autogenerating ids:
Entities must have have one field annotated with #Id. The actual
name of the field is irrelevant and can be renamed at any time, even
after data is persisted. This value (along with the kind 'Car')
becomes part of the Key which identifies an entity.
The #Id field can be of type Long, long, or String. If you use
Long and save an entity with a null id, a numeric value will be
generated for you using the standard GAE allocator for this kind. If
you use String or the primitive long type, values will never be
autogenerated.
Related
In the description of the delete method in org.springframework.data.repository,CrudRepository interface it is written only that it deletes a given entity and that it accepts entity object itself.
It specifies nothing about entity's id needing to be unique.
However, this method works only when entity has an unique id. If the table may have multiple rows with the same id, this method fails when entity whose id is not unique is attempted to be deleted (at least in my case).
Now I understand that it is a very bad thing that an id is not unique in the table, but, in theory, it should work since this method accepts the entire entity as a parameter, and every entity (when all its columns are combined) in my table is unique. There are no two identical rows in a table since table has an unique constraint on a combination of all its columns.
Sure, there are other methods, like deleteById which would fail since they only accept id as a parameter and not the whole entity and since id is not unique, Spring does not know which entity to delete. Sure.
But why delete method fails when it should be able to distinguish between entities with the same id since it accepts the whole entitiy as a parameter (thus giving it access to all other columns of the entity and not just the id column)?
The requirement for the JPA id is that it is a primary key i.e. uniquely identifies the row. If you do not follow this, bad things will happen. You can have a composite primary key though, as it seems your row is identified by multiple columns. Look into #Embeddable/#EmbeddedId mappings for this purpose.
I'm designing an application in which I hope to use projection queries to retrieve Entity objects from the App Engine Datastore to save on latency and cost. I have two questions about this:
1) If one calls the Entity.getProperty(String propertyName) method on a returned Entity where propertyName does not correspond to one of the properties selected for by the Projection, will the return value be null or will Java throw an exception? The Entity documentation doesn't indicate what happens if propertyName does not exist. A corollary, do the not-selected-for properties no longer exist in the returned Entity or do they simply have no or null values assigned to them?
2) Is the Key of the truncated Entity that is returned the same as the Key of the original full Entity that's actually in the datastore? From what I understand, the Key is a hash of the kind, name/id property, and ancestor path of an Entity. Name/id also appears to be a property, so if one doesn't select for it, does the Key of the returned Entity differ from that of the actual Entity?
These questions seem like they would be fairly easy to answer with some testing once I'm up and running, but I'm new to App Engine and am still just designing my project, so I won't be in a position to do so for a while. Was hoping someone out there already knows the answer.
If a property does not exist in an entity, .getPropery() returns null. No exception is thrown.
If a property is not named in a projection query, the retrieved entity does not have this property even if the full entity does.
The key of an entity returned in a projection query is the same as in any other query. The key is created when an entity is first inserted in the datastore, and it does not change after that.
A little explanation. When you insert a new entity in the datastore, the datastore creates an entity and, separately, creates an entry for each indexed property, or a combination of properties (custom index), in a respective index. Projection query is just another combination of indexed properties. It retrieves all the data it needs directly from its own index without retrieving the entity itself.
I have an Entity type say URLInfo which keeps info about URLs. The primary key of this entity is URL itself ( that makes sure that I always have unique URLs in the datastore). I also want unique integer id for each url so that sharing the id becomes easier. Though, I can use GUIDs, but that is not a preferred thing for me. How can I achieve this requirement? Integer Ids need not be sequential ( preferred, if they are). Entities can be generated at a faster rate (that means I can't keep a common counter to update each time I generate a new URL record). This is what I have tried so far - In the URLInfo class, I defined a field - Long Id and annotate it with #Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) in the hope that it will get automatically generated with the unique value. But when I save the new entity (with id set as null), it saves the entity in the datastore but doesn't assign any value to this field.
I am trying all this on a local machine.
Thanks
Try this
#GeneratedValue(strategy=GenerationType.IDENTITY)
I am completely fresh to both JDO and GAE, and have been struggling to get my data layer to persist any code at all!
The issues I am facing may be very simple, but I just cant seem to find any a way no matter what solution I try.
Firstly the problem: (Slightly simplified, but still contains all the info necessary)
My data model is as such:
User:
(primary key)
String emailID
String firstName
Car:
(primary key)
User user
(primary key)
String registration
String model
This was the initial datamodel. I implemented a CarPK object to get a composite primary key of the User and the registration. However that ran into a variety of issues. (Which i will save for another time/question)
I then changed the design as such:
User: (Unchanged)
Car:
(primary key)
String fauxPK (here fauxPK = user.getEmailID() + SEP + registration)
User user
String registration
String model
This works fine for the user, and it can insert and retrieve user objects. However when i try to insert a Car Object, i get the following error:
"Cannot have a java.lang.String primary key and be a child object"
Found the following helpful link about it:
http://stackoverflow.com/questions/2063467/persist-list-of-objects
Went to the link suggested there, that explains how to create Keys, however they keep talking about "Entity Groups" and "Entity Group Parents". But I cant seem to find any articles or sites that explain what are "Entity Group"s or an "Entity Group Parents"
I could try fiddling around some more to figure out if i can store an object somehow, But I am running sort on patience and also would rather understand and implement than vice versa.
So i would appreciate any docs (even if its huge) that covers all these points, and preferably has some examples that go beyond the very basic data modeling.
And thanks for reading such a long post :)
I'm afraid you won't like the answer. GAE JDO has to be used a very specific way and is fraught with limitations that you have to observe to use it effectively. Read the docs forwards and backwards. For the issue you are seeing now, you probably need to read this section a couple of times:
http://code.google.com/appengine/docs/java/datastore/relationships.html
GAE JDO has owned and unowned relationships. See the documentation above for examples of owned vs unowned. I believe you want Car and User to have an unowned relationship. Note this revelation in the Google App Engine documentation about unowned relationships:
http://code.google.com/appengine/docs/java/datastore/relationships.html#Unowned_Relationships
In addition to owned relationships, the JDO API also provides a facility for managing unowned relationships. The App Engine implementation of JDO does not yet implement this facility, but don't worry, you can still manage these relationships using Key values in place of instances (or Collections of instances) of your model objects.
This essentially means, to use GAE JDO, you should not use a direct reference for an unowned relationship like between the Car and User classes. Rather, you should use indirect references between them, i.e. Car should have a field for the User's key rather than a direct reference to the User itself. Some of the trouble you are having is because GAE JDO cannot deal with how you are modeling this relationship in code.
Asker goes on to say:
Went to the link suggested there, that explains how to create Keys, however they keep talking about "Entity Groups" and "Entity Group Parents". But I cant seem to find any articles or sites that explain what are "Entity Group"s or an "Entity Group Parents"
Entity Group - a graph of objects that were initially persisted together. For example, because Car refers directly to a User, when you persist a given Car instance for the first time, then you would also persist the User instance to which it refers and this Car instance and this User instance would be part of the same entity group. If this User instance was already been persisted, either independently by itself or as part of another Car instance, then this User instance is already in another entity group. "Owned" relationships are supposed to be in the same entity group. Note that GAE JDO transactions can modify only 1 entity group - any more will raise an exception.
Entity Group Parent - a top-level/root ("parent") persisted class. In the above example, when you persist a given Car instance for the first time, you would also persist the User instance it refers to. The Car instance is the entity group parent. An "owned" "child" class like User embeds its parent's (Car's) key within its own (User) key. If you were to pull a Car instance from the database and then attempt to access the User that this Car refers to, then the GAE JDO will use the Car's key to find the corresponding User (because the target User's key has the parent Car's key embedded as part of its own key).
Asker got this error message:
"Cannot have a java.lang.String primary key and be a child object"
Note this statement in the docs:
The child class must have a key field whose type can contain the parent key information: either a Key, or a Key value encoded as a string. See Creating Data: Keys for information on key field types.
This means that "child" classes must use certain types of keys (i.e. keys that are capable of encapsulating their parent's key within the child's key). Long and String are suitable for entity group parents classes, i.e. non-child classes. However, "child" classes must use either Key or Key encoded as String type for their key. The error message indicates that the Car class refers to the User class as if it were an "owned" "child" class, and therefore the User class must use an key type appropriate for a child, but the User class is not using a key type appropriate for a child (non-encoded String).
The fix for the immediate problem at hand is to model Car and User to be an unowned relationship by changing Car from having the direct reference to User to instead having an indirect reference by storing the related User's key. The overall fix will likely include taking a hard look at how to fit your object model into GAE JDO's framework (once you wade through the docs to try to understand it). This will likely include having to manually manage some of the relationships between the classes.
If its any consolation, I'm dealing with the same sort of issues with GAE JDO myself (I even have a Car class too!).
Read http://code.google.com/appengine/docs/java/datastore/relationships.html
I have a class mapped as an Entity to persist it in a database. I have an id field as the primary key so every time the object is persisted the value of the id is retrieved from the sequence "myClass_pk_seq", a code like the following one.
#Entity
#Table(name="myObjects")
public class MyClass {
#Id
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator="sequence")
#SequenceGenerator(name="sequence", sequenceName="myClass_pk_seq", allocationSize=1)
#Column(name="myClassId")
private Integer id;
private Integer code;
...
}
I need to make in "code" attribute something similar to id. I need to have a sequence so I can assign to code the next value of the sequence (to reserve that value in case the user wants to reserve it but without persisting data). I mean the user will see the field, if he doesn't know what to enter he can push a button and receieve in the screen the next possible value (and he can or not accept it). How can I get the next value of a sequence defined in JPA (and increment its value) without persisting the data for a non primary key field?
I just want to have a method which call nextval on a sequence associated with "code" field, and returns the value. What's the best way to do it in JPA with annotations?
Thanks.
I just want to have a method which call nextval on a sequence associated with "code" field, and returns the value. What's the best way to do it in JPA with annotations?
Use native SQL to get the next sequence value when the user pushes the button. Either create the sequence manually or use a "fake entity" to have JPA create it for you.
If you don't want to use native SQL, insert an entity relying on the sequence and gets its id.
Both solutions sounds a bit ugly. Maybe you could simply use a random generator like a UUID generator.
Actually, you didn't mention anything about the uniqueness of the code (and the JPA annotations don't show it must be unique). Why don't you return a random int?
See another question/answers on the subject of using sequence defined elsewhere than id fields. You can create a fake entity with one field (of type Long id). Connect it to the sequence you defined in the DB. Then create a CrudRepository implementation for that entity and call its save() method with an empty instance of the fake entity object you defined. Hibernate will run for you a "select YOUR_SEQ.NEXTVAL from dual" query.