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.
Related
I have an entity ProjectEmployee which represents a ternary association. The composition of two of its fields Employee and Project has to be unique:
#Entity
#Data
#IdClass(ProjectEmployeeId.class)
public class ProjectEmployee {
#Id
#ManyToOne
private Project project;
#Id
#ManyToOne
private Employee employee;
#ManyToOne
private ProjectEmployeeRole projectEmployeeRole;
}
Im using REST and i would like to identify each resource with an unique identifier. I canĀ“t do it for ProjectEmployee, because this entity does not have one unique identifier. Whats the best solution for this? Do i always have to send two parameters to identify this resource like this?
GET:
../projectemployees/{proejctId}/{employeeId}
This would identify the resource, but is there any way to do it with just one identifier instead of two?
"REST" doesn't care what you use as an identifier, so long as it conforms to the production rules described by RFC 3986.
/cee03013-7761-465f-a71c-791450c8e785
Is a perfectly satisfactory URI.
Any information encoded into the URI is done by the origin server at its own discretion.
Any spelling that allows you, the server, to correctly associate the request with the intended resource and its representations, is fine.
I'm using OpenJPA to load comments from my database into comment objects. Comment objects also have categories, sources (string), and comment time fields. This works great with OpenJPA, and I like my Comment object to the Comment table, and all is right with the world.
For a summary view, I'm interested in doing a GROUP BY query on the categories and sources so that for each source, I can see a break down of how many comments are available.
SELECT source, category, count(category) FROM Comments GROUP BY source,category
Now, my idea was to create this query using the entity manager, and have it somehow use a CommentSummary object instead of the Comment object. I have no idea how to tell OpenJPA how to do this. It seems like all the examples of using the GROUP BY do not consider also getting the base objects themselves.
I tried creating a view called 'CommentSummary', but OpenJPA wanted to modify the table to add an id field - perhaps if I simply told it the source and category fields were the primary keys it would work. I'm just a little confused that this isn't addressed directly anywhere that I can understand maps to my problem.
Has anyone done this successfully? What should I be doing differently?
Assuming you have an object CommentSummary with constructor that takes parameters source, category and count, you might try with:
SELECT NEW x.y.z.CommentSummary(c.source, c.category, count(c.category)) FROM Comments c GROUP BY c.source, c.category
CommentSummary object:
package x.y.z;
public class CommentSummary {
private String source;
private String category;
private int categoryCount;
// attribute getters/setters
public CommentSummary(String source, String category, int count) {
this.source = source;
this.category = category;
this.count = count;
}
}
I am attempting to implement a Hibernate/JPA2 solution over an existing schema, which cannot be changed. Here is a minimal example of the existing schema:
CREATE TABLE REASON (
REASON_CODE CHAR(1),
REASON_DESCRIPTION CHAR(50))
CREATE TABLE HEADER (
REASON_CODE CHAR(1),
OTHERFIELD1 CHAR(40),
OTHERFIELD2 CHAR(40) )
Normally this would be the "correct" way from a DB perspective: Link REASON to HEADER by the REASON_CODE. However it's presenting me with an awkward problem in Java and I'm not sure of the best way to solve it. I've modeled these entities as follows:
#Entity
#Table(name="REASON")
public class Reason implements java.io.Serializable {
#Id
#Column(name="REASON_CODE", unique=true, nullable=false, length=1)
private Character reasonCode;
#Column(name="REASON_DESCRIPTION", nullable=false, length=25)
private String reasonDescription;
}
#Entity
#Table(name="HEADER")
public class Header implements java.io.Serializable {
#ManyToOne
#JoinColumn(name = "REASON_CODE", nullable = false)
private Reason reason;
#Column(name="OTHERFIELD1")
private String otherField1;
#Column(name="OTHERFIELD2")
private String otherField2;
}
Once again, as far as I can tell, this is "correct" from a Java perspective - linking Header to Reason with a reference.
The problem is that when I need to use one of these Reason values in my code I wind up with awkward syntax like:
Reason r = reasonService.findOne('X'); // X is the REASON_CODE in the database record
// Do some processing with variable r
Or this:
header.setReason(reasonService.findOne('X'));
Ideally I could implement Reason as an enum like:
public enum Reason {
X_MARKSTHESPOT("X"),
C_MEANSSOMETHINGELSE("C"),
F_MEANSATHIRDTHING("F") ;
private String code;
private Reason(String code) {
this.code = code;
}
}
And then simply have this in my code:
header.setReason(Reason.X_MARKSTHESPOT);
But from what I understand that is not possible with JPA, which offers only EnumType.STRING (basically the name) or EnumType.ORDINAL (even worse, the index in the enum list). A possible way around this would be JPA 2.1's Converter, but I have never used it. I have also read here (in one of the answers) that a Hibernate User Type might be useful. One of our programmers has solved this in another app by writing two complete classes - an enum class for internal use and a "shadow" class which iterates through the enum and syncs the records in the database on every startup. But this seems like a kludgey way to do it. What is the best way to handle this, bearing in mind that the database schema cannot be changed?
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)
What is appropriate way of creating objects with One-to-Many relationship using Objectify and RequestFactory? I've read documentation for these libraries, and also reviewed number of sample projects such as listwidget and gwtgae2011. All of them use #Embedded annotation which is not what I want because it stores everything within one entity. Another option according to documentation would be to use #Parent property in child classes. In my example (getters/setters removed for simplicity) I have entities Person and Organization which defined as
#Entity
public class Person extends DatastoreObject
{
private String name;
private String phoneNumber;
private String email;
#Parent private Key<Organization> organizationKey;
}
and
#Entity
public class Organization extends DatastoreObject
{
private String name;
private List<Person> contactPeople;
private String address;
}
Now if I understood documentation correctly in order to persist Organization with one Person I have to persist Organization first, then set organizationKey to ObjectifyService.factory().getKey(organization) for Person object and then persist it. I already don't like that I have to iterate through every child object manually but using RequestFactory makes everything is more convoluted due to presence of proxy classes. How would I define Organization and OrganizationProxy classes - with Key<> or without it ? Will I have to define something like this in Organization ?
public void setContactPeople(List<Person> contactPeople)
{
for (int i = 0; i < contactPeople.size(); ++i)
{
DAOBase dao = new DAOBase();
Key<Organization> key = dao.ofy().put(this);
contactPeople.get(i).setOrganizationKey(key);
}
this.contactPeople = contactPeople;
}
And how would I load Organization with its children from Datastore ? Will I have to manually fetch every Person and fill out Organization.contactPeople in #PostLoad method ?
It seems like I'll have to write A LOT of maintenance code just to do what JPA/JDO does behind the scene. I simply don't get it :(
Am I missing something or it's the only way to implement it ?
Thanks a lot for answers in advance!!!
You need to make it as #Parent only when you going to use it in transaction against all Person in this Organization. I'm sure it's not what you want.
It's enough to save just private Key<Organization> organizationKey, and filter by this field when you need to find Person for specified Organization
As about loading all referenced objects - yes, it is, you have to load it manually. It's pita, but it's not a lot of code.
Also, there is a different way to store this relationship, if your organization are small enough, and consists of few hundreds of people. At this case you can have List<Key<Person>> contactPeopleKey;, and load all this people by existing Key, manually, it much be much faster than loading by new Query