I am learning GAE and am getting a bit stuck. If I use the following, with a finally to make sure the persistence manager is closed, I get an exception when trying to actually read the Note objects:
public class Notes {
public List<Note> getAll() {
PersistenceManager pm = PMF.instance().getPersistenceManager();
try {
Query query = pm.newQuery("select from com.uptecs.google1.model.Note order by subject");
return (List<Note>) query.execute();
} finally {
pm.close();
}
}
}
The exception I get is this:
Object Manager has been closed
org.datanucleus.exceptions.NucleusUserException: Object Manager has been closed
at org.datanucleus.ObjectManagerImpl.assertIsOpen(ObjectManagerImpl.java:3876)
at org.datanucleus.ObjectManagerImpl.getFetchPlan(ObjectManagerImpl.java:376)
at org.datanucleus.store.query.Query.getFetchPlan(Query.java:497)
Try detaching the object from the graph with detachable="true":
#PersistenceCapable(identityType = IdentityType.APPLICATION, detachable="true")
public class Note {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long key;
...
}
Note: I totally understand the need for this, sometimes you need to retrieve the objects and lists in a controller, close the PM in the controller, then pass the models to the views. Until better solutions are known to me, this is what I am doing this on JDO/GAE with no problems so far.
List:
It seems to me that you will have to detach all the items in the list if you want to be able to use them after the PM is closed. I'd use this to get specific lists of items. A full getAll() can be very big in size.
public List<Note> getList(){
List<Note> detachedList=null, list=null;
try {
String query = "select from " + Note.class.getName();
pm = PMF.get().getPersistenceManager();
list = (List<Note>)pm.newQuery(query).execute();
detachedList = new ArrayList<Note>();
for(Note obj : list){
detachedList.add(pm.detachCopy(obj));
}
} finally {
pm.close();
}
return detachedList;
}
By Key:
public Note findByKey(Long key) {
Note detachedCopy=null, object=null;
try{
pm= PMF.get().getPersistenceManager();
object = pm.getObjectById(Note.class,key);
detachedCopy = pm.detachCopy(object);
}catch (JDOObjectNotFoundException e) {
return null; // or whatever
}
finally {
pm.close(); // close here
}
return detachedCopy;
}
Afer the close, you have a detached copy, with which you can work.
Reference: http://www.datanucleus.org/products/accessplatform_1_1/jdo/attach_detach.html
When result is returned in the list - objects are retrieved lazily (only when you ask for them). Since your persistence manager is closed you get an exception. By "detaching" the objects your are effectively telling the persistence manager to retrieve them eagerly.
In addition to the answer from bakkal, I would say that you absolutely need the detachable="true" annotation parameter, otherwise you will never get it to work.
To detach a list of objects, you can also use pm.detachCopyAll(your_query_result_list), wich will be a bit faster than your implementation of the iteration to detach, and will let you spare a few lines of code. Thanks JDO ! ;-) But be aware, this method requires explicit cast of its results.
Here's a working example I currently use in my last App (the Key used in the query is an Encoded String) :
pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery(TandemSubscription.class);
query.setFilter("groupSubscriptionKey==groupSubscriptionKeyParam");
query.setOrdering("dateRDV desc");
query.declareParameters("String groupSubscriptionKeyParam");
// Get Data
#SuppressWarnings("unchecked")
List<TandemSubscription> savedSubscriptions =
(List<TandemSubscription>) query.execute(Key);
// Detach all objects in the list
savedSubscriptions =
(List<TandemSubscription>) pm.detachCopyAll(savedSubscriptions);
pm.close();
// Now you can use the list and its content.
I Hope this helps a bit.
Related
Hi guys i have this mapping inside the Customer entity:
#OneToOne(cascade={javax.persistence.CascadeType.ALL})
#JoinColumn(name="address")
private Address address;
And then i have this method in my DAO class:
#SuppressWarnings("unchecked")
public List<Customer> getCustomersFromThisAddress() throws Exception{
sessao = null;
try{
sessao = HibernateUtil.getSessionFactory().openSession();
Customer customer= new Customer();
Criteria criteria = sessao.createCriteria(customer.getClass())
.createAlias("address", "a")
.add(Restrictions.ilike("a.area", "bedford"));
return (List<Customer>) criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY).list();
} catch (Exception e) {
return null;
} finally {
sessao.close();
}
}
I would like to return all customers from the bedford area... I am new to Hibernate and Criteria, please help.
You have to remember about two things when using the ilike:
a) The underlying database must be able to support it or have an equivalent function.
b) Without specifying MatchMode or adding % symbols to the second argument, your statement is just a case-insensitive equals.
So if you want to search for a text that simply contains somewhere the bedford string then use one of the following:
.add(Restrictions.ilike("a.area", "%bedford%"));
or
.add(Restrictions.ilike("a.area", "bedford", MatchMode.ANYWHERE));
I was getting an empty list '[]' I realized that I made a mistake in the .add(Restriction.. line!!
the 'area' column data, in the Address table are all recorded as 'Bedford'..
after reading this: https://www.tutorialspoint.com/hibernate/hibernate_criteria_queries.htm
I found that I just needed to change
Criteria criteria = sessao.createCriteria(customer.getClass())
.createAlias("address", "a")
.add(Restrictions.ilike("a.area", "bedford"));
to
Criteria criteria = sessao.createCriteria(customer.getClass())
.createAlias("address", "a")
.add(Restrictions.like("a.area", "bedford"));
to return my list... Hope this will help others!!
I'm trying to save with GreenDAO an entity called hotel. Each hotel has a relation one-to-many with some agreements and each agreement has got... well, a picture is worth a thousand words.
Now, what I do is the following:
daoSession.runInTx(new Runnable() {
#Override
public void run() {
ArrayList<Hotel> listOfHotels = getData().getAvailability();
for(Hotel h : listOfHotels)
{
List<HotelAgreement> hotelAgreements = h.getAgreements();
for(HotelAgreement ha : hotelAgreements) {
ha.setHotel_id(h.getHotel_id());
HotelAgreementDeadline hotelAgreementDeadline = ha.getDeadline();
List<HotelRemark> hr = hotelAgreementDeadline.getRemarks();
List<HotelAgreementDeadlinePolicies> hadp = hotelAgreementDeadline.getPolicies();
daoSession.getHotelReportDao().insertOrReplaceInTx( h.getReports() );
daoSession.getHotelPictureDao().insertOrReplaceInTx( h.getPictures() );
daoSession.getHotelRemarkDao().insertOrReplaceInTx(hr);
daoSession.getHotelAgreementDeadlinePoliciesDao().insertOrReplaceInTx(hadp);
daoSession.getHotelAgreementDeadlineDao().insertOrReplace(hotelAgreementDeadline);
daoSession.getHotelAgreementDao().insertOrReplace(ha);
}
// daoSession.getHotelReportsDao().insertOrReplace( getData().getReports() );
}
daoSession.getHotelDao().insertOrReplaceInTx(listOfHotels);
}
});
This, of course, does not work. I get a "Entity is detached from DAO context" error on the following line:
HotelAgreementDeadline hotelAgreementDeadline = ha.getDeadline();
I understand this is because I try to get the Agreements from a Hotel entity which does not come from the database, but from another source (a web service, in this case). But why does this happen with ha.getDeadline() and not with h.getAgreements()?
Now, I have the Hotel object and it does include pretty much all data: agreements, deadline, policies, remarks, pictures, report. I'd just like to tell GreenDAO: save it! And if I can't and I have to cycle through the tree - which is what I'm trying to do with the code above - how am I supposed to do it?
Here I read that I have to "store/load the object first using a Dao". Pretty awesome, but... how does it work? I read the greenDAO documentation about relations but couldn't find anything.
Thank you to everybody who's willing to help :-)
At some point, when you get the response from the webservice, you are creating new entity objects and filling them with the info. Try inserting each new object in the DB just after that.
If you want, you can insert, for example, all n Agreement for an Hotel using insertOrReplaceInTx, but you shouldn't use any relation before all the involved objects are in the DB.
I think that greendao team have to add the following control in the method
getToOneField() like in the getToManyList()
if(property == null){
code already generated by greendao plugin
}
return property;
so in your case in HotelAgreements class
#Keep
public DeadLine getDeadLine {
if(deadLine == null) {
long __key = this.deadLineId;
if (deadLine__resolvedKey == null || !deadLine__resolvedKey.equals(__key)) {
final DaoSession daoSession = this.daoSession;
if (daoSession == null) {
throw new DaoException("Entity is detached from DAO context");
}
DeadLineDao targetDao = daoSession.getDeadLineDao();
DeadLine deadLineNew = targetDao.load(__key);
synchronized (this) {
deadLine = deadLineNew;
deadLine__resolvedKey = __key;
}
}
}
return deadLine;
}
adding the control
if(deadLine == null) {
...
}
so if you receive data from rest json
the object is populated and getProperty() method return property field from object not from database just like it does with Lists
then you can insert or replace it
Then, when you load or load deeply object from db the property is null and greendao take it from DB
I have a question about deleting entities in EJB3.
I have two database tables: MainCategory and Category.
First, I have to find all MainCategory entitys' name and its Category, so I do this:
public List<MainCategory> findAllWithCategories() {
TypedQuery<MainCategory> query = em.createNamedQuery("MainCategory.findAll", MainCategory.class);
List<MainCategory> result = query.getResultList();
for (MainCategory mc : result){
try{
Hibernate.initialize(mc.getSubCategories());
}catch (Exception e){
e.printStackTrace();
}
}
return result;
}
Than I need its Categories, but I have to initialize something, so I do this (where selectedMainCategory is an element of List<MainCategory> = mainCategoryRepository.findAllWithCategories() )
List<Category> mainCategories = categoryRepository.findByMainCategoryIdAndInitialze(selectedMainCategory.getId());
instead of this:
List<Category> subCategories = mainCategory.getSubCategories();
And after some action I need to delete a Category, so I do (where selectedSubCategory is an element of subCategories):
selectedMainCategory.getSubCategories.remove(selectedSubCategory);
mainCategoryRepository.modify(selectedMainCategory);
However selectedSubCategory hasn't been removed from selectedMainCategory.getSubCategories().
Ok, I can remove it manually if I find it by Id and manually remove from the list, but I can't find out why getSubCategories.remove(object) doesn't work in this case. I guess it is something about equality of two java object, but I don't know exactly. How does EJB and Java work in this case? Can you explain it to me?
I'm trying to manually delete every entity that's in a collection on an entity. The problem is, the entities don't get deleted from the database, even though they get removed from the collection on the task.
Below is the code im using to achieve this:
public int removeExistingCosts(final DataStoreTask task) {
int removedAccumulator = 0;
Query query = entityManager.createNamedQuery(DataStoreCost.GET_COSTS_FOR_TASK);
query.setParameter(DataStoreCost.TASK_VARIABLE_NAME, task);
try {
List costsForTask = query.getResultList();
for(Object cost : costsForTask) {
task.getCosts().remove(cost);
removedAccumulator++;
}
} catch (NoResultException e) {
logger.debug("Couldn't costs for task: {}", task.getId());
}
entityManager.flush();
entityManager.persist(task);
return removedAccumulator;
}
Any ideas?
P.S the collection is represented as:
#OneToMany(targetEntity = DataStoreCost.class, mappedBy = "task", cascade = CascadeType.ALL)
private Collection<DataStoreCost> costs;
Cheers.
I think you need to explicitly remove the Cost entity via the entityManager. When you remove the Cost from the Tasks cost list you actually only remove the reference to that instance. It does not know that that particular Cost will not be used anywhere else.
It's not deleting the entity, because it doesn't know if something else is referring to it.
You need to enable delete orphan. In jpa2, use the orphanRemoval attribute. If you're using hibernate annotations, use CascadeStyle delete orphan.
I'm writing a small application using GWT and JDOs to store persistent data. I've been trying to write a function that updates multiple JDO objects based on a query. Its body looks something like this:
PersistenceManager pm = getPersistenceManager();
try {
q = pm.newQuery(MyObject.class, query);
List<MyObject> objects = (List<MyObject>) q.execute();
for (MyObject object: objects) {
object.setMyField(newValue);
}
System.out.println(objects); //[1]
} finally {
pm.close();
}
If I look at the output of the print statement at [1], the objects all have the correctly updated values. When I make an RPC to retrieve the updated objects, however, the values are the same as they were before the update method was called. If I check the datastore in the admin panel, the updates also do not appear.
All the other persistence behaviour in my application works fine (e.g. adding new objects, removing objects, querying objects), but I can't seem to figure out what's wrong here. Most of the resources I've found (like http://code.google.com/appengine/docs/java/datastore/jdo/creatinggettinganddeletingdata.html#Updating_an_Object) suggest that just having the PersistenceManager open should persist any changes you make to retrieved objects.
Any suggestions? I am truly baffled.
Thank you!
SOLUTION
PersistenceManager pm = getPersistenceManager();
try {
q = pm.newQuery(MyObject.class, query);
List<MyObject> objects = (List<MyObject>) q.execute();
for (MyObject object: objects) {
object.setMyField(newValue);
JDOHelper.makeDirty(object, myField);
}
} finally {
pm.close();
}
The proper way to update JDOs is to use a transaction, e.g. (w/o proper handling)
PersistenceManager pm = getPersistenceManager();
try {
q = pm.newQuery(MyObject.class, query);
List<MyObject> objects = (List<MyObject>) q.execute();
pm.currentTransaction().begin(); // <-------
for (MyObject object: objects) {
object.setMyField(newValue);
}
pm.currentTransaction().commit(); // <-------
System.out.println(objects); //[1]
} finally {
pm.close();
}
I'd recommend you do that for other all other update scenario including add/delete operations.