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;
}
}
Related
Consider the following setup.
Space.java
class Space {
Id id;
ParkingCampus campus;
}
class ParkingCampus {
Id id;
String country;
}
This is not the exact structure of my project but it is close enough for what I am trying to understand.
How would I be able to run a query on my 'Space' object which only returns instances where the child class 'ParkingCampus' has the String 'country' set to a specific value, eg: "UK".
I was thinking something like:
sessionFactory.getCurrentSession()
.createCriteria(String.class)
.add(Restrictions.eq("country", "UK"))
.list();
But i'm not sure if that would compile correctly. So does Hibernate by default do a 'deep' search in an attempt to map results to my restriction criteria or do I need to do something else to specify the query to work in this way?
Any help would be greatly appreciated!
Use Space as the base criteria, create an alias for the parking campus, and add a restriction on the alias' child country to UK.
However, keep in mind that your implementation seems a bit off, IMO. There should be a table with a compound key of parkingCampusId and spaceId, rather than the Space owning the id.
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Space.class, "space");
criteria.createAlias("space.parkingCampus", "campus");
criteria.add(Restrictions.eq("campus.country", "UK");
I would like to use #Version for optimistic concurrency control with JPA & Hibernate.
I know how it works in the typical scenario of two parallel transactions. I also know that if I have a CRUD with 1:1 mapping between the form and entity, I can just pass version along as a hidden field and use this to prevent concurrent modifications by users.
What about more interesting cases, which use DTOs or change command patterns? Is it possible to use #Version in this scenario as well, and how?
Let me give you an example.
#Entity
public class MyEntity {
#Id private int id;
#Version private int version;
private String someField;
private String someOtherField;
// ...
}
Now let's say two users open the GUI for this, make some modifications and save changes (not at the same time, so the transactions don't overlap).
If I pass the entire entity around, the second transaction will fail:
#Transactional
public void updateMyEntity(MyEntity newState) {
entityManager.merge(newState);
}
That's good, but I don't like the idea of passing entities everywhere and sometimes would use DTOs, change commands etc.
For simplicity change command is a map, eventually used in a call like this on some service:
#Transactional
public void updateMyEntity(int entityId, int version, Map<String, Object> changes) {
MyEntity instance = loadEntity(entityId);
for(String field : changes.keySey()) {
setWithReflection(instance, field, changes.get(field));
}
// version is unused - can I use it somehow?
}
Obviously, if two users open my GUI, both make a change, and execute it one after another, in this case both changes will be applied, and the last one will "win". I would like this scenario to detect concurrent modification as well (the second user should get an exception).
How can I achieve it?
If I understand your question correctly, all you need is a setter for your private int version field and when you update the entity, you set it in your entity. Of course your DTO must always transport version data. Eventually, you would do also something like:
MyEntity instance = loadEntity(entityId);
entityManager.detach(instance);
for(String field : changes.keySey()) {
setWithReflection(instance, field, changes.get(field));
}
//set also the version field, if the loop above does not set it
entityManager.merge(instance);
I would like in HQL to use the result of a abstract method in my "where" clause. Can this be done?
Something like this:
#NamedQuery(name="getMailRelations", query="Select mr from MailRelation mr where mr.getOccurrences() > 5"
I have a mapped super class something like this
#Entity
#Table(name="Mail_Entity", schema="relations")
#Inheritance(strategy=InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="relationType", discriminatorType=DiscriminatorType.STRING)
#PersistenceContext(name="domas")
public abstract class MailRelation {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
#ManyToOne(cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST})
#JoinColumn(name="mailId", referencedColumnName="mailId", nullable=false)
private Mail mail;
public void setMail(Mail mail) {
this.mail = mail;
if(!mail.getMailRelations().contains(this))
mail.addMailRelation(this);
}
public abstract int getOccurrences();
public Mail getMail() {
return mail;
// and more code......
No, that is impossible. The HQL code is translated into SQL and executed on the database. Generally Java methods can't be translated into SQL, and the database does not have any access to your Java code.
If you have a problem like this, there are for example these three possibilities to handle it. None of these possibilities is perfect.
1) You write the logic of the method in HQL (or SQL) using WHERE, GROUP BY and HAVING. In your example the getOccurrences() method seems to return a number of rows, which perhaps can be handled by `HAVING COUNT(...) > 5'.
2) You use database stored procedures. These are p. ex. procedures written in PL/SQL (in the case of Oracle). They can be accessed in select statements. But you loose the independency of the chosen database.
3) You load more rows than necessary and filter later in your Java code.
The solution is up to you, but I'm adding some additional options you can consider:
If you manage to precalculate the hash in all cases, use a parametrized named query:
#NamedQuery(name="getMailRelations", query="Select mr from MailRelation mr where :occurrences > 5"
then, you can call the query and add the parameter "occurrences":
String precalculatedHash = //your code here.
entityManager.createNamedQuery("getMailRelations",MailRelation.class).setParameter("occurrences", precalculatedHash).getResultList();
Another option is to go a little deeper with your hash logic, and determine what do you want to achieve with it. With that in mind you can use Criteria API to create a query and add all the restrictions represented by that hash. This can be a little tricky, so discard this option if the hash proves to be too context-depending (and I mean if it relies a lot on what do you have persisted, and the context of your application).
The third option is to bring all the results (or the smallest set of results possible, through either parameters or, again, Criteria API), and make your particular filtering logic.
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
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.