I see a similar question in Problems while saving a pre-persisted object in Google App Engine (Java), and indeed I was not calling close() on my persistence manager. However, I am now calling close, but my object update is not being persisted. Specifically, I want to remove an element from a Set, and save that smaller set. Here is the persistence manager related code, that doesn't throw an exception, but doesn't save my data:
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
PersistenceManager pm = PMF.get().getPersistenceManager();
UserProfileInfo userProfile = pm.getObjectById(UserProfileInfo.class,user.getUserId());
int presize = userProfile.getAccounts().size();
AccountInfo ai = userProfile.removeAccount(id);
int postsize = userProfile.getAccounts().size();
UserProfileInfo committed = (UserProfileInfo)pm.makePersistent(userProfile);
int postcommitsize = committed.getAccounts().size();
pm.close();
And here is the relevant part of the UserProfileInfo class:
#PersistenceCapable(identityType = IdentityType.APPLICATION)
class UserProfileInfo {
#Persistent
private Set<AccountInfo> accounts;
public AccountInfo removeAccount(Long id) throws Exception {
Iterator<AccountInfo> it = accounts.iterator();
StringBuilder sb = new StringBuilder();
while(it.hasNext()) {
AccountInfo acctInfo = it.next();
Long acctInfoId = acctInfo.getId();
if(acctInfoId.equals(id)) {
it.remove();
return acctInfo;
}
sb.append(" ");
sb.append(acctInfoId);
}
throw new Exception("Cannot find id " + id + " Tried " + sb.toString());
}
}
So it looks like the answer is owned objects cannot use a Long primary key. The datanucleus enhancer told me this for another object type I added. I'm not sure why it skipped this warning for my AccountInfo object.
I switched my key over to a String, and changed the annotations to use the string properly, and now I'm able to delete from the collection.
I'd have thought that the first thing to do when debugging anything would be to look at the log (DEBUG level). It tells you what states the objects are in at the different points. So what state is it in when you call makePersistent() ? and after ? and what happens when you call pm.close() ...
Related
I am trying to improve the speed at which pages are loading on my site and it seems the issue is with the TTFB. The backend is using Java with Spring framework.
Most of the pages on the website have a TTFB of >1000ms, this time also fluctuates and occasionally will as much as 5000ms.
I have made database indexes for all of the commonly used SQL queries in the back end as well upgrading the instance class running on Google App Engine. This has had a positive impact but the overall performance is still lacking. (The server hosting is in the nearest location to me)
Additional I observed that the TTFB is roughly 200ms longer than the time it takes for the code to run and return the model in the controller. In some cases there are a lot of attributes being added to the model so it's possible html building is taking considerable time but I wonder if there is an issue with how Spring is configured.
From what I have read online a TTFB of more than 600ms is consider sub optimal so I think there is room for more improvement.
Are there any known performance issues with Spring on Google App Engine which I should explore further?
Do you have suggestion for anything else I should try?
Below is the code from one of the slower controllers in cases that helps in identify any obvious inefficiencies.
Thanks for any help!
public String requestPrivateCompanyProfile(Model model,
#PathVariable String companyName,
#RequestParam(required = false) String alertboxMessage,
#RequestParam(required = false) String openSubmenu) {
User user = sessionService.getUser();
Ecosystem ecosystem = sessionService.getEcosystem();
model.addAttribute("user", user);
model.addAttribute("ecosystem", ecosystem);
model.addAttribute("canSeeAdminButton", accessLevelService.isUserHasManagmentAccessLevel(ecosystem, user));
model.addAttribute("userPic", cloudStorageService.getProfilePic(user));
model.addAttribute("ecoNavLogo", cloudStorageService.getEcosystemLogo(ecosystem.getName(), true));
model.addAttribute("defaultCompanyLogo",cloudStorageService.getDefaultCompanyLogo());
// Pass on the alertboxMessage and openSubmenu parameters, if there are any
if (alertboxMessage != null) model.addAttribute("alertboxMessage", alertboxMessage);
if (openSubmenu != null) model.addAttribute("openSubmenu", openSubmenu);
// If user is not registered in the current ecosystem, redirect to index
if (ecoUserDataRepository.findByKeyEcosystemAndKeyUser(ecosystem, user) == null) return "redirect:/";
// If the company doesn't exist, redirect to /companies
Company company = companyRepository.findByEcosystemAndName(ecosystem, companyName);
if (company == null) return "redirect:/companies";
//checks the user has permission to view this page
if (!accessLevelService.isCanSeePrivateCompanyProfile(ecosystem, company, user)) return "redirect:/companies";
// Store the company user data along with the profile pics of each employee
List<CompanyProfileEmployeeDto> employeeDtos = new ArrayList<>();
List<CompanyUserData> cuds = companyUserDataRepository.findAllByKeyCompany(company);
for (CompanyUserData cud : cuds) {
User employee = cud.getKey().getUser();
String profPic = cloudStorageService.getProfilePic(employee);
if (employee == company.getOwner()) {
employeeDtos.add(0, new CompanyProfileEmployeeDto(cud, profPic));
} else {
employeeDtos.add(new CompanyProfileEmployeeDto(cud, profPic));
}
}
//Get all the ecosystem users to enable search for new team members
EcoUserData[] ecoUserData = ecoUserDataRepository.findAllEcoUsers(ecosystem).toArray(new EcoUserData[0]);
//Get tags used by the company
String ecoSystemTags = ecosystem.getEcosystemTags() == null ? "" : ecosystem.getEcosystemTags();
String companyTagsString = company.getTags() == null ? "" : company.getTags();
String[] companyTags = company.getTags() == null ? null : company.getTags().replace("#", "").split(";");
List<String> unusedTags = TagsService.getUnusedTags(companyTagsString, ecoSystemTags);
//get goals and order them for the private company
List<CompanyGoal> companyGoalAchieved = companyGoalRepository.findCompanyGoalByAchievedAndCompany(false, company);
List<CompanyGoal> companyNotGoalAchieved = companyGoalRepository.findCompanyGoalByAchievedAndCompany(true, company);
Collections.reverse(companyGoalAchieved);
Collections.reverse(companyNotGoalAchieved);
//this makes achieved goals the first in the list
List<CompanyGoal> companyGoalsOrdered = new ArrayList<>(companyGoalAchieved);
companyGoalsOrdered.addAll(companyNotGoalAchieved);
//get the shared docs for a specific private company
List<CompanySharedDocs> companySharedDocs = companySharedDocsRepository.findCompanySharedDocsByCompanyAndDocType(company, "shared");
//get the admin documents for a specific private company
List<CompanySharedDocs> companyAdminDocs = companySharedDocsRepository.findCompanySharedDocsByCompanyAndDocType(company, "admin");
//get the admin documents for a specific private company
List<CompanySharedDocs> resourceLinks = companySharedDocsRepository.findCompanySharedDocsByCompanyAndDocType(company, "resource");
//gets shared notes for the company sorts the list so the recently edited notes are first in the list
List<CompanySharedNote> companySharedNotes = companySharedNoteRepository.findCompanySharedNoteByCompany(company);
companySharedNotes.sort(Comparator.comparing(CompanySharedNote::getLastEdited).reversed());
//finds all kpi associated with a company and saves them into a list, each kpi in the list then has its kpiEntries sorted by date
List<KeyPerformanceIndicator> companyKpis = keyPerformanceIndicatorRepository.findAllByCompany(company);
Collections.reverse(companyKpis);
for (KeyPerformanceIndicator kpi: companyKpis){
kpi.sortKpiEntriesByDate();
}
//checks if the user just created a new kpi and if they did add attribute to change frontend display
model.addAttribute("showKpiTab", sessionService.getAttribute("showKpiTab"));
sessionService.removeAttribute("showKpiTab");
model.addAttribute("companyKpis", companyKpis);
model.addAttribute("resourceLinks", resourceLinks);
model.addAttribute("isOwner", company.getOwner() == user);
model.addAttribute("canDeleteCompanyProfile", accessLevelService.isDeleteCompanyProfile(ecosystem, company, user));
model.addAttribute("canSeePrivateCompanyProfile", true);
model.addAttribute("canEditCompanyProfile", accessLevelService.isCanEditCompanyProfile(ecosystem, company, user));
model.addAttribute("companyAdminDocs", companyAdminDocs);
model.addAttribute("companySharedNotes", companySharedNotes);
model.addAttribute("companyGoals", companyGoalsOrdered);
model.addAttribute("companySharedDocs", companySharedDocs);
model.addAttribute("company", company);
model.addAttribute("empDtos", employeeDtos);
model.addAttribute("ecoUserData", ecoUserData);
model.addAttribute("companyTags", companyTags);
model.addAttribute("unusedTags", unusedTags);
model.addAttribute("canUploadAdminDocs", ecoUserDataRepository.findByKeyEcosystemAndKeyUser(ecosystem, user).getAccessLevels().isCanUploadAdminDocs());
model.addAttribute("companyNameList", companyUserDataRepository.findAllCompanyNameByUserAndEcosystem(user, ecosystem));
return "ecosystem/company-profile/private-company-profile";
}
I have the below Stream class that is getting returned from DB:
Stream<Transaction> transctions=transRepository.findByTransctionId();
public class Transaction{
String transctionId;
String accountId;
String transName;
String accountName;
}
Now my Requirement is as below:
Transaction entity has 4 fields. So, from DB all the 4 fields were fetched by Jpa.
But client who needs this data ,he has sent the columnsName in list that he is looking from Transaction model
List<String> columnNames=Arrays.asList("transctionId","accountName")
I have post this data to Kafka.I have to take each Transction from this stream post it to kafka.
But cline is looking for only this 2 fields "transctionId","accountName" should go as part of Transaction in Kafka instead of all 4 fields.
The data should go in form of json to Kafa having below format:
{
"transctionId":"1234",
"accountName" :"test-account"
}
Basically only those fields should go to kafka which they have asked for instead of converting the whole pojo to json and send it.
Is there any way to achieve that?
If you need to invoke a method, but you only have its name, the only way I know is via reflection. I would do it like this:
Stream<Transaction> transctions=transRepository.findByTransctionId();
List<Transaction> outTransactions = new ArrayList<>();
List<String> columnNames = new ArrayList<>();
transactions.forEach(tr -> {
Transaction outTransaction = new Transaction();
columnNames.forEach( col -> {
try {
var getMethod = tr.getClass().getMethod("get" + StringUtils.capitalize(col));
Object value = getMethod.invoke(tr);
String valueStr = value instanceof String ? value.toString() : "";
var setMethod = outTransaction.getClass().getMethod("set" + StringUtils.capitalize(col));
setMethod.invoke(outTransaction, valueStr);
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
e.printStackTrace();
}
});
outTransactions.add(outTransaction);
});
There is a lot of traversing, but with the requirements you have, this is the generic solution I can come up with. Another shortcoming to this solution is the creation of new Transaction objects. Which means that if Transactions are many, memory usage can grow. Maybe this solution can be optimised to take advantage of streaming the transactions from the DB.
Another way to do it is to have different endpoints for each known set of properties that the client sends you. For example:
#GetMapping("/transaction_id_and_name")
List<Transaction> getTransactionsIdAndName() {
... obtain Transactions, return a new list of Transactions, with transaction_id and name ... }
#GetMapping("/transaction_id_and_status")
List<Transaction> getTransactionsNameAndStatus() {...}
This is the DAO I have created:
public Poll updatePoll(int id){
Session s = factory.getCurrentSession();
Transaction t = s.beginTransaction();
Poll poll = (Poll) s.get(Poll.class, id);
Citizen citizen = (Citizen) s.get(Citizen.class, 1);
List<Poll> list = citizen.getPolledList();
boolean check = list.contains(poll);
if(!check){
Query q = s.createSQLQuery("update Poll set poll_count = poll_count + 1 where poll_id = id");
q.executeUpdate();
s.update(poll);
}else{
return poll;
}
s.close();
return poll;
}
This is the Action created:
public String submitVote(){
ServletContext ctx = ServletActionContext.getServletContext();
ProjectDAO dao = (ProjectDAO)ctx.getAttribute("DAO");
Poll poll = dao.updatePoll(poll_id);
String flag = "error";
if (poll != null){
ServletActionContext.getRequest().getSession(true).setAttribute("POLL", poll);
flag = "voted";
}
return flag;
}
I know I have been going horribly wrong and the code I'm posting might be utter rubbish. But I hope the intent is clear, thus if possible please lent me a helping hand. My project is mainly in JSP (Struts 2), jQuery and MySQL 5.1, so please do not suggest PHP codes as I've found earlier.
The framework is used to wrap the servlet stuff from user, you should use its features if you want doing something like
ServletActionContext.getRequest().getSession(true)
But
Map m = ActionContext.getContext().getSession();
Hello I'm newbie in learning hibernate framework. I was solved my error but I don't know what the problem happen. In my project I have 2 tables Tblbarang and Tbljenis. And 1 field at Tblbarang had relations as foreign key by Tbljenis.
I want to update Tblbarang table. I had two method
private void getcombobarang() {
Query q = sess.createQuery("from Tblbarang");
arrbarang = new ArrayList<>();
DefaultComboBoxModel comboModel = new DefaultComboBoxModel();
for (Object o : q.list()) {
Tblbarang coba = (Tblbarang) o;
comboModel.addElement(coba.getNamabarang());
arrbarang.add(coba);
}
combobarang.setModel(comboModel);
}
This method to set model combobox which I would choose to set the table Tblbarang item.
and now this method to update my Table Tblbarang
sess = NewHibernateUtil.getSessionFactory().openSession();
sess.beginTransaction();
Tblbarang tb = new Tblbarang();
tb.setKodbarang(arrbarang.get(combobarang.getSelectedIndex()).getKodbarang());
tb.setNamabarang(arrbarang.get(combobarang.getSelectedIndex()).getNamabarang());
tb.setTbljenis(arrbarang.get(combobarang.getSelectedIndex()).getTbljenis());
tb.setHarganet(arrbarang.get(combobarang.getSelectedIndex()).getHarganet());
tb.setHargajual(arrbarang.get(combobarang.getSelectedIndex()).getHargajual());
System.out.println(arrbarang.get(combobarang.getSelectedIndex()).getTbljenis()); // <-- this line resolved my problem
int st = Integer.parseInt(stok.getText()) ;
int jm = Integer.parseInt(jumlah.getText());
String totss = String.valueOf(st + jm);
Short totstok = Short.parseShort(totss);
tb.setStok(totstok);
sess.update(tb);
sess.getTransaction().commit();
when without System.out.print() the error are following
org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions
at org.hibernate.proxy.AbstractLazyInitializer.setSession(AbstractLazyInitializer.java:126)
at org.hibernate.proxy.AbstractLazyInitializer.setSession(AbstractLazyInitializer.java:126)
at org.hibernate.engine.StatefulPersistenceContext.reassociateProxy(StatefulPersistenceContext.java:573)
at org.hibernate.engine.StatefulPersistenceContext.reassociateIfUninitializedProxy(StatefulPersistenceContext.java:533)
at org.hibernate.event.def.ProxyVisitor.processEntity(ProxyVisitor.java:50)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:125)
at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:83)
at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:77)
at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:144)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:314)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:246)
at org.hibernate.event.def.DefaultUpdateEventListener.performSaveOrUpdate(DefaultUpdateEventListener.java:57)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
at org.hibernate.impl.SessionImpl.fireUpdate(SessionImpl.java:742)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:730)
at org.hibernate.impl.SessionImpl.update(SessionImpl.java:722)
at retail.ui.frmBarangMasuk.tambahitemActionPerformed(frmBarangMasuk.java:622) //<-this line directing to sess.update(tb)
I will simply my code like this
sess = NewHibernateUtil.getSessionFactory().openSession();
sess.beginTransaction();
Tblbarang tb = (Tblbarang) arrbarang.get(combobarang.getSelectedIndex());
System.out.println(arrbarang.get(combobarang.getSelectedIndex()).getTbljenis());
int st = Integer.parseInt(stok.getText()) ;
int jm = Integer.parseInt(jumlah.getText());
String totss = String.valueOf(st + jm);
Short totstok = Short.parseShort(totss);
tb.setStok(totstok);
sess.update(tb);
sess.getTransaction().commit();
but the exception showing same error. I want to know what happen with my code? anyone can explain with that issue or this is bug from hibernate, thanks
In getcombobarang, you have a sess(session1) to get objects from database. And when updating tb, you open another sess(session2).
If Tblbarang contains a foreign-key object, in this case, which must associates with session1, because it's obtained from the function getcombobarang at first. So sess.update() throws an exception as you have seen.
For solution:
use merge() instead of update()
before update, copy the foreign-key object's properties to a whole new object, then set it into tb
I'm also confused about the impact of System.println() here.
I still can't work with GAE's keys/ids. I keep getting the error: No entity was found matching the key: Key(Medewerker(5201690726760448)). The entities exist in the datastore, I checked this multiple times.
I'm trying to just simply get an user object with a certain ID. In my servlet I have the following code:
Long userId = Long.parseLong(req.getParameter("user"));
User user = userDao.getUser(userId);
The above code brings up the error. In userDaoOfyImpl.java I have the following method 'getUser':
public Gebruiker getGebruiker(Long id) {
Gebruiker result = null;
Gebruiker leerling = (Gebruiker) ofy.get(Leerling.class, id);
Gebruiker medewerker = (Gebruiker) ofy.get(Medewerker.class, id);
Gebruiker stagebedrijf = (Gebruiker)ofy.get(StageBedrijf.class, id);
//Gebruiker instantie returnen
if(leerling != null) {
result = leerling;
} else if(medewerker != null) {
result = medewerker;
} else if(stagebedrijf != null) {
result = stagebedrijf;
}
return result;
}
The variables are dutch but I think you guys know the idea. The above method searches in different classes looking for a user that matches the ID and then returns it.
The problem is I get the error shown above and I'm really getting frustrated, what am I doing wrong guys? Is it the method or the way I use ID's or...?
Thanks in advance!
here you can read for the get method:
Throws: NotFoundException - if the key does not exist in the datastore
use
Gebruiker leerling = (Gebruiker) ofy.find(Leerling.class, id);
the find method doesn't throws NotFoundException when the key doesn't exist but null.