Objectify Ref in a subclass - java

I'm trying to get a list picking by Reference.
My classes are like:
A License run on a Daemon,
A License can be a LicenseCountryCondition or another subclass with a Ref (for LicenseCountryCondition, the parameter is a Ref of a Country).
License:
#Entity
#Cache
#Index
public class License {
#Id
Long id;
private String name;
private String startDate;
private String expDate;
private int timeStamp;
private int status;
Ref<Daemon> daemon;
private boolean inactive;
}
LicenseCountryCondition :
#Index
#Subclass(index=true)
public class LicenseCountryCondition extends License{
Ref<Country> country;
}
If I want to find a list of the LicenseCountryCondition working on a specific Daemon, I do this:
Daemon dae=ofy().load().type(Daemon.class).filter("name", "example").first().now();
List<LicenseCountryCondition>test=ofy().load().type(LicenseCountryCondition.class).filter("daemon",dae).list();
for(LicenseCountryCondition i:test){
System.out.println(i.getName());
System.out.println(i.getDaemon().getName());
}
And I got the good results.
But, when I try to get a list of LicenseCountryCondition working on a specific Country, it doesn't work:
Country ctr=ofy().load().type(Country.class).filter("name", "France").first().now();
List<LicenseCountryCondition> test=ofy().load().type(LicenseCountryCondition.class).filter("country",ctr).list();
for(LicenseCountryCondition i:test){
System.out.println(i.getName());
}
Can I get this list? (I saw this but it's not the same problem)
Thanks for your attention.

Make sure your query for France actually returns a real country (not null).
There's nothing obviously wrong in what you have written, but there's too much stuff going on here and too much unspecified database state for someone to be able to answer the question. The best thing to do is put together a test case that creates some entities (so the db state is known) and then demonstrates queries that you think should succeed but nevertheless fail.

Related

GAE Endpoints (Java) with objectify - how to model partial data (for client)?

I have the following entities:
#Entity
public class Person {
#Id public Long id;
public String name;
public Ref<Picture> picture;
public String email;
public byte age;
public short birthday; // day of year
public String school;
public String very_long_life_story;
... some extra fields ...
}
#Entity
public class Place {
#Id public Long id;
public String name;
public String comment;
public long createdDateMS;
public long visitors;
#Load public List<Ref<Person>> owners;
}
Few notes:
(A) Maximum size of owners, in Place entity, is 4 (~)
(B) The person class is presumable very big, and when querying place, I would like to only show a subset of the person data. This optimizations is aimed both at server-client and server-database communications. Since objectify (gae actually) only load/save entire entities, I would like to do the following:
#Entity
pubilc class PersonShort {
#Id public Long id;
public Ref<Picture> picture;
public String name;
}
and inside Place, I would like to have (instead of owners):
#Load public List<PersonShort> owners;
(C) The problem with this approach, is that now I have a duplication inside the datastore.
Although this isn't such a bad thing, the real problem is when a Person will try to save a new picture, or change name; I will not only have to update it in his Person class,
but also search for every Place that has a PersonShort with same id, and update that.
(D) So the question is, is there any solution? Or am I simply forced to select between the options?
(1) Loading multiple Person class, which are big, when all I need is some really small information about it.
(2) Data duplication with many writes
If so, which one is better (Currently, I believe it's 1)?
EDIT
What about loading the entire class (1), but sending only part of it?
#Entity
public class Person {
#Id public Long id;
public String name;
public Ref<Picture> picture;
public String email;
public byte age;
public short birthday; // day of year
public String school;
public String very_long_life_story;
... some extra fields ...
}
public class PersonShort {
public long id;
public String name;
}
#Entity
public class Place {
#Id public Long id;
public String name;
public String comment;
public long createdDateMS;
public long visitors;
// Ignore saving to datastore
#Ignore
public List<PersonShort> owners;
// Do not serialize when sending to client
#ApiResourceProperty(ignored = AnnotationBoolean.TRUE)
#Load public List<Ref<Person>> ownersRef;
#OnLoad private void loadOwners() {
owners = new List<PersonShort>();
for (Ref<Person> r : ownersRef) {
owners.add(nwe PersonShort(r.get()));
}
}
}
It sounds like you are optimizing prematurely. Do you know you have a performance issue?
Unless you're talking about hundreds of K, don't worry about the size of your Person object in advance. There is no practical value in hiding a few extra fields unless the size is severe - and in that case, you should extract the big fields into some sort of meaningful entity (PersonPicture or whatnot).
No definite answer, but some suggestions to look at:
Lifecycle callbacks.
When you put your Person entity, you can have an #OnSave handler to automatically store your new PersonShort entity. This has the advantage of being transparent to the caller, but obviously you are still dealing with 2 entity writes instead of 1.
You may also find you are having to fetch two entities too; initially you may fetch the PersonShort and then later need some of the detail in the corresponding Person. Remember Objectify's caching can reduce your trips to Datastore: it's arguably better to have a bigger, cached, entity than two separate entities (meaning two RPCs).
Store your core properties (the ones in PersonShort) as separate properties in your Person class and then have the extended properties as a single JSON string which you can deserialize with Gson.
This has the advantage that you are not duplicating properties, but the disadvantage is that anything you want to be able to search on cannot be in the JSON blob.
Projection Queries. You can tell Datastore to return only certain properties from your entities. The problem with this method is that you can only return indexed properties, so you will probably find you need too many indexes for this to be viable.
Also, use #Load annotations with care. For example, in your Place class, think whether you really need all those owners' Person details when you fetch the owners. Perhaps you only need one of them? i.e., instead of getting a Place and 4 Persons every time you fetch a Place, maybe you are better off just loading the required Person(s) when you need them? (It will depend on your application.)
It is a good practice to return a different entity to your client than the one you get from your database. So you could create a ShortPerson or something that is only used as a return object in your REST endpoints. It will accept a Person in its constructor and fill in the properties you want to return to the client from this more complete object.
The advantage of this approach is actually less about optimization and more that your server models will change over time, but that change can be completely independent of your API. Also, you choose which data is publicly accessible, which is what you are trying to do.
As for the optimization between db and server, I wouldn't worry about it until it is an issue.

Orika polymorphic mapping

I have the following entities:
public class Activity
{
private Long activityId;
private String name;
private Long year;
}
public class Course extends Activity
{
private Long duration;
private Date startDate;
private Date endDate;
....
}
public class Conference extends Activity
{
private Date dueDate;
private Person speaker;
....
}
I have modeled this in my database as one Activity table with all attrbitues for child entities, and then mapped them on Hibernate using single-table strategy.
I want to retrieve all Activities for a given year. I know how to do that on the data access layer through Hibernate, my problem comes with mapping those polymorphic objects (some of them are courses and some of them are conferences) using Orika mapper: I always end up with Activity objects without each concrete entity's attributes.
More specifically, I've got a fourth class, let's call it A, which has a list of Activity elements which may be of Course or Conference class, and I would like to map it like this:
ADTO adto = map(A, ADTO.class);
I haven't found any info on this issue on the internet...
Orika support polymorphic mapping and within collection also
Please take a look at this PolicyElementsTestCase
There is lot of use cases within test code of Orika, you can refer to that. Hope this can help you.

How to make a java class related to another class with Neo4j?

I have a class House and a class Room. Each of these classes are a NodeEntity and are persisted in separate repositories, HouseRepository and RoomRepository. House contains a Set<Room>. I want to be able to delete a Room instance and automatically have that instance removed from the Set<Room> inside of the House class. Since Neo4j is a graph database, I figured that I should be able to declare a relationship between the House and each Room and deleting a Room instance will take care of this automatically. The two following classes represent House and Room.
#NodeEntity
public class House {
#GraphId
private Long id;
#Indexed(unique=true) String uid;
#RelatedTo (type="addition", direction=Direction.OUTGOING)
#Fetch
private Set<Room> rooms;
public House(String uid, Set<Room> rooms) {
this.uid = uid;
this.rooms = rooms;
}
public House() {
this.uid = //random uid;
}
}
#NodeEntity
public class Room {
#GraphId
private Long id;
#Indexed(unique=true) String uid;
public Room(String uid) {
this.uid = uid;
}
public Room() {
this.uid = //random uid;
}
}
I am thinking that I should be able to write a Cypher query in the RoomRepository that would take care of this, but I am not sure. I have thought of something like this:
public interface RoomRepository extends BaseRepository<Room>{
#Query("start room=node({0}) " +
"match house-[:addition*]->room" +
"delete room")
public void deleteRoomAndRemoveRoomFromHouse(String uid);
}
What is the recommended way to handle these types of deletes?
Your approach should almost work. You may bump up against an exception because you try to delete a node without first having deleted its relationship. (Unless SDN magic takes care of that for you, but I don't think it intercepts cypher queries.)
As your MATCH clause stands, it will act as a filter, meaning that whatever is bound to the room identifier in your start clause is only retained by the time you reach the delete clause if it has the relevant relationship of at least depth 1. If the room you pass as a parameter does not have at least one incoming [:addition] relationship, it is no longer bound and won't be deleted. Perhaps this is intentional, if so keep it, but add (otherwise replace it with) a match clause that binds all the rooms relationships and deletes them before you delete the room. Try something like
START room=node({0})
MATCH room-[r]-()
DELETE r, room
But I think either the repository or Neo4jTemplate should have plenty of voodoo to take care of this kind of operation for you. Or if you use the advanced mapping with AspectJ, you may have all kinds of chocolate chips baked into your room entity. I know there is a NodeEntity#persist(), I think there is a NodeEntity#remove() as well.
Once the node is deleted, it won't show up in the Set<Room> field of your room class. (If you use simple mapping you may have to retrieve it or sync it manually to the database, possibly a Neo4jTemplate#fetch(), passing the Set<Room> field, will do that for you.)

How to store created/lastUpdate fields in AppEngine DataStore using Java JDO 3?

Abstract
I have a working application in Appengine using Java and JDO 3.
I found these arguments (auto_now and auto_now_add) which correspond exactly what I want to implement in Java. So essentially the question is: How to convert AppEngine's Python DateTimeProperty to Java JDO?
Constraints
Converting my application to Python is not an option.
Adding two Date properties and manually populating these values whenever a create/update happens is not an option.
I'm looking for a solution which corresponds to what JDO/Appengine/Database authors had in mind for this scenario when they created the APIs.
It would be preferable to have a generic option: say I have 4 entities in classes: C1, C2, C3, C4 and the solution is to add a base class C0, which all 4 entities would extend, so the 4 entities don't even know they're being "audited".
[update] I tried (using a simple entity)
#PersistenceCapable public class MyEntity {
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY, primaryKey = "true")
private Long id;
#Persistent private String name;
...
1. #Persistent public void getLastUpdate() { return new Date(); }
As suggested by answer, but it seems to always update the value, even when I just load the value from the datastore or just modify an unrelated field (e.g. String name).
You can easily enough have a property (setter/getter) on a java class and have the property persistable (rather than the field). Within that getter you can code whatever you want to control what value goes into the datastore.
If I didn't do the following hack, I can't read the value stored in the datastore [neither with the hack :( ]:
#Persistent public Date getLastUpdate() { return new Date(); }
private Date prevUpdate;
public void setLastUpdate(Date lastUpdate) { this.prevUpdate = lastUpdate; }
public Date getPrevUpdate() { return prevUpdate; }
Is there any way to differentiate if a persistence operation is in progress or my code is calling the getter?
2. #Persistent(customValueStrategy = "auto_now_add") private Date lastUpdate;
I modeled auto_now_add after org.datanucleus.store.valuegenerator.TimestampGenerator replacing Timestamp with java.util.Date.
But it was only populated once at the first makePersistent call, regardless of how many times I modified other fields and called makePersistent. Also note that it doesn't seem to behave as the documentation says (or my English is rusty):
Please note that by defining a value-strategy for a field then it will, by default, always generate a value for that field on persist. If the field can store nulls and you only want it to generate the value at persist when it is null (i.e you haven't assigned a value yourself) then you can add the extension "strategy-when-notnull" as false
3. preStore using PersistenceManager.addInstanceLifecycleListener
Works as expected, but I could make it work across multiple entities using a base class.
pm.addInstanceLifecycleListener(new StoreLifecycleListener() {
#Override public void preStore(InstanceLifecycleEvent event) {
MyEntity entity = (MyEntity)event.getPersistentInstance();
entity.setLastUpdate(new Date());
}
#Override public void postStore(InstanceLifecycleEvent event) {}
}, MyEntity.class);
4. implements StoreCallback and public void jdoPreStore() { this.setLastUpdate(new Date()); }
Works as expected, but I could make it work across multiple entities using a base class.
To satisfy my 4th constraint (using solutions 3 or 4)
Whatever I do I can't make the following structure work:
public abstract class Dateable implements StoreCallback {
#Persistent private Date created;
#Persistent private Date lastUpdate;
public Dateable() { created = new Date(); }
public void jdoPreStore() { this.setLastUpdate(new Date()); }
// ... normal get/set properties for the above two
}
#PersistenceCapable public class MyEntity extends Dateable {
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY, primaryKey = "true") private Long id;
#Persistent private String name;
The problems when the enhancer runs:
public abstract class Dateable:
DataNucleus.MetaData Registering class "[...].Dateable" as not having MetaData.
public abstract class Dateable with the above log, but running the code anyway:
Creation date changes whenever I create or read the data from datastore.
#PersistenceCapable public abstract class Dateable:
DataNucleus.MetaData Class "[...].MyEntity" has been specified with 1 primary key fields, but this class is using datastore identity and should be application identity.
JDO simply provides persistence of Java classes (and its fields/properties) so don't see what the design of JDO has to do with it.
You can easily enough have a property (setter/getter) on a java class and have the property persistable (rather than the field). Within that getter you can code whatever you want to control what value goes into the datastore. Either that or you use a preStore listener to be able to set things just before persistence so the desired value goes into the datastore.

How should I implement Transaction database EJB 3.0

In the CustomerTransactions entity, I have the following field to record what the customer bought:
#ManyToMany
private List<Item> listOfItemsBought;
When I think more about this field, there's a chance it may not work because merchants are allowed to change item's information (e.g. price, discount, etc...). Hence, this field will not be able to record what the customer actually bought when the transaction occurred.
At the moment, I can only think of 2 ways to make it work.
I will record the transaction details into a String field. I feel that this way would be messy if I need to extract some information about the transaction later on.
Whenever the merchant changes an item's information, I will not update directly to that item's fields. Instead, I will create another new item with all the new information and keep the old item untouched. I feel that this way is better because I can easily extract information about the transaction later on. However, the bad side is that my Item table may contain a lot of rows.
I'd be very grateful if someone could give me an advice on how I should tackle this problem.
I would try a third option something like this.
public class Item {
private String sku;
private double currentPrice;
}
public class Customer {
private String name;
private List<Transaction> transactions;
}
public class Transaction {
private Item item;
private Customer customer;
private double pricePerItem;
private double quantity;
private String discountCode;
}
I will leave you to work out the JPA mappings.

Categories

Resources