How to join non primary key in google app engine - java

How to get data of non primary key column userId using java in google app engine
List<UserAddress> list = (List<UserAddress>) pmf.getObjectById(UserAddress.class, Long.valueOf(userId));
System.out.println(list.size());
When I fetch the data the following error occur in console
NestedThrowablesStackTrace:
Could not retrieve entity of kind UserAddress with key UserAddress(4)
org.datanucleus.exceptions.NucleusObjectNotFoundException: Could not retrieve entity of kind UserAddress with key UserAddress(4)
Tried below code also, to fetch the data of non primary key column userId but it shows empty list.
#SuppressWarnings("unchecked")
public List<UserAddress> getUserAddressFind(String userId) {
List<UserAddress> returnList = new ArrayList<UserAddress>();
PersistenceManager pmf = PMF.get().getPersistenceManager();
try {
Query query = pmf.newQuery(UserAddress.class);
query.setFilter("userId == userIdParam");
query.declareParameters("Long userIdParam");
returnList = (List<UserAddress>) query.execute(userId);
System.out.println(returnList.size());
if (returnList != null && returnList.isEmpty()) {
System.out.println("No results for userAddresses");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
pmf.close();
}
return returnList;
}
UserAddress.java
package com.rrd.up2me.datastore;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
#PersistenceCapable(identityType = IdentityType.APPLICATION)
public class UserAddress {
#PrimaryKey
#Persistent(valueStrategy = IdGeneratorStrategy.SEQUENCE)
private Long userAddressId;
#Persistent
private Long userId;
#Persistent
private Long addressId;
#Persistent
private Boolean isPrimary;
public Long getUserAddressId() {
return userAddressId;
}
public void setUserAddressId(Long userAddressId) {
this.userAddressId = userAddressId;
}
public Long getUserId() {
return userId;
}
public void setUserId(Long userId) {
this.userId = userId;
}
public Long getAddressId() {
return addressId;
}
public void setAddressId(Long addressId) {
this.addressId = addressId;
}
public Boolean getIsPrimary() {
return isPrimary;
}
public void setIsPrimary(Boolean isPrimary) {
this.isPrimary = isPrimary;
}
}

In UserAddress.java class userId is long when execute the query passed variable type is Stringso data is not fetching. AfterType cast the userId String to Long problem solved.
Ex: Long.valueOf(userId).
Query query = pmf.newQuery(UserAddress.class);
query.setFilter("userId == userIdParam");
query.declareParameters("Long userIdParam");
returnList = (List<UserAddress>) query.execute(Long.valueOf(userId));
System.out.println(returnList.size());

Related

Hibernate: How to join a table with a column which is not a foreign key

I'm trying to create a OneToOne relation between tartikel and teigenschaft with the primary key kArtikel in tartikel. The code snippet in TArtikelEntity:
#OneToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "kArtikel", referencedColumnName="kArtikel")
public TeigenschaftEntity getTeigenschaftEntity() {
return teigenschaftEntity;
}
public void setTeigenschaftEntity(TeigenschaftEntity teigenschaftEntity) {
this.teigenschaftEntity = teigenschaftEntity;
}
The complete entity of teigenschaft:
#Entity
#Table(name = "teigenschaft", schema = "dbo", catalog = "Mandant_EinsZwei")
public class TeigenschaftEntity {
private int kEigenschaft;
private int kArtikel;
private String cWaehlbar;
private Integer nSort;
private String cTyp;
private String cAktiv;
#Id
#Column(name = "kEigenschaft")
public int getkEigenschaft() {
return kEigenschaft;
}
public void setkEigenschaft(int kEigenschaft) {
this.kEigenschaft = kEigenschaft;
}
#Basic
#Column(name = "kArtikel")
public int getkArtikel() {
return kArtikel;
}
public void setkArtikel(int kArtikel) {
this.kArtikel = kArtikel;
}
#Basic
#Column(name = "cWaehlbar")
public String getcWaehlbar() {
return cWaehlbar;
}
public void setcWaehlbar(String cWaehlbar) {
this.cWaehlbar = cWaehlbar;
}
#Basic
#Column(name = "nSort")
public Integer getnSort() {
return nSort;
}
public void setnSort(Integer nSort) {
this.nSort = nSort;
}
#Basic
#Column(name = "cTyp")
public String getcTyp() {
return cTyp;
}
public void setcTyp(String cTyp) {
this.cTyp = cTyp;
}
#Basic
#Column(name = "cAktiv")
public String getcAktiv() {
return cAktiv;
}
public void setcAktiv(String cAktiv) {
this.cAktiv = cAktiv;
}
}
Here is where I'm getting the NullPointerException (Line 4):
session.beginTransaction();
TArtikelEntity tArtikelEntity = session.get(TArtikelEntity.class, 189820);
System.out.println(tArtikelEntity.toString());
System.out.println(tArtikelEntity.getTeigenschaftEntity().getkEigenschaft()+" <---- kEigenschaft");
session.getTransaction().commit();
I located the problem in the second query. It's not using kArtikel but kEigenschaft (the primary key of teigenschaft):
select teigenscha0_.kEigenschaft as kEigensc1_12_0_, teigenscha0_.cAktiv as cAktiv2_12_0_, teigenscha0_.cTyp as cTyp3_12_0_, teigenscha0_.cWaehlbar as cWaehlba4_12_0_, teigenscha0_.kArtikel as kArtikel5_12_0_, teigenscha0_.nSort as nSort6_12_0_ from Mandant_EinsZwei.dbo.teigenschaft teigenscha0_ where teigenscha0_.kEigenschaft=?|select teigenscha0_.kEigenschaft as kEigensc1_12_0_, teigenscha0_.cAktiv as cAktiv2_12_0_, teigenscha0_.cTyp as cTyp3_12_0_, teigenscha0_.cWaehlbar as cWaehlba4_12_0_, teigenscha0_.kArtikel as kArtikel5_12_0_, teigenscha0_.nSort as nSort6_12_0_ from Mandant_EinsZwei.dbo.teigenschaft teigenscha0_ where teigenscha0_.kEigenschaft=189820
But how can that be? I mentioned the JoinColumn in TArtikelEntity to kArtikel. Why is it not using kArtikel but kEigenschaft?
Null pointer exception isn't due to join. It's because you are converting a null object to string.
try this :
System.out.println(tArtikelEntity==null?null:tArtikelEntity.toString());

Spring Data JPA - Get the values of a non-entity column of a custom native query

I am using Spring Boot/MVC.
I have a custom query using JpaRepository:
public interface WorkOrderRepository extends JpaRepository<WorkOrder, Integer> {
#Query(value = "SELECT * FROM (SELECT * FROM workorder) Sub1 INNER JOIN (SELECT wo_number, GROUP_CONCAT(service_type SEPARATOR ', ') AS 'service_types' FROM service_type GROUP BY wo_number) Sub2 ON Sub1.wo_number=Sub2.wo_number WHERE fleet_company_id=?1 AND (order_status='On-Bidding' OR order_status='Draft')", nativeQuery = true)
Collection<WorkOrder> findWorkOrdersByFleet(Long fleetCompanyID);
}
It returns the following table:
http://imgur.com/Ylkc6U0
As you can see it has service_types columns which is a result of Concat, it's not part of the entity class. My problem is how can I get the value of that column. Some said I can use a separate DTO to map the service_types column? Or I can use 'new' keyword? Maybe you have other worked on me. I also tried to make a transient column service_types but it didn't work.
This is my entity class:
#Entity
#Table(name="workorder")
public class WorkOrder {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name="wo_number")
private Long woNumber;
#ManyToOne(optional=false, cascade=CascadeType.ALL)
#JoinColumn(name = "vehicle_id")
private Vehicle vehicle;
#ManyToOne(optional=false, cascade=CascadeType.ALL)
#JoinColumn(name = "fleet_company_id")
private FleetCompany fleetCompany;
#Column(name="order_title")
private String orderTitle;
#Column(name="order_date")
private String orderDate;
#Column(name="order_time")
private String orderTime;
#Column(name="order_status")
private String orderStatus;
#Column(name="ref_number")
private String refNumber;
#Column(name="proposals")
private int proposals;
//#Column(name="serviceTypes")
#Transient
private int serviceTypes;
public WorkOrder() {
super();
}
public Long getWoNumber() {
return woNumber;
}
public void setWoNumber(Long woNumber) {
this.woNumber = woNumber;
}
public String getOrderTitle() {
return orderTitle;
}
public void setOrderTitle(String orderTitle) {
this.orderTitle = orderTitle;
}
public String getOrderDate() {
return orderDate;
}
public void setOrderDate(String orderDate) {
this.orderDate = orderDate;
}
public String getOrderTime() {
return orderTime;
}
public void setOrderTime(String orderTime) {
this.orderTime = orderTime;
}
public String getOrderStatus() {
return orderStatus;
}
public void setOrderStatus(String orderStatus) {
this.orderStatus = orderStatus;
}
public String getRefNumber() {
return refNumber;
}
public void setRefNumber(String refNumber) {
this.refNumber = refNumber;
}
public int getProposals() {
return proposals;
}
public void setProposals(int proposals) {
this.proposals = proposals;
}
public Vehicle getVehicle() {
return vehicle;
}
public void setVehicle(Vehicle vehicle) {
this.vehicle = vehicle;
}
public FleetCompany getFleetCompany() {
return fleetCompany;
}
public void setFleetCompany(FleetCompany fleetCompany) {
this.fleetCompany = fleetCompany;
}
public int getServiceTypes() {
return serviceTypes;
}
public void setServiceTypes(int serviceTypes) {
this.serviceTypes = serviceTypes;
}
}
Some people told me to make a DTO:
public class WorkOrderDTO extends WorkOrder {
private String service_types;
public WorkOrderDTO() {
super();
}
public WorkOrderDTO(String service_types) {
this.service_types = service_types;
}
public String getService_types() {
return service_types;
}
public void setService_types(String service_types) {
this.service_types = service_types;
}
}
and add make the repository replaced from WorkOrder to WorkOrderDTO.
public interface WorkOrderRepository extends JpaRepository<WorkOrderDTO, Integer>
but when I do that I have autowiring problems.
I solved my own problem, finally!!!
I used #SqlResultMapping
SqlResultSetMapping(
name="workorder",
classes={
#ConstructorResult(
targetClass=WorkOrderDTO.class,
columns={
#ColumnResult(name="wo_number", type = Long.class),
#ColumnResult(name="service_types", type = String.class),
#ColumnResult(name="order_title", type = String.class)
}
)
}
)
And I created a new POJO that is not an entity named WorkOrderDTO.
#PersistenceContext
private EntityManager em;
#Override
public Collection<WorkOrderDTO> getWork() {
Query query = em.createNativeQuery(
"SELECT Sub1.wo_number, Sub2.service_types, Sub1.order_title FROM (SELECT * FROM workorder) Sub1 INNER JOIN (SELECT wo_number, GROUP_CONCAT(service_type SEPARATOR ', ') AS 'service_types' FROM service_type GROUP BY wo_number) Sub2 ON Sub1.wo_number=Sub2.wo_number WHERE fleet_company_id=4 AND (order_status='On-Bidding' OR order_status='Draft')", "workorder");
#SuppressWarnings("unchecked")
Collection<WorkOrderDTO> dto = query.getResultList();
Iterable<WorkOrderDTO> itr = dto;
return (Collection<WorkOrderDTO>)itr;
}
At last, the users who hated me for posting the same problem won't be annoyed anymore.

detached entity passed to persist for batch insert in JPA

For the following batch insert method, i get this exception "detached entity passed to persist". Could you take a look at this method and give me some hints?
Thank you so much.
if needed, I will provided the entities here, for the moment I provide Keyword entity :
public class Keyword implements Serializable {
private static final long serialVersionUID = -1429681347817644570L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="key_id")
private long keyId;
#Column(name="key_name")
private String keyName;
#ManyToOne
#JoinColumn(name="tweet_id")
private Tweet tweet;
public long getKeyId() {
return keyId;
}
public void setKeyId(long keyId) {
this.keyId = keyId;
}
public String getKeyName() {
return keyName;
}
public void setKeyName(String keyName) {
this.keyName = keyName;
}
public Tweet getTweet() {
return tweet;
}
public void setTweet(Tweet tweet) {
this.tweet = tweet;
}
}
Here Tweet Entity :
#Entity
#Table(name="tweets")
public class Tweet implements Serializable{
#Id
#Column(name="tweet_id")
private long tweetId;
#Column(name="tweet_text")
private String tweetText;
#Temporal(TemporalType.TIMESTAMP)
#Column(name = "created_at")
private Date createdAt;
#Column(name="lang_code")
private String languageCode;
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#OneToMany(mappedBy="tweet")
//#JoinColumn(name="hashtag_id")
private List<Hashtag> hashtags;
#OneToMany(mappedBy="tweet")
//#JoinColumn(name="url_id")
private List<Url> urls;
public List<Keyword> getKeywords() {
return keywords;
}
public void setKeywords(List<Keyword> keywords) {
this.keywords = keywords;
}
#OneToMany(mappedBy="tweet")
//#JoinColumn(name="url_id")
private List<Keyword> keywords;
public long getTweetId() {
return tweetId;
}
public void setTweetId(long tweetId) {
this.tweetId = tweetId;
}
public String getTweetText() {
return tweetText;
}
public void setTweetText(String tweetText) {
this.tweetText = tweetText;
}
public Date getCreatedAt() {
return createdAt;
}
public void setCreatedAt(Date createdAt) {
this.createdAt = createdAt;
}
public String getLanguageCode() {
return languageCode;
}
public void setLanguageCode(String languageCode) {
this.languageCode = languageCode;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<Hashtag> getHashtags() {
return hashtags;
}
public void setHashtags(List<Hashtag> hashtags) {
this.hashtags = hashtags;
}
public List<Url> getUrls() {
return urls;
}
public void setUrls(List<Url> urls) {
this.urls = urls;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + (int) (tweetId ^ (tweetId >>> 32));
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tweet other = (Tweet) obj;
if (tweetId != other.tweetId)
return false;
return true;
}
And here Url entity :
#Entity
#Table(name="tweet_url")
public class Url implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="url_id")
private int urlId;
#Column(name="url")
private String url;
#ManyToOne
#JoinColumn(name="tweet_id",referencedColumnName="tweet_id")
private Tweet tweet;
public int getUrlId() {
return urlId;
}
public void setUrlId(int urlId) {
this.urlId = urlId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Tweet getTweet() {
return tweet;
}
public void setTweet(Tweet tweet) {
this.tweet = tweet;
}
And here is hashtag entity :
#Entity
#Table(name="tweet_hashtag")
public class Hashtag implements Serializable{
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="hashtag_id")
private int hashtagId;
#Column(name="hashtag")
private String hashtag;
#ManyToOne
#JoinColumn(name="tweet_id",referencedColumnName="tweet_id")
private Tweet tweet;
public int getHashtagId() {
return hashtagId;
}
public void setHashtagId(int hashtagId) {
this.hashtagId = hashtagId;
}
public String getHashtag() {
return hashtag;
}
public void setHashtag(String hashtag) {
this.hashtag = hashtag;
}
public Tweet getTweet() {
return tweet;
}
public void setTweet(Tweet tweet) {
this.tweet = tweet;
}
And the method :
public void batchInsert(List<Keyword> results) throws HibernateException {
// chekeywordck if key exists
// try {
em=RunQuery.emf.createEntityManager();
em.getTransaction().begin();
for(Keyword result:results)
{
try{
em.persist(result.getTweet().getUser());
}
catch(ConstraintViolationException ce)
{
System.out.print("duplicated insert catched");
}
try{
em.persist(result.getTweet());
}
catch(ConstraintViolationException ce)
{
System.out.print("duplicated insert catched");
}
if(result.getTweet().getHashtags()!=null)
for(Hashtag hashtag:result.getTweet().getHashtags())
em.persist(hashtag);
if(result.getTweet().getUrls()!=null)
for(Url url:result.getTweet().getUrls())
em.persist(url);
em.persist(result);
em.flush();
em.clear();
//when I put these two line out of this loop, it still is the same.
}
em.getTransaction().commit();
// }
}
And here is the exception :
Exception in thread "Thread-3" javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: model.twitter.entities.Url
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
at model.service.QueryResultService.batchInsert(QueryResultService.java:74)
at controller.ResultsController.save(ResultsController.java:125)
at controller.ResultsController.parse(ResultsController.java:89)
at main.TwitterStreamConsumer.run(TwitterStreamConsumer.java:41)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: model.twitter.entities.Url
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
... 5 more
To answer your question: your model defines a one-to-many relationship between Tweet and URL without any cascading. When you are passing a Tweet instance for persisting, the URL objects have not yet been saved and your model does not mandate Tweet to cascade the persist operation to the URL instances. Therefore it can not create the relationship with them.
Cascading tells the hibernate, how to execute DB operations on related entities.
You can instruct it to pass/cascade the persist operation to the related entity, to cascade all operations or an array of operations.
That being said, your problem(1 of them) could be fixed if you modify the relationship with cascading info:
#OneToMany(mappedBy="tweet", cascade={CascadeType.PERSIST})
private List<Url> urls;
But your sample indicates other possible issues and I would encourage you to spent some more time reading Hibernate ORM documentation and practicing on sample model with less relationships.
One of the obvious issues seems to be the lack of understanding of relationship owner concept.
For example, in your Tweet-to-Url relationship, URL is the relationship owner(responsible for managing the relationship, e.g. managing the link via foreign key)
Please consult hibernate docs or one of hundreds of similar questions here on SO for more info.
Depending on how you fill the data, it is possible that you will run into constraint issues, or your entities will not be linked together, because you are not saving the owning side.
Also using try/catch for constraint violations is a very bad way of detecting duplicated entries. ConstraintViolationException can be have many causes and the reason you are getting them is related to the above mentioned relationship mapping issues.
ORM is complex subject and it is really beneficial to start with smaller examples, trying to understand the framework mechanics before moving to the more challenging models. Good Luck
For all the persist calls try using this instead:
if(result.getTweet().getUser().getId() == null) {
em.persist(result.getTweet().getUser());
} else {
result.getTweet().setUser(em.merge(result.getTweet().getUser()));
}
if(result.getTweet().getId() == null) {
em.persist(result.getTweet());
} else {
result.setTweet(em.merge(result.getTweet()));
}
if(result.getId() == null) {
em.persist(result);
} else {
result = em.merge(result);
}

app engine endpoint return 503 error while listing all the entities

I am trying to get list of all my entities from the data store in app engine. i created my class and generate the app engine endpoint class. All the apis seems to work except the list all my entities. It returns 503 error mesage. here is my class following by app engine endpoint class. I appriciat if you can tell me where is the problem:
package com.example.placeits;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;
import com.google.appengine.datanucleus.annotations.Unowned;
#PersistenceCapable
public class PlaceIt {
#PrimaryKey
private long id;
#Persistent
private String title;
#Persistent
private double longit;
#Persistent
private double latit;
#Persistent
private String description;
#Persistent
private int onSchedule;
#Persistent
private String status;
#Persistent
private int schedule=0;
#Persistent
private String cat0;
#Persistent
private String cat1;
#Persistent
private String cat2;
#Persistent
private Boolean iscategory;
#Persistent
#Unowned
private User userName;
public String getCat0() {
return cat0;
}
public void setCat0(String cat0) {
this.cat0 = cat0;
}
public String getCat1() {
return cat1;
}
public void setCat1(String cat1) {
this.cat1 = cat1;
}
public String getCat2() {
return cat2;
}
public void setCat2(String cat2) {
this.cat2 = cat2;
}
public void palceit()
{
id = getId();
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public double getLongit() {
return longit;
}
public void setLongit(double longit) {
this.longit = longit;
}
public double getLatit() {
return latit;
}
public void setLatit(double latit) {
this.latit = latit;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getOnSchedule() {
return onSchedule;
}
public void setOnSchedule(int l) {
this.onSchedule = l;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getSchedule() {
return schedule;
}
public void setSchedule(int schedule) {
this.schedule = schedule;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getUserName() {
return userName.getUsername();
}
public void setUserName(String name) {
userName = new User();
userName.setUsername(name);
}
public Boolean getIscategory() {
return iscategory;
}
public void setIscategory(Boolean iscategory) {
this.iscategory = iscategory;
}
}
And the app engine class is:
package com.example.placeits;
import com.example.placeits.PMF;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiMethod;
import com.google.api.server.spi.config.ApiNamespace;
import com.google.api.server.spi.response.CollectionResponse;
import com.google.appengine.api.datastore.Cursor;
import com.google.appengine.datanucleus.query.JDOCursorHelper;
import java.util.HashMap;
import java.util.List;
import javax.annotation.Nullable;
import javax.inject.Named;
import javax.persistence.EntityExistsException;
import javax.persistence.EntityNotFoundException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
#Api(name = "placeitendpoint", namespace = #ApiNamespace(ownerDomain = "example.com", ownerName = "example.com", packagePath = "placeits"))
public class PlaceItEndpoint {
/**
* This method gets the entity having username. It uses HTTP GET method.
*
* #param username.
* #return placeitlist.
*/
#ApiMethod(name = "getPlaceItForUser")
public List<PlaceIt> getPlaceItForUser(#Named("username") String username,
#Nullable #Named("limit") Integer limit) {
PersistenceManager mgr = null;
List<PlaceIt> execute = null;
try {
mgr = getPersistenceManager();
Query query = mgr.newQuery(PlaceIt.class);
query.setFilter("userName ==" +username);
execute = (List<PlaceIt>) query.execute();
// Tight loop for fetching all entities from datastore and accomodate
// for lazy fetch.
for (PlaceIt obj : execute)
;
} finally {
mgr.close();
}
return execute;
}
/**
* This method lists all the entities inserted in datastore.
* It uses HTTP GET method and paging support.
*
* #return A CollectionResponse class containing the list of all entities
* persisted and a cursor to the next page.
*/
#SuppressWarnings({ "unchecked", "unused" })
#ApiMethod(name = "listPlaceIt")
public CollectionResponse<PlaceIt> listPlaceIt(
#Nullable #Named("cursor") String cursorString,
#Nullable #Named("limit") Integer limit) {
PersistenceManager mgr = null;
Cursor cursor = null;
List<PlaceIt> execute = null;
try {
mgr = getPersistenceManager();
Query query = mgr.newQuery(PlaceIt.class);
if (cursorString != null && cursorString != "") {
cursor = Cursor.fromWebSafeString(cursorString);
HashMap<String, Object> extensionMap = new HashMap<String, Object>();
extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
query.setExtensions(extensionMap);
}
if (limit != null) {
query.setRange(0, limit);
}
execute = (List<PlaceIt>) query.execute();
cursor = JDOCursorHelper.getCursor(execute);
if (cursor != null)
cursorString = cursor.toWebSafeString();
// Tight loop for fetching all entities from datastore and accomodate
// for lazy fetch.
for (PlaceIt obj : execute)
;
} finally {
mgr.close();
}
return CollectionResponse.<PlaceIt> builder().setItems(execute)
.setNextPageToken(cursorString).build();
}
/**
* This method gets the entity having primary key id. It uses HTTP GET method.
*
* #param id the primary key of the java bean.
* #return The entity with primary key id.
*/
#ApiMethod(name = "getPlaceIt")
public PlaceIt getPlaceIt(#Named("id") Long id) {
PersistenceManager mgr = getPersistenceManager();
PlaceIt placeit = null;
try {
placeit = mgr.getObjectById(PlaceIt.class, id);
} finally {
mgr.close();
}
return placeit;
}
/**
* This inserts a new entity into App Engine datastore. If the entity already
* exists in the datastore, an exception is thrown.
* It uses HTTP POST method.
*
* #param placeit the entity to be inserted.
* #return The inserted entity.
*/
#ApiMethod(name = "insertPlaceIt")
public PlaceIt insertPlaceIt(PlaceIt placeit) {
PersistenceManager mgr = getPersistenceManager();
try {
if (containsPlaceIt(placeit)) {
throw new EntityExistsException("Object already exists");
}
mgr.makePersistent(placeit);
} finally {
mgr.close();
}
return placeit;
}
/**
* This method is used for updating an existing entity. If the entity does not
* exist in the datastore, an exception is thrown.
* It uses HTTP PUT method.
*
* #param placeit the entity to be updated.
* #return The updated entity.
*/
#ApiMethod(name = "updatePlaceIt")
public PlaceIt updatePlaceIt(PlaceIt placeit) {
PersistenceManager mgr = getPersistenceManager();
try {
if (!containsPlaceIt(placeit)) {
throw new EntityNotFoundException("Object does not exist");
}
mgr.makePersistent(placeit);
} finally {
mgr.close();
}
return placeit;
}
/**
* This method removes the entity with primary key id.
* It uses HTTP DELETE method.
*
* #param id the primary key of the entity to be deleted.
*/
#ApiMethod(name = "removePlaceIt")
public void removePlaceIt(#Named("id") Long id) {
PersistenceManager mgr = getPersistenceManager();
try {
PlaceIt placeit = mgr.getObjectById(PlaceIt.class, id);
mgr.deletePersistent(placeit);
} finally {
mgr.close();
}
}
private boolean containsPlaceIt(PlaceIt placeit) {
PersistenceManager mgr = getPersistenceManager();
boolean contains = true;
try {
mgr.getObjectById(PlaceIt.class, placeit.getId());
} catch (javax.jdo.JDOObjectNotFoundException ex) {
contains = false;
} finally {
mgr.close();
}
return contains;
}
private static PersistenceManager getPersistenceManager() {
return PMF.get().getPersistenceManager();
}
}
I had this problem because Eclipse AGE generates the listmethod as POST, then I care that method doing it a Get, then the client does not need send any post argument. That work for me. Some like this:
#ApiMethod(name = "listPlaceIt",httpMethod = HttpMethod.GET)
public CollectionResponse<PlaceIt> listPlaceIt(
#Nullable #Named("cursor") String cursorString,
#Nullable #Named("limit") Integer limit) {
}

Can not read embedded objects with JDO on App Engine

I have two simple Pojos User and Rating. User has an embedded list of ratings.
The classes are annoted with #PersistenceCapable and the proprties with #Persistent.
I wrote a simple test that creates a User, sets ratings and persists it with
PersistenceManager pm = PMF.get().getPersistenceManager();
pm.makePersistent(user);
When I fetch the object like this ratings is null (not as I expected):
User user = (User) pm.getObjectById(User.class, key);
I tried some things to solve the problem:
When I annote the property ratings in User with #Persistent(defaultFetchGroup = "true") the list contains an object with a key, parentkey etc. but the value is never set (resulting in 0.0 instead of the actual value).
I could solve the problem by additionally setting a transaction before persisting the data:
pm.currentTransaction().begin();
pm.makePersistent(user);
pm.currentTransaction().commit();
So finally it works with the annotation and the transaction. But why is it?
The behaviour is the same in local unit tests (with the test helper), dev mode and deployed on app engine.
I am using App Engine SDK 1.8.1.
For reference here are User, Rating and the test:
#PersistenceCapable
public class User {
#PrimaryKey
#Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
private Key key;
// if added ratings is fetched
#Persistent(defaultFetchGroup = "true")
private List<Rating> ratings;
public Key getKey() {
return key;
}
public void setKey(Key key) {
this.key = key;
}
public List<Rating> getRatings() {
return ratings;
}
public void setRatings(List<Rating> ratings) {
this.ratings = ratings;
}
}
#PersistenceCapable
public class Rating {
#PrimaryKey
#Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
private Key key;
#Persistent
private double rating;
public Key getKey() {
return key;
}
public void setKey(Key key) {
this.key = key;
}
public double getRating() {
return rating;
}
public void setRating(double rating) {
this.rating = rating;
}
}
#Test
public void testFindByIdWithExistingKey() throws DaoException {
User user = new User();
List<Rating> ratings = new ArrayList<Rating>();
Rating rating = new Rating();
rating.setRating(1.2);
ratings.add(rating);
user.setRatings(ratings);
Key key = persist(user);
User user2 = dao.findById(key);
Assert.assertEquals(1.2, user2.getRatings().get(0).getRating(), 0.0001);
}
private Key persist(User user) {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
//pm.currentTransaction().begin();
pm.makePersistent(user);
//pm.currentTransaction().commit();
return user.getKey();
} finally {
pm.close();
}
}
#Override
public User findById(Key key) throws DaoException {
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
User user = (User) pm.getObjectById(User.class, key);
return user;
} catch (RuntimeException e) {
throw new DaoException("could not find user", e);
} finally {
pm.close();
}
}

Categories