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?
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'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 have a function that return an ArrayList< String > ,the list contain elements retrieved from database using JPA ,my problem is that I can't understand the format of the output!
the function is:
public ArrayList<String> getMyListEnvironment()
{
ArrayList<String> env=new ArrayList<String>();
try{
EntityTransaction entr=em.getTransaction();
entr.begin();
javax.persistence.Query multipleSelect= em.createQuery("SELECT h.hEnv FROM HPe h WHERE h.hPePK.pePlatform = :w ").setParameter("w", "platf1");
List s = new LinkedList();
s= multipleSelect.getResultList();
env = new ArrayList(s);
entr.commit();
return env;
}
catch (Exception e )
{
System.out.println(e.getMessage());
System.out.println("error");
}
finally {
em.close();
}
return env;
}
The output(Result):
[DTOMonito.HEnv[ envUrl=http://10.55.99.5:1055 ], DTOMonito.HEnv[ envUrl=http://10.55.99.99:8090 ]]
The query is returning the list of hEnv found as fields of the the HPe entity (seems like these abbreviations for the entities cause more confusion than good - it's a good idea to use descriptive names for these type of things).
Is HPe.hEnv a String? Perhaps your output is confusing because someone is storing a formatted string in this field. Without seeing your code, this is very hard to decipher.
Btw, this method is a bit wasteful for creating dead stores. There is absolutely no point in writing something like this:
List s = new LinkedList();
s= multipleSelect.getResultList();
You could save a line of code (and a LinkedList allocation) by just writing
List s = multipleSelect.getResultList();
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.