I'm using Google App Engine and I created an persistent entity using Google documentation about JDO. The class is the following:
#PersistenceCapable
public class Message {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
public long id;
#Persistent
public Text message;
#Persistent
public boolean isNew;
#Persistent
public long categoryId;
#Persistent
public boolean plus;
#Persistent
public Date lastUpdate;
Message(long id, String message, boolean isNew, long categoryId, Date lastUpdate, boolean plus) {
this.id = id;
this.message = new Text(message);
this.isNew = isNew;
this.categoryId = categoryId;
this.lastUpdate = lastUpdate;
this.plus = plus;
}
}
And than, I create the a HttpServlet with the following doPost code:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/plain");
PrintWriter writer = resp.getWriter();
Date tenDaysAgo = new Date(new Date().getTime()-TEN_DAYS_IN_MILISSECOND);
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
Query queryMessages = pm.newQuery(Message.class);
queryMessages.setFilter("isNew == True && lastUpdate <= lastUpdateParam");
queryMessages.declareParameters(Date.class.getName() + " lastUpdateParam");
List<Message> results = (List<Message>) queryMessages.execute(tenDaysAgo);
for(Message msg : results) {
msg.isNew = false;
pm.makePersistent(msg);
}
//pm.makePersistentAll(results);
writer.print(results.size() + " messages changed.");
}finally {
pm.close();
}
}
But, when I do a post request I receive the message "3048 messages changed." and I check the database and the data is unchanged. The persistence is not working to persist the changes I made in the object. Even though using makePersistentAll( list ) or makePersistent( object ) the result is the same: no change in the database.
What I'm missing?
Thank you!
You need to create a JDO transaction to keep track of changes and then commit them to issue the update SQL statements:
pm.currentTransaction().begin();
for(Message msg : results) {
msg.isNew = false;
}
pm.currentTransaction().commit();
Related
I have added Hibernate filters on my entities . These filters are applied on queries which fetch Collection of entity but not applied on queries which fetch single entity. Below is my code.
AOrganization.java
#MappedSuperclass
#FilterDef(name = "OrgFilter", parameters = { #ParamDef(name = "allowedOrgIdList", type = "long") })
#Filter(name = "OrgFilter", condition = "org_id in (:allowedOrgIdList)")
public class AOrganization implements Serializable {
#ManyToOne()
#JoinColumn(name = "org_id", nullable = true)
private Organization organization;
public Organization getOrganization() {
return organization;
}
public void setOrganization(Organization organization) {
this.organization = organization;
}
}
Site.java
#Data
#Entity
#Table(name = "site")
public class Site extends AOrganization{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "id")
private long id;
#Column(name = "site_name")
private String siteName;
#Override
public String toString() {
return "Site [id=" + id + ", siteName=" + siteName + "]";
}
}
SiteService.java
public interface SiteService {
public List<Site> getAllSites();
public List<Site> getSiteBySiteName(String siteName);
public Site updateSiteName(Long id, String siteName);
}
SiteRepository.java
#Repository
public interface SiteRepository extends AOrganizationRepository<Site, Long> {
public List<Site> findBySiteName(String siteName);
public List<Site> findByOrganization_Id(Long orgId);
}
AOrganizationRepository.java
#NoRepositoryBean
public interface AOrganizationRepository<T, ID extends java.io.Serializable> extends CrudRepository<T, ID> {
}
SiteServiceImpl.java
#Service
public class SiteServiceImpl implements SiteService {
#Autowired
private EntityManager entityManager;
#Autowired
private SiteRepository siteRepository;
#Override
public List<Site> getAllSites() {
Iterable<Site> sites = siteRepository.findAll();
List<Site> allSites = new ArrayList<>();
sites.forEach(allSites::add);
return allSites;
}
#Override
public List<Site> getSiteBySiteName(String siteName) {
List<Site> allSites = siteRepository.findBySiteName(siteName);
return allSites;
}
#Override
public Site updateSiteName(Long id,String siteName) {
Site site = siteRepository.findById(id).get();
if(site == null)
return null;
site.setSiteName(siteName);
siteRepository.save(site);
return site;
}
}
AOrganizationAspect.java
#Aspect
#Component
#Slf4j
public class AOrganizationAspect {
#PersistenceContext
private EntityManager entityManager;
#Pointcut("execution(public * com.harshal.springboot.springfilter.repository.AOrganizationRepository+.*(..))")
protected void aOrganizationRepositoryRepositoryMethod() {
log.info("aOrganizationRepositoryRepositoryMethod");
}
#Around(value = "aOrganizationRepositoryRepositoryMethod()")
public Object enableOwnerFilter(ProceedingJoinPoint joinPoint) throws Throwable {
// Variable holding the session
Session session = null;
try {
// Get the Session from the entityManager in current persistence context
session = entityManager.unwrap(Session.class);
// Enable the filter
Filter filter = session.enableFilter("OrgFilter");
// Set the parameter from the session
List<Long> orgList = getAllowedOrgIdList();
filter.setParameterList("allowedOrgIdList", orgList);
} catch (Exception ex) {
// Log the error
log.error("Error enabling OrgFilter : Reason -" + ex.getMessage());
}
// Proceed with the joint point
Object obj = joinPoint.proceed();
// If session was available
if (session != null) {
// Disable the filter
session.disableFilter("OrgFilter");
}
// Return
return obj;
}
private List<Long> getAllowedOrgIdList() {
return Arrays.asList(2l);
}
}
So , hibernate filters are applied if method getSiteBySiteName is called and filters are not applied if findById method is called.
Below are queries :
For getSiteBySiteName :
select site0_.id as id1_2_, site0_.org_id as org_id3_2_,
site0_.site_name as site_nam2_2_ from site site0_ where site0_.org_id
in (?) and site0_.site_name=?
Please help . Thanks in advance.
For findById
select site0_.id as id1_2_0_, site0_.org_id as org_id3_2_0_,
site0_.site_name as site_nam2_2_0_, organizati1_.id as id1_1_1_,
organizati1_.address as address2_1_1_, organizati1_.org_name as
org_name3_1_1_ from site site0_ left outer join organization
organizati1_ on site0_.org_id=organizati1_.id where site0_.id=?
findById is using the EntityManager.find method and do not create a query.
Plus Hibernate Filters only work on queries.
You should write a query instead of using findById
My Organization entity
#Entity
public class Organization implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
private String name;
private String type;
private byte image;
#OneToMany(cascade=CascadeType.MERGE)
#JoinColumn(name="ORGANIZATION_ID")
private List<User> admin;
My User entity
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Key key;
private String score;
private boolean online;
private String resume;
public Status status;
public enum Status {
ACTIVE, INACTIVE, VERIFIED, NOT_VERIFIED , BANNED
};
#ManyToOne(cascade=CascadeType.MERGE)
#JoinColumn(name="ORGANIZATION_ID")
private Organization organization;
#Persistent
private User_personal user_p;
public User_personal getUser_personal(){
return user_p;
}
public void setUser_personal(User_personal user_p) {
this.user_p = user_p;
}
#OneToMany(mappedBy = "user", cascade=CascadeType.MERGE)
private List<Project> projects;
I got the one-Many relation between User and Projects correctly but not working for User and Organization(many-one).I am getting error like this
WARNING: /OrganizationServlet
javax.persistence.PersistenceException: Detected attempt to establish
Organization(no-id-yet) as the parent of User(4793870697103360) but the
entity identified by User(4793870697103360) has already been persisted
without a parent. A parent cannot be established or changed once an object
has been persisted.at...
showing error at em.getTransaction().commit();.
My servlet is
protected void doPost(HttpServletRequest request, HttpServletResponse
response) throws ServletException, IOException {
// TODO Auto-generated method stub
HashMap<String,String> map = Request_to_map.getBody(request);
boolean validToken = JWT.parseJWT(request.getHeader("Access-token")
,map.get("email"));
JsonObject output = new JsonObject();
List<User> organization_admin = new ArrayList<User>();
if(validToken == true){
EntityManager em;
em = EMF.get().createEntityManager();
String organizationName = map.get("name");
String type = map.get("type");
byte image = 0;
if(map.get("image")!=null)
{
image = Byte.valueOf(map.get("image"));
}
String email = map.get("email");
if(organizationName==null||type==null||email==null||map.get("image")==null)
{
throw new IllegalArgumentException("please fill required
details");
}
try{
em.getTransaction().begin();
User user = User.find(email, em);
if(user!=null)
{
Organization.org_status status= org_status.ACTIVE;
Organization organization = new
Organization(organizationName, type,image,status);
user.setOrganization(organization);
organization_admin = organization.getAdmin();
if(organization_admin == null)
{
organization_admin = new ArrayList<User>();
}
organization_admin .add(user);
organization.setAdmin(organization_admin);
em.persist(organization);
em.persist(user);
output.addProperty("message", "done");
em.getTransaction().commit();
}
else
output.addProperty("message","No such User found.Please
check details provided");
}
finally{
if(em.getTransaction().isActive())
em.getTransaction().rollback();
// em.close();
}
}
else
output.addProperty(Constants.MESSAGE,
Constants.TokenNotAuthenticated);
response.setContentType("application/Json");
response.getWriter().println(output);
}
Can anyone help me in getting this? When user is created I am getting ORGANIZATION_ID as a column but cant create entity of organization.I dont think joins are to be used as GAE doesn't allow it.
I have just started with App Engine and I have tried to make a very simple app which adds Person objects with distinctive names to the datastore. This the object:
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Person {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Long id;
#Persistent
#Unique
private String name;
public Person(String nameIn){
this.name = nameIn;
}
public Long getId(){
return this.id;
}
public void setId(Long idIn){
this.id = idIn;
}
}
This servlet is responsible for persisting objects on datastore. But prior to that, the method doesUserExist(String) checks whether object with the same 'name' field exists:
#SuppressWarnings("serial")
public class PersonDatastoreServlet extends HttpServlet {
private static final String PARAM_NAME = "name";
private PersistenceManager pmf = PMF.get().getPersistenceManager();
public void doGet(HttpServletRequest req, HttpServletResponse response)
throws IOException {
String name = req.getParameter(PARAM_NAME);
PrintWriter printWriter = response.getWriter();
try{
if(!doesUserExist(name)) {
Person p = new Person(name);
pmf.makePersistent(p);
response.setContentType("text/html");
printWriter.println("<h1>"+p.getId()+"</h1>");
}
else {
response.setContentType("text/html");
printWriter.println("<p>User already exists</p>");
}
}
catch(Exception e) {
throw new IOException();
}
finally{
pmf.close();
}
}
private boolean doesUserExist(String nameIn) {
Query q = pmf.newQuery(Person.class);
q.setFilter("name == lastNameParam");
q.declareParameters("String lastNameParam");
String name = nameIn;
try{
List<Person> list = (List<Person>) q.execute(name);
if (list.isEmpty()){
return false;
}
else return true;
}
finally{
q.closeAll();
}
}
}
The take seems very straightforward, but it just not working. I have a form which processing the request. When I run my app for the first time it does successfully create and persist an object, however whenever i want to add another object with a different name, I am getting the Error
Error: Server Error
The server encountered an error and could not complete your request.
If the problem persists, please report your problem and mention this error message and the query that caused it.
It indicates that the query causes the problem but I have idea what is wrong with my query. Can anybody help please?
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
one to many relationship in java google ap engine caused error ?
i have implement a system to save information about user .
So i have aggregation at my class so the user class has list from contact class ...etc
in the first page "test it's just for register the user just by phone number " that must save the user in database but this cause error when i deploye my project in Google app engine < 500 server error >
and the other page for update the exist user who previously has been registered, so at this will add to the list which the user object has .
user class
#PersistenceCapable
public class User implements Serializable{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
public String userNumber;
#Persistent (mappedBy = "userC")
public List<Contact> UserContacts =new ArrayList<Contact>();
public void AddContact(String name,String number) {
Contact C=new Contact();
C.ContactName=name;
C.PhoneNumber=number;
this.UserContacts.add(C); }
}
Contact class
#PersistenceCapable
public class Contact implements Serializable{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
public String ContactName;
#Persistent
public String PhoneNumber;
#Persistent
public User userC; }
this page cause register for the user test will get user phone number and sign up should create new user with this number
test page
#SuppressWarnings("serial")
public class Test extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
resp.getWriter().println("<html><body><form method = \"POST\" action=\"/signup\">" + "please enter ur number :"+"<h4><label>name : <input name = \"userphoneNUMBER\" type = \"text \" size = \"25 \" /> </label>"+"<p> <input type = \"submit\" value = \"Submit\" />"+ "</form></body></html>");
}
}
this page take the number to create user
#SuppressWarnings("serial")
public class SignUP extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
String user_PhoneNumber=req.getParameter("userphoneNUMBER");
User obj = new User();
obj.userNumber=user_PhoneNumber;
resp.getWriter().println(obj.userNumber );
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(obj);
} finally {
pm.close();
} } }
this page to continue update value at user object who already exist
#SuppressWarnings("serial")
public class Testinfo extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
resp.getWriter().println("<html><body><form method = \"POST\" action=\"/saveinfo\">" +
"<center> <h2>please fill this form :</h2> </br> "+
"<h4><label> ContactName : <input name = \"ContactName\" type = \"text \" size = \"25 \" /> </label>"
+
"<p> <input type = \"submit\" value = \"Submit\" />"+
"</form></body></html>");
}
}
this page to save the information which cause error and no value will save at app engine
#SuppressWarnings("serial")
public class SaveInfo extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
String ContactName = req.getParameter("ContactName");
String ContactNumber = req.getParameter("ContactNumber");
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery("select * from " + User.class.getName());
List<User> list = (List<User>) query.execute();
for (User obj : list) {
if (obj.userNumber.equals("111")) {
pm.currentTransaction().begin();
obj.AddContact(ContactName, ContactNumber);
pm.makePersistent(obj);
pm.currentTransaction().commit(); }
}
pm.close(); } }
this 111 for testing which i entered before as user phone number .
So how can i deal with lists and aggregation issues ??
when going to update the user information this error occurred
Uncaught exception from servlet
javax.jdo.JDOUserException: Identifier expected at character 1 in "*" at org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:375)
at org.datanucleus.jdo.JDOQuery.execute(JDOQuery.java:230)
at sstooree.SaveInfo.doPost(SaveInfo.java:44)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.apphosting.utils.servlet.ParseBlobUploadFilter.doFilter(ParseBlobUploadFilter.java:102)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
by trying to change the query
from
Query query = pm.newQuery("select * from " + User.class.getName());
to
Query query = pm.newQuery("select from " + User.class.getName());
that make the code work successfully without any error :)
i have implement a system to save information about user .
So i have aggregation at my class so the user class has list from contact class ...etc
in the first page "test it's just for register the user just by phone number " that must save the user in database but this cause error when i deploye my project in Google app engine < 500 server error >
and the other page for update the exist user who previously has been registered, so at this will add to the list which the user object has .
user class
#PersistenceCapable
public class User implements Serializable{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
public String userNumber;
#Persistent (mappedBy = "userC")
public List<Contact> UserContacts =new ArrayList<Contact>();
public void AddContact(String name,String number) {
Contact C=new Contact();
C.ContactName=name;
C.PhoneNumber=number;
this.UserContacts.add(C); }
}
Contact class
#PersistenceCapable
public class Contact implements Serializable{
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
public String ContactName;
#Persistent
public String PhoneNumber;
#Persistent
public User userC; }
this page cause register for the user test will get user phone number and sign up should create new user with this number
test page
#SuppressWarnings("serial")
public class Test extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
resp.getWriter().println("<html><body><form method = \"POST\" action=\"/signup\">" + "please enter ur number :"+"<h4><label>name : <input name = \"userphoneNUMBER\" type = \"text \" size = \"25 \" /> </label>"+"<p> <input type = \"submit\" value = \"Submit\" />"+ "</form></body></html>");
}
}
this page take the number to create user
#SuppressWarnings("serial")
public class SignUP extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
String user_PhoneNumber=req.getParameter("userphoneNUMBER");
User obj = new User();
obj.userNumber=user_PhoneNumber;
resp.getWriter().println(obj.userNumber );
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(obj);
} finally {
pm.close();
} } }
this page to continue update value at user object who already exist
#SuppressWarnings("serial")
public class Testinfo extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/html");
resp.getWriter().println("<html><body><form method = \"POST\" action=\"/saveinfo\">" +
"<center> <h2>please fill this form :</h2> </br> "+
"<h4><label> ContactName : <input name = \"ContactName\" type = \"text \" size = \"25 \" /> </label>"
+
"<p> <input type = \"submit\" value = \"Submit\" />"+
"</form></body></html>");
}
}
this page to save the information which cause error and no value will save at app engine
#SuppressWarnings("serial")
public class SaveInfo extends HttpServlet {
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
String ContactName = req.getParameter("ContactName");
String ContactNumber = req.getParameter("ContactNumber");
PersistenceManager pm = PMF.get().getPersistenceManager();
Query query = pm.newQuery("select from " + User.class.getName());
List<User> list = (List<User>) query.execute();
for (User obj : list) {
if (obj.userNumber.equals("111")) {
pm.currentTransaction().begin();
obj.AddContact(ContactName, ContactNumber);
pm.makePersistent(obj);
pm.currentTransaction().commit(); }
}
pm.close(); } }
this 111 for testing which i entered before as user phone number .
So how can i deal with lists and aggregation issues ??
when going to update the user information this error occurred
Uncaught exception from servlet
javax.jdo.JDOUserException: Identifier expected at character 1 in "*" at org.datanucleus.jdo.NucleusJDOHelper.getJDOExceptionForNucleusException(NucleusJDOHelper.java:375)
at org.datanucleus.jdo.JDOQuery.execute(JDOQuery.java:230)
at sstooree.SaveInfo.doPost(SaveInfo.java:44)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
at com.google.apphosting.utils.servlet.ParseBlobUploadFilter.doFilter(ParseBlobUploadFilter.java:102)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
the problem in the query
change this
Query query = pm.newQuery("select from " + User.class.getName());
to
Query query = pm.newQuery("select * from " + User.class.getName());
you are not selecting any column . which cause a sql syntax error