I'm facing some problems trying to remove an entity from the database. I have an interface to abstract the AppEngine Entity from my business Object. I can easily Insert and Update, but when I try to delete I got the error:
java.lang.UnsupportedOperationException: Non-owned relationships are
not currently supported at
org.datanucleus.store.appengine.DatastoreFKListStoreSpecialization.clearWit houtDelete(DatastoreFKListStoreSpecialization.java:
123)
at org.datanucleus.sco.backed.List.clear(List.java:817)
at
org.datanucleus.store.mapped.mapping.CollectionMapping.preDelete(Collection Mapping.java:
299)
at
org.datanucleus.store.appengine.DependentDeleteRequest.execute(DependentDel eteRequest.java:
71)
...
I got the interface ...
public interface ICompany extends IEntityBean {
// Getters
public List<IUser> getUsers();
public List<IDepartment> getDepartments();
public ICurrency getCurrency() throws Exception;
}
... the implementation ...
public class GAECompany extends GAEEntityBean implements ICompany {
#Override
#OneToMany(mappedBy = "company")
public List<IUser> getUsers() {
return this.users;
}
#Override
#OneToMany(mappedBy = "company")
public List<IDepartment> getDepartments() {
return this.departments;
}
#Transient
public ICurrency getCurrency() throws Exception {
return this.currency;
}
}
and the code to remove...
// Get the entity manager
EntityManager em = this.getDBManager();
IEntityBean persistent = em.find(obj.getClass(), obj.getId());
em.remove(persistent);
em.flush();
I don't have any dependent objects I've just created an Company and now I'm trying to delete it. I assumed the mapping is right cause I'm able to INSERT an UPDATE the
company. but not REMOVE!
Am I doing something wrong??
Solved!
I just updated the version of Google JDO/JPA to 2.0 and it works well!
Related
Hibernate and trying to build simple feature where we can search Product by Id. Hibernate has inbuit function to search an entity by its id. I tried the same but i am getting "java.lang.NoSuchMethodException" .
MyController.java :
#GetMapping(value = "/getProducts/{id}" , produces ="application/json")
public ResponseEntity<Product> display(#PathVariable int id) {
Product products = productServiceImp.getAllProducts(id);
return ResponseEntity.ok(products);
MyProductServiceImp:
#Override
public Product getAllProducts(int product_id ) {
return productRepository.getById(product_id );
}
MyProductRepository:
#Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
}
Schema of Product table : (product_id, desciption,display_name, qty, amount)
When i try to invoke API by postman
curl --location --request GET 'http://localhost:8080/admin/getProducts/1.
I see it is Caused by: java.lang.NoSuchMethodException: com.Project.OrderProcessing.OrderProcessing.Entity.Product$HibernateProxy$zAdAYVvM.<init>().I am unable to understand reason behind it
Try findById since getById is deprecated. Untested, but something like:
MyProductServiceImp:
#Override
public Optional<Product> findById(Integer productId) {
return productRepository.findById(productId);
}
Product.java
#Entity //make sure this is present
#Getter //from Lombok
#Setter //from Lombok
public class Product {
#Id //need this
#GeneratedValue //need this to auto-generate
private Integer id;
private String description;
//the rest: displayName, quantity, amount...
}
Your #Repository interface looks fine. There are different variations for your controller depending on what you need to do. But for now, just try calling your service method so you know you get the result back from the DB and work from there.
Camel-case your variables in general for consistency. Then you can use the Spring conventions in interfaces for repositories so your method could look like findAllByDisplayName() instead of findAllByDisplay_Name() and Spring will handle the query for you.
Also note that presumably, you're not getting all products with one product ID, right? So it should just be called getProduct or findProduct or getProductById or findProductById.
MyControllerClass:
#RequestMapping("/admin")
#RestController
public class ProductController {
#GetMapping(value = "/getProducts/{id}" , produces ="application/json")
public Optional<Product> display(#PathVariable int id) {
Optional<Product> products = productServiceImp.getProductDetailsbyID(id);
return products;
}
}
MyProductServiceImp :
#Override
public Optional<Product> getProductDetailsbyID(int product_id ) {
Optional<Product> prodresult=productRepository.findById(product_id);
return prodresult;
}
I have used FindbyID in place of GetById and it worked !!
I have next error: nested exception is org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.Model.entities, could not initialize proxy - no Session
My Model entity:
class Model {
...
#OneToMany(fetch = FetchType.LAZY, mappedBy = "model", orphanRemoval = true)
#Cascade(CascadeType.ALL)
#Fetch(value = FetchMode.SUBSELECT)
public Set<Entity> getEntities() {
return entities;
}
public void addEntity(Entity entity) {
entity.setModel(this);
entities.add(entity);
}
}
And I have a service class:
#Service
#Transactional
class ServiceImpl implements Service {
#Override
public void process(Model model) {
...
model.addEntity(createEntity());
...
}
}
I'm calling service from another service method:
#Override
#JmsListener(destination = "listener")
public void handle(final Message message) throws Exception {
Model model = modelService.getById(message.getModelId());
serviceImpl.process(model);
modelService.update(model);
}
But when I'm trying to call this method I'm getting exception on line entities.add(entity); also the same exception occurs when I'm calling getEntities() on model .
I've checked transaction manager and it's configured correctly and transaction exists on this step. Also I've checked tons of answers on stackoverflow connected to this exception but nothing useful.
What could be the cause of it?
It seems that model is a detached entity.
Try to merge and perform operations on a merge instance:
#Override
public void process(Model model) {
...
Model mergedModel = session.merge(model);
mergedModel.addEntity(createEntity());
...
}
So as #Maciej Kowalski mentioned after first #Transactional read of my model it's already in deatached state and call to get entities from another #Transactional method failed with LazyInitializationException.
I've changed my service a bit to get model from database in the same transaction:
#Service
#Transactional
class ServiceImpl implements Service {
#Override
public void process(long modelId) {
...
Model model = modelDao.get(modelId);
model.addEntity(createEntity());
...
}
}
Now everything works as expected.
I get an javax.persistence.EntityNotFoundException from the following code:
#Transactional
public ManagementEmailConfig save(ManagementEmailConfig managementEmailConfig)
{
logger.info("Save Management Email Config");
try
{
managementEmailConfig = entityManager.merge(managementEmailConfig);
entityManager.flush();
} catch (Exception e)
{
//ERROR: com.xxx.app.dao.kpi.ManagementEmailConfigDAO -
Not able to save Management Email Config
//javax.persistence.EntityNotFoundException: Unable to find com.xxx.app.model.configuration.AlertCommunicationAddress with id 1260
logger.error("Not able to save Management Email Config", e);
return null;
}
return managementEmailConfig;
}
where the model looks like this (shortened version):
import java.io.Serializable;
import javax.persistence.*;
import java.util.List;
/**
* The persistent class for the MANAGEMENT_EMAIL_CONFIG database table.
*
*/
#Entity
#Table(name="MANAGEMENT_EMAIL_CONFIG")
#NamedQuery(name="ManagementEmailConfig.findAll", query="SELECT m FROM ManagementEmailConfig m")
public class ManagementEmailConfig implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name="MANAGEMENT_EMAIL_CONFIG_ID")
private long managementEmailConfigId;
//bi-directional many-to-one association to AlertCommunicationAddress
#OneToMany(mappedBy="managementEmailConfig")
private List<AlertCommunicationAddress> alertCommunicationAddresses;
public ManagementEmailConfig() {
}
public long getManagementEmailConfigId() {
return this.managementEmailConfigId;
}
public void setManagementEmailConfigId(long managementEmailConfigId) {
this.managementEmailConfigId = managementEmailConfigId;
}
public List<AlertCommunicationAddress> getAlertCommunicationAddresses() {
return this.alertCommunicationAddresses;
}
public void setAlertCommunicationAddresses(List<AlertCommunicationAddress> alertCommunicationAddresses) {
this.alertCommunicationAddresses = alertCommunicationAddresses;
}
public AlertCommunicationAddress addAlertCommunicationAddress(AlertCommunicationAddress alertCommunicationAddress) {
getAlertCommunicationAddresses().add(alertCommunicationAddress);
alertCommunicationAddress.setManagementEmailConfig(this);
return alertCommunicationAddress;
}
public AlertCommunicationAddress removeAlertCommunicationAddress(AlertCommunicationAddress alertCommunicationAddress) {
getAlertCommunicationAddresses().remove(alertCommunicationAddress);
alertCommunicationAddress.setManagementEmailConfig(null);
return alertCommunicationAddress;
}
}
The use case is that the user provides a new alertCommunicationAddress to an existing ManagementEmailConfig and I want create the alertCommunicationAddress then update the ManagementEmailConfig.
If you are using Spring you've made life really difficult for yourself by not using Spring features
I suggest you do the following:
Using Spring Data JPA, write a repository interface to allow
you to easily persist your entity:
public interface ManagementEmailConfigRepository extends JpaRepository { }
use it to persist your entity (save is insert if it's not there,
update if it is)
#Inject
private ManagementEmailConfigRepository managementEmailConfigRepository;
....
managementEmailConfigRepository.save(managementEmailConfig);
This gets rid of the following from your code:
needing to write a save method at all
needing to do a flush
no need for try catch type code
no need for that named query on your entity
(you get that for free on your repository)
I'll leave it up to you to decide where you want the #Transactional annotation; it really shouldn't be on your DAO layer but higher up, e.g. your service layer.
I have a JPA Project (Eclipse Link), works fine but I want to persist a class that is not Entity(Or Not entity in the same Persistence Context), currently I persist the reference id, and after that I do the call to retrieve the Object. I need know what is the best way to do that.. I do not want add code in the bean as listener event, because I want have a clean bean(constructos,properties, setters and getters without annotations),
My Idea is to extend the PersistenceContext(but, I do not know how to do it) adding a filter and identify the class to persist and doing something to replace the persistence of the class not mapped.
Any ideas or my question is out of place?
This is a Simple Example..
#Entity
public class Customer{
#Column
Integer id;
#Column
/*transient?*/
CustomerInfo customerInfo
/*setters and getters*/
}
/*this class maybe not be Entity.. Maybe be a Web Service Response Bean*/
public class CustomerInfo{
private String firstName;
private String lastName;
private BigDecimal balance;
/*setters and getters*/
}
Following my comments: create an embeddable CustomerInfoKey with the essential information.
Two solutions then:
Inheritance:
Have CustomerInfo inherits CustomerInfoKey
Use setCustomerInfoKey(customerInfo) with customerInfo a CustomerInfo.
Composition and delegation:
Have a field CustomerInfoKey key in CustomerInfo
Delegate the getter/setter of CustomerInfoKey in CustomerInfo:
public Foobar getFoobar() {return key.getFoobar()}
public void setFoobar(Foobar foobar) {key.setFoobar(key);}
Have a method getKey() and use it to persist data; you can even create a setter taking a CustomerInfo in Customer and doing the appropriate stuff.
I don't know how JPA implementations behave when it encounters partial mapping like solution #1. But it should work.
As proposed by NoDataFound in the comment, if you do not want to add an Id, an Embeddable/Embedded tandem could be the solution: because of the Id problem, you should have the data in the same table (it is possible to keep different classes). You have the doc in the Java EE tutorial. If you don't want to change the code, you could use the XML for object/relational mapping. In the wikibook about JPA you have an XML sample.
To resolve this, I am creating a EntityListener:
public interface JREntityListener<T> {
public Class getTarget();
public void postUpdate(T t) throws Exception;
public void postCreate(T t) throws Exception;
public void preMerge(T t) throws Exception;
public void postMerge(T t) throws Exception;
public void prePersist(T t) throws Exception;
public void postPersist(T t) throws Exception;
}
I am Created a Class to Catch the events of a Entity
public class JRDescriptorEventListener<T> implements DescriptorEventListener{
//implements all methods of DescriptorEventListener
//i am Show only One to Example
#Override
public void postClone(DescriptorEvent descriptorEvent) {
// descriptorEvent.getObject();
try {
logger.info("postClone");
t.postUpdate((T) descriptorEvent.getObject());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
I am created a Binding EntityListener with PersistenceContext (Thanks jhadley by injecting a spring dependency into a JPA EntityListener):
public void addListener(JREntityListener t) {
JpaEntityManager entityManager = null;
try {
// Create an entity manager for use in this function
entityManager = (JpaEntityManager) entityManagerFactory.createEntityManager();
// Use the entity manager to get a ClassDescriptor for the Entity class
ClassDescriptor desc =
entityManager.getSession().getClassDescriptor(t.getTarget());
JRDescriptorEventListener jrDescriptorEventListener = new JRDescriptorEventListener(t);
desc.getEventManager().addListener(jrDescriptorEventListener);
logger.info("Entity Listener for " + t.getTarget().getCanonicalName() + " is added");
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
if (entityManager != null) {
// Cleanup the entity manager
entityManager.close();
}
}
}
Now I am implements the Listener addind Listener
javoraiPersistenceBase.addListener(myEntityListener);
public class MyEntityListener implements JavoraiEntityListener<Customer> {
#Autowired
CustomerSvc customerSvc;
#Override
public Class getTarget() {
return Customer.class;
}
#Override
public void postUpdate(Customer customer) throws Exception {
CustomerInfo customerInfo = globalDataSvc.findCustomerInfoById(customer.getCustomerInfo().getId());
customer.setCustomerInfo(customerInfo);
}
}
I have the following two classes: Claim (parent) and ClaimInsurance (child). They are as follows:
public class Claim {
private SortedSet<ClaimInsurance> claimInsurances = new TreeSet<ClaimInsurance>();
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="claim", orphanRemoval=true)
#Sort(type=SortType.NATURAL)
public SortedSet<ClaimInsurance> getClaimInsurances() {
return this.claimInsurances;
}
public void setClaimInsurances(SortedSet<ClaimInsurance> claimInsurances) {
this.claimInsurances = claimInsurances;
}
}
And:
public class ClaimInsurance implements java.io.Serializable, Comparable<ClaimInsurance> {
private Claim claim;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="ClaimId", nullable=false)
public Claim getClaim() {
return this.claim;
}
public void setClaim(Claim claim) {
this.claim = claim;
}
}
When I try to delete the Claim it gives following Exception
org.hibernate.exception.ConstraintViolationException: could not delete: [com.omnimd.pms.beans.Claim#201]
...
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The DELETE statement conflicted with the REFERENCE constraint "FK_RCMSClaimInsuranceTable_RCMSClaimTable". The conflict occurred in database "Omnimdv12", table "dbo.RCMSClaimInsuranceTable", column 'ClaimId'.
When I change the claimInsurances mapping in the Claim class as follows, everything works fine:
private Set<ClaimInsurance> claimInsurances = new HashSet<ClaimInsurance>();
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="claim", orphanRemoval=true)
public Set<ClaimInsurance> getClaimInsurances() {
return this.claimInsurances;
}
public void setClaimInsurances(Set<ClaimInsurance> claimInsurances) {
this.claimInsurances = claimInsurances;
}
It seems that the problem is when I use Set (HashSet) in the mapping it works, but if I instead use SortedSet (TreeSet) it gives an error.
What could be the actual problem? What am I missing?
OK. The problem is resolved now. with the help of #JB Nizet
For same Claim i was having several ClaimInsurance whose compareTo() giving same result.
I changed the compareTo() in ClaimInsurance such that it will return different values for same Claim..that's it, its working now.