bind(ObjectDatastore.class).to(AnnotationObjectDatastore.class);
So that is basically it.
In each DAO class where I want to use the datastore I inject it like this:
@Inject private ObjectDatastore dataStore;
In my rest-endpoints (the first entry point for each request) I injected the datastore using a provider:
@Inject private Provider<ObjectDatastore> dataStore;
Then at the first line of each method I've put datastore.get(); in order to create a new datastore each time.
First off all this works only the first time, the second time it says that multiple threads are accessing the datastore. But I think that might be because I somewhere forgot to put the datastore.get(); ... So I will try to sort that out.
But is this the correct way? I would say no and that there is another way to automatically retrieve a new datastore on each request but I don't seem how...
But my main issue right now is that whenever I'm storing some stuff in the database, and a few methods later (in the same request) I want to retrieve the stuff that I've written (I'm basically creating a synchronization service for my Androd app) the data cannot be retrieved yet! So I get nullpointer exceptions. The way I was working before I let guice configure the datastore it dit work for me. So is there a way I can disable caching or do you have any idea what could be going wrong that I cannot immediatly retrieve my data anymore that I have persisted?
All the syncing stuff is going on in a transaction to be able to rollback all if somewhere in the sync process I have a problem...
Just tell me if you need more input :-)
Kr,
Dirk
Hello,I'm binding ObjectDatastore as RequestScoped object, so no metter where in your code you are calling datastoreProvider.get(), you will get always the same instance in context of the request.
So if I create GuiceObjectDataStore and annotate it with @RequestScoped it will work?Is there another way to make it request scoped (I'm not that experienced with Guice) ?
bind(ObjectDatastore.class).to(AnnotationObjectDatastore.class).in(RequestScoped.class);
Using the .scope(Scopes.REQUEST) doesn't compile for me becuase the Scopes class only has a SINGLETON and NO_SCOPE property.
And to start a transaction now in my service layer I will just have to inject a Provider<ObjectDataStore> datastores and then call datastores.get().beginTransaction(); right?
I will have to test further to see if my other problems are gone now, but here's another problem that I now have.
I do different queries on the class Project before I will persist one (just to do different kind of checks in different cases). But when quering the second time on the Project class (using a total different query, the first query is a retrieve by name and email, the second query is a count of items on syncKey and email) then I have this error:
java.lang.IllegalStateException: Find command must have an ancestor in a transaction.
Here is my code for the query:
int count = getDataStore().find()
.type(Project.class)
.addFilter("syncKey", FilterOperator.EQUAL, syncKey)
.addFilter("userEmail", FilterOperator.EQUAL, user.getEmail())
.returnCount()
.now();
return count == 0 ? true : false;
No idea what's wrong...
At first sight my issue is solved when I bind like this:bind(ObjectDatastore.class).to(AnnotationObjectDatastore.class).in(RequestScoped.class)
And to start a transaction now in my service layer I will just have to inject a Provider<ObjectDataStore> datastores and then call datastores.get().beginTransaction(); right?
I will have to test further to see if my other problems are gone now, but here's another problem that I now have.
I do different queries on the class Project before I will persist one (just to do different kind of checks in different cases). But when quering the second time on the Project class (using a total different query, the first query is a retrieve by name and email, the second query is a count of items on syncKey and email) then I have this error:
java.lang.IllegalStateException: Find command must have an ancestor in a transaction.Here is my code for the query:
int count = getDataStore().find()
.type(Project.class)
.addFilter("syncKey", FilterOperator.EQUAL, syncKey)
.addFilter("userEmail", FilterOperator.EQUAL, user.getEmail())
.returnCount()
.now();
return count == 0 ? true : false;No idea what's wrong...
User user = userDao.findAll().get(0);
Transaction tx = datastores.get().beginTransaction();
// Create a setup service...
Project project = new Project();
project.setName("TEST ABC");
project.setLastUpdated(new Date());
project.setUser(user);
projectDao.persist(project);
Project persistedProject = projectDao.find("TEST ABC", user);
if (persistedProject == null) {
System.out.println("Project not found...");
tx.rollback();
} else {
System.out.println("Project found!");
tx.commit();
}
Correct me if I am wrong but since you are in a transaction, the persist is not commited, so that's why your persistedProject
is always null
. To me you need to rollback when an exception is raised. So if your persist
fails, it should throw an exception. See the example: https://code.google.com/p/twig-persist/wiki/Transactions
project
= persistedProject
. no?
I wrote a simple test that tells me that it is because of the transactions...
Project persistedProject = projectDao.find("TEST ABC", user);
The dev server has a setting that lets you control the "Unapplied job percentage"
Does this method do a find() rather than a get()? When you use the HRD there is a delay between writing data and reading it.
But in other ORM frameworks (meaning not on GAE, something like hibernate) if it's not yet comitted I can already retrieve it.
Project project = getDataStore().find()
.type(Project.class)
.addFilter("name", FilterOperator.EQUAL, name)
.ancestor(user)
.returnUnique()
.now();
Ok I think I understand now.Let's see :P1. When I use a find() I will hit the datastore, so when in a transactions it does not include my persisted (but not yet comitted) entities2. When I use a load() I will hit the twig-cache you mentioned in which the persisted (but not yet comitted) entities can be found.Is that right?
If so then my second question is how I can dynamically use the load() method.Currently my find method is this:Project project = getDataStore().find()
.type(Project.class)
.addFilter("name", FilterOperator.EQUAL, name)
.ancestor(user)
.returnUnique()
.now();So how can I convert this to the load() method? The load method does not has an addFilter(), ancestor(),... Load is only mentioned to load by by key isn't it?
My use-case is that I do some checks on a project, then persist or update an existing project. Next
I query all my projects to find one that equals my task I want to sync. But that is not necessarily the same project, but it's possible. So I cannot query it on key so I cannot use the load() method?
But in your entire explanation that load() loads from a twig-cache and find() loads from the datastore (or the snapshot) makes me thinking that it would make sense if twig always checked the twig-cache when using load() also, no?
But I guess I'm in trouble :DProblem is that I cannot make project.name the @id of the entity because the key is a composite key by User and project.name.
So because composite keys are not possible I have @GaeKey instead and check this user/project.name restriction manually.