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)
Related
I'm trying to do my first JEE application with rest api and hibernate. I dont know how to do it in proper way. I mean that I have entity User
#Entity
#XmlRootElement
public class User {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long id;
private String username;
private String password;
private String email;
private LocalDateTime lastDateOfLogin;
#OneToMany(fetch=FetchType.LAZY)
private List<Post> posts = new ArrayList<>();
#OneToMany(fetch=FetchType.LAZY)
private List<Comment> comments = new ArrayList<>();
#OneToMany(fetch=FetchType.LAZY)
private List<Like> likes = new ArrayList<>();
#OneToMany(fetch=FetchType.LAZY)
private List<User> followers = new ArrayList<>();
#OneToMany(fetch=FetchType.LAZY)
private List<User> following = new ArrayList<>();
and I have UserResource method to get one user
#GET
#Path("{id}")
public User getUser(#PathParam("id") long id)
{
return userService.getOne(id);
}
Now my problem is that when I'm trying to get one user I'm getting exception org.hibernate.LazyInitializationException - of course I know why but question is how to do this get it in proper way. In this #GET I don't need this OneToMany collections because when I want E.g user posts I will call user/1/posts url and I will receive all user posts.
How to develop this kind of applications? Should I delete relations from user entity and just search in database posts of user when I need them? Or maybe there is another solution for it?
If that particular endpoint is only interested in the basic details about the user and none of the associations your database model has to other objects in your system, you need to somehow prevent the serialization process from looking at those attributes.
If it is a field that you want to always be ignored, you could annotate it with #XmlTransient, but this is a decision that is determined at build time and cannot be modified at runtime. For situations where you need to dynamically influence the serialization step, you can either look at these two articles:
How to Conditionally serialize with JAXB or Jackson
Jacksons JsonView or MOXy's external mapping-files
Another alternative would be to modify your service to return a class instance for that specific view that only contains the attributes you want to be marshalled into the output XML. This can easily be accomplished with a JPA select new query like:
SELECT new com.company.app.BasicUser(u.userName, other attributes) FROM User u
WHERE u.id = :id
Now your XML marshalling would be based on BasicUser and not your domain entity User, where that BasicUser doesn't have any of the associations or attributes that you don't wish to have serialized for that specific view.
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.
I'm trying to use Hibernate Search on two Entities, that do not (and must not) share a relation on object-level, however they're connected by a join table that uses their IDs. (legacy)
These are more or less the two Entities:
#Entity
#Indexed
class Person {
#Id
private long id;
#Field
private String name;
....
}
#Entity
#Indexed
class Address {
#Id
private long id;
#Field
private String street;
#Field
private String zip;
....
}
They are connected by their IDs:
#Entity
class Relation {
#Id
private long id;
private long personId;
private long addressId;
}
The goal I'm trying to achieve is finding similar persons that share a similar address via Hibernate Search. This means I'm searching for attributes from both Person and Address.
I guess the easiest way is to "emulate" an #IndexedEmbedded relation which means denormalizing the data and add "street" and "zip" from Address to a Person document. I stumbled upon Hibernate Search Programmatic API, but I'm not sure if that's the right way to go (and how to go on from to there)..
Would this be the proper way of doing things or am I missing something?
If you cannot add this relationship into the model, you will be pretty much out of luck. You are right that you would have to index the Person and corresponding Address data into the same document (this is what #IndexedEmbedded does really). The normal/best way to customize the Document is via a custom (class) bridge. The problem in your case, however, is that you would need access to the current Hibernate Session within the implementation of the custom bridge.
Unless you are using some approach where this Session for example is bound to a ThreadLocal, there won't be a way for you to load the matching Address data for a given Person within the bridge implementation.
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.
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.