How to enforce unique field in Google Cloud Endpoints API (GAE) - java

I have a custom user object in my Google Cloud Endpoints API:
public class User {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id; // <- This is unique by default because of #PrimaryKey
#Persistent
private String username; // <- How to make this unique as well
...
}
What would be the best way of enforcing an arbitrary field to be unique? Should I just, in my insert method, query for a user with the given username to check if it already exists?
I have looked at answers given in older posts, but was wondering if anything has changed since then.

Related

H2 Database generation strategy is leaving gaps between id values

I'm working on a REST API using Spring. I have this class, which id's is being generated automatically:
#Entity
public class Seller implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private double tasa;
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getTasa() {
return tasa;
}
public void setTasa(double tasa) {
this.tasa = tasa;
}
}
I added some endpoints to create, delete and get a seller from the DB. So my problem arises when I delete one seller from the DB. When I try to create a new one, I was expecting to get the lower available value for the id but what is actually doing is using some kind of counter/sequence. Let me show you:
So in my second post instruction I was expecting a json with id = 1, instead I received a 2. I tried using TABLE and IDENTITY strategies but the unwanted behavior continued. So my question is: how can I achieve the behavior I desire? I don´t want gaps between my seller's ids.
In general the database are designed to be incremental. When the ID is generated, it is not generated based on the content of the tables. instead of it, the ID is generated using a sequence. In your example you have some records, but imagine a database with a lot of records. The database generates the IDs based on a Sequence (or similar), to avoid read the data, an expensive process.
If the ID is not relevant to the business, then this behavior doesn't affect your process. (Like the message's id in a chat).
If the ID is important, I recommend to redefine the delete process. you probably need to preserve all the ids, like a customer id.
If you want to preserve the sequence and allow delete records, the recommendation is to generate the id by yourself, but you need to lead with problems like concurrence
I tried using TABLE and IDENTITY strategies but the unwanted behavior continued.
This is not unwanted behaviour. Check
How primary keys are generated.
So my question is: how can I achieve the behavior I desire? I don´t want gaps between my seller's ids
One way to achieve this is to not use #GeneratedValue(strategy = GenerationType.AUTO) and set id manually from program and in there you can put any logic you want.
It's not recommended to set primary key manually. If you want you can use any other field like seller_code for this behaviour.
Another question here which is similar to this.

Override Spring data JPA id annotation.

I'm using Spring-data-Jpa where I've an entity
#Entity(name="person")
public class Person implements Serializable {
#javax.persistence.Id
private long dbId;
#Id
private final String id;
// others attributes removed
}
In above class I've two different ids id (marked with org.springframework.data.annotation.Id) and dbId(marked with javax.persistence.Id) , since my id field is always populated with a unique identifier (for Person class which I'm getting from somewhere else) so while using Spring JpaRepository it always tries to update the record and since it's not in db, nothing happens.
I've debug code and saw that it uses SimpleKeyValueRepository which gets the id field which is id, and thus it always gets a value and tries to update record, can I override this behavior to use dbId instead of id field? Is there any way to achieve same with some configuration or annotation, any help is greatly appreciated.
Each entity must have exactly one #Id. On the other hand, you might want to declare a column as unique. It can be done by:
#Entity(name="person")
public class Person implements Serializable {
#Id
private Long id;
#Column(unique = true)
private final String uuid;
// others attributes removed
}
Also remember, that Spring Data JPA id should be reference Long instead of a primitive as you want to save objects with id = null.
String id should probably be String uuid and be initialized as String uuid = UUID.randomUUID().toString();
Similar situation would be an unique email requirement for user. On one hand it'll be a primary key, but on the other, you won't mark it as #Id.
If you need further clarification or your environment is more complicated, just ask in comments section below.

Query two entities in Google App Engine JDO

Am new to google appengine and jdo. I do not know how to write a query in JDO with two entities. I have UserProfile and UserFeed entity like as below.
#PersistenceCapable
public class UserProfile {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private String firstName;
#Persistent
private String lastName;
#Persistent
private List<Key> friendProfileKeys;
}
#PersistenceCapable
public class UserFeed {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Key profileKey;
#Persistent
private String comment;
#Persistent
private UserFeedType userFeedType;//Friends,Public
}
Below query I used to get list of feeds that user posted.
final Query query = pm.newQuery(UserFeed.class);
final List v;
query.setFilter("profileKey == paramUserProfileKey");
query.declareParameters("com.google.appengine.api.datastore.Key paramUserProfileKey");
v = (List) query.execute(profile.getKey());
Please help me to get list of feeds that user and his friends posted and also public posts.
As #DataNucleus said in his comment, GAE Datastore doesn't support join queries, so I'm afraid it's impossible to retrieve all you want to retrieve in a single query...
As far as I understand you have 2 choices:
The 1st choice is to use several queries: one query asking for all the public posts, then other query like the one you wrote to get all the feeds of the user, other to get all his friends and lastly one query for each friend, asking for their posts...
The 2nd choice is to use owned relationships. This way you have to change your fields of type Key (the "foreign keys", not the primary ones!) and use fields of the actual classes. For example, you should have a field like this:
#Persistent
private List<UserProfile> friendProfiles;
and
#Persistent
private UserProfile profile;
This way, as said also in the GAE/J documentation, when you retrieve for example an UserFeed, you can easily get the associated User just using:
retrievedUserFeed.getProfile();
and you could also access the friends of the writer of a retrieved feed by:
retrievedUserFeed.getProfile().getFriendProfiles();
These owned relationship have a behaviour that I can't really explain you in detail (see previous link), but basically when you retrieve an entity that has an owned relationship with other entity, if you don't touch the correspondent field, the related entity is never retrieved. In the previous example, if you retrieve a UserFeed but you never use the method getProfile() the UserProfile is never loaded in memory, thus saving resources...
By the way, if you use this method, I strongly suggest you to have a relationship from UserProfile to UserFeed such as:
#Persistent
private List<UserFeed> ownedFeeds;
Because you will want to navigate from UserProfile to UserFeed and not only the opposite way... (Note: this is a design issue independent of GAE and JDO and whatever implementation)

difference of owned one-to-many relationship between GAE/J low level datastore API and DataNucleus JDO

When creating an owned one-to-many relationship, in Java, I noticed that there is a difference in the resulting record between using the low level Datastore API and DataNucleus JDO. Not sure if this is intentional or any way to fix it.
For example,
If there are multiple addresses for an employee in the following link:
https://developers.google.com/appengine/docs/java/datastore/entities#Ancestor_Paths
Using the low level datastore api as following, the employee record doesn't show an address column(i.e. property):
Entity employee = new Entity("Employee");
datastore.put(employee);
Entity address_home = new Entity("Address", employee.getKey());
datastore.put(address_home);
Entity address_mailing = new Entity("Address", employee.getKey());
datastore.put(address_mailing);
Using JDO, the employee record shows an address column(i.e. property):
#PersistenceCapable
public class Employee {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent(mappedBy = "employee")
private List<Address> addresses;
List<Address> getAddresses() {
return addresses;
}
void setAddresses(List<Address> addresses) {
this.addresses = addresses;
}
// ...
}
#PersistenceCapable
public class Address {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private Employee employee;
#Persistent
private String Street;
...
}
The extra property is harmless. However why is this necessory for JDO?
I'm using GAE/J 1.7.2 with DataNucleus v2 on dev server.
Latest storage version of the GAE JDO plugin will store all relations in an object as a property, hence the Employee class will have a property for the addresses it stores. This is a much more logical way of storing things than how GAE JDO used to store things (it originally tried to simulate foreign keys, using the ownership of the other side). Storing the List in the owner has advantages for loading the elements into the collection, as well as allowing an element to be present in a List more than once (whereas with older storage versions that would be impossible).
All version of GAE JDO upto and including 2.1.1 store the index position in each Address that is in the List, whereas really they need not be stored now since the "addresses" property in Employee provides that - this is left over from the early versions which needed it stored in that way. Version 2.1.2 onwards don't add that list index property to the element.

Implementing tagging in JDO

I am implementing a tagging system for a website that uses JDO .
I would like to use this method.
However I am new to relationships in JDO.
To keep it simple, what I have looks like this:
#PersistentCapable
class Post {
#Persistent String title;
#Persistent String body;
}
#PersistentCapable
class Tag {
#Persistent String name;
}
What kind of JDO relationships do I need and how to implement them? I want to be able to list all Tags that belong to a Post, and also be able to list all Posts that have a given Tag. So in the end I would like to have something like this:
Table: Post
Columns: PostID, Title, Body
Table: Tag
Columns: TagID, name
Table: PostTag
Columns: PostID, TagID
You should look at: http://code.google.com/appengine/docs/java/datastore/relationships.html#Unowned_Relationships
Basically you create a Class PostTag which appart from it's primary key also has two Key fields for each of the relationships:
#PersistentCapable
class PostTag {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
/*you should add this to Post and Tag as well,
since this is what the fields in PostTag will reference
you can rename them to ClassnameID if you like, I believe*/
#Persistent
private Key post;
#Persistent
private Key tag;
}
Then when you create PostTag you should do something like this
PostTag pt = new PostTag();
pt.setPost(post.getKey());
pt.setTag(tag.getKey());
// persist pt here;
I used getters/setters here, since you usually set the fields to private and access them through accessor methods, but that's your call; also 'post' and 'tag' in the above snippet are supposed to be the already persisted objects that you want to link.
Edit: you should probably also take a look at: http://code.google.com/appengine/docs/java/datastore/usingjdo.html#Unsupported_Features_of_JDO since app engine only partially implements JDO (I believe it's because of the different way the datastore works, compared to traditional databases). They may add support for missing features in future though.
You want a many-to-many relationship, which JDO supports. However, App Engine doesn't fully support JDO, so I don't know if this is possible.

Categories