detached entity passed to persist - springboot - java

Sales Order save not working for existing Customer but working for new Customer
#Entity
#Table(name = "sales_order")
#EntityListeners(AuditingEntityListener.class)
public class SalesOrder extends Auditable<String> implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
#OneToOne(fetch = FetchType.EAGER,cascade=CascadeType.ALL)
#JoinColumn(name = "customer_id", nullable = false)
private Customer customer;
#Entity
#Table(name = "customer")
#EntityListeners(AuditingEntityListener.class)
public class Customer extends Auditable<String> implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
#OneToOne(mappedBy="customer",cascade={CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST,CascadeType.REFRESH})
private SalesOrder salesOrder;
SalesOrder salesOrder = new SalesOrder();
Branch branch = BranchContextHolder.getCurrentBranch();
String nextSequense = null;
if(salesOrderDto.getId()==null) {
salesOrder = new SalesOrder(salesOrderDto);
salesOrder.setBranch(branch);
if(customerRepository.existsByPhone(salesOrderDto.getCustomer().getPhone())) {
Customer customer = customerRepository.findCustomerByPhone(salesOrderDto.getCustomer().getPhone());
customer.setSalesOrder(salesOrder);
salesOrder.setCustomer(customer);
}
nextSequense = sequenceService.getNextSequense(branch.getId(),module.getId());
salesOrder.setUid(nextSequense);
}
//save sales order
salesOrder = salesOrderRepository.save(salesOrder);
On save getting error:
detached entity passed to persist: com.jee.cms.app.customer.model.Customer; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: com.jee.cms.app.customer.model.Customer
Anything I am missing?

Try annotating your method with #Transactional. Then then Customer won't get detached within the method.

Related

JPA Embeddable bidirectional

What's the correct way to create bidirectional 1to1 mapping using Embeddable annotation? This one throws error
"EmpId has no persistent id property: Emp.id"
#Entity
public class Per implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "per_id")
private Long id;
#OneToOne
#JoinColumn(name = "per_id", referencedColumnName = "emp_id")
private Emp emp;
}
#Embeddable
public class EmpId implements Serializable {
private static final long serialVersionUID = 1L;
#OneToOne(mappedBy = "emp")
private Per per;
}
#Entity
public class Emp implements Serializable {
#EmbeddedId
private EmpId id;
}
I'd like to operate entities like
per.getEmp();
emp.getId().getPer();

How to remove foreign key without deleting the whole entity

I am new to Spring boot and I want to be able to delete the value of a forgein key if its entity is removed without deleting the whole entity linked to it; I explain in my case a single person who has an Account can be at the same time an Author and a Player, so if I delete an author I want to delete its refrence in Account table without deleting the whole account because this account can still point on player. I searched on the internet I found cascadetype but it will delete the whole account!
Thank you in advance!
here is my entities
#Table(name = "account")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Account implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "ID")
private Long id;
#ManyToOne
#JoinColumn(name = "Author")
private Author author;
#ManyToOne
#JoinColumn(name = "Player")
private Player player;
//attributs, getters & setters
}
#Table(name = "player")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Player implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "ID")
private Long id;
//attributs, getters & setters
}
//ma.myapp.usersgestion.domain.Author
#Table(name = "author")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Author implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
#Column(name = "ID")
private Long id;
#OneToMany(mappedBy = "author")
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
#JsonIgnoreProperties(value = { "player", "author"}, allowSetters = true)
private Set<Account> accounts = new HashSet<>();
//attributs, getters & setters
}
UPDATE
Im using jhipster (spring boot with React) and h2 database (with disk-based persistence)
//AuthorResource.java
#RestController
#RequestMapping("/api")
#Transactional
public class AuthorResource {
private final Logger log = LoggerFactory.getLogger(AuthorResource.class);
private static final String ENTITY_NAME = "author";
#Value("${jhipster.clientApp.name}")
private String applicationName;
private final AuthorRepository authorRepository;
public AuthorResource(AuthorRepository authorRepository) {
this.authorRepository = authorRepository;
}
/**
* {#code DELETE /authors/:id} : delete the "id" author.
*
* #param id the id of the author to delete.
* #return the {#link ResponseEntity} with status {#code 204 (NO_CONTENT)}.
*/
#DeleteMapping("/authors/{id}")
public ResponseEntity<Void> deleteAuthor(#PathVariable Long id) {
log.debug("REST request to delete Author : {}", id);
authorRepository.deleteById(id);
return ResponseEntity
.noContent()
.headers(HeaderUtil.createEntityDeletionAlert(applicationName, true, ENTITY_NAME, id.toString()))
.build();
}
//...
}
//AuthorRepository
#SuppressWarnings("unused")
#Repository
public interface AuthorRepository extends JpaRepository<Author, Long> {}
In your entity class author add the following:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "author", cascade = { CascadeType.DETACH, CascadeType.MERGE, CascadeType.REFRESH, CascadeType.PERSIST })
private Set<Account> accounts;
I've omitted the cascadetype CascadeType.REMOVE from the list. This will prevent Account from also being deleted when the related Author entity is deleted.
EDIT:
If the above solution somehow doesn't work then you can also try adding #OnDelete(action = OnDeleteAction.NO_ACTION) above the accounts field.
#OnDelete is a hibernate specific annotation.
EDIT 2:
If none of the solutions provided above work then you can also consider making a javax.persistence.#PreRemove annotated method that manually sets the author field for each related Account to null. You place this method inside the Author class. A method that is annotated with #PreRemove will always run before the entity is deleted. So for Author you could use the following method to set all author_id fields to null.
#PreRemove
public void deleteAuthor(){
this.getAccounts().forEach(account -> account.setAuthor(null));
}

Hibernate one to one criteria fetching

I am using hibernate one to one mapping between car and person table. But a person might have car and might not have a car. now while fetching the records from the person table using hibernate criteria , I want to fetch only those persons who have a car, i.e only those entries in person table for which a corresponding entry in car table exists. How this can be done using hibernate criteria/alias?
Below is the piece of code. kindly help with the criteria or alias that has to written to fetch result:
#Getter
#Setter
#Entity
#Table(name = "Person")
public class Person implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Person_ID")
private Long personId;
#OneToOne(mappedBy = "personAsset", cascade = CascadeType.ALL)
private Car car;
}
#Getter
#Setter
#Entity
#Table(name = "Car")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Car_ID")
private Long carId;
#OneToOne
#JoinColumn(name = "Person_ID")
private Person personAsset;
}
what you are looking for is the cascadeType orphanRemoval=true on the #OneToOne annotation.
here is your class how would look like :
#Getter
#Setter
#Entity
#Table(name = "Car")
public class Car implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "Car_ID")
private Long carId;
#OneToOne(fetch=FetchType.EAGER , cascade=CascadeType.ALL, orphanRemoval=true)
#JoinColumn(name = "Person_ID")
private Person personAsset;
}
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Person> query = cb.createQuery(Person.class);
Root<Person> person = query.from(Person.class);
Predicate predicate = cb.isNotNull(person.join("car"));
predicates.add(predicate );

Save object with OneToMany from JSON to database

I'm trying to send the following JSON to a REST API and persist on database, but only the Product is created, the Image it is not.
{"name":"pen",
"description":"red pen",
"images":[{"type":"jpeg"}]
}
#Controller
#POST
#Path("/product/add")
#Consumes("application/json")
public Response addProduct(Product product) {
service.createProduct(product);
}
#Service
#Autowired
private ProductDAO productDAO;
#Autowired
private ImageDAO imageDAO;
public void createProduct(Product product) {
productDAO.save(product);
}
#Product
#Entity
#Table
public class Product implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer productId;
#Column(name = "NAME")
private String name;
#Column(name = "DESCRIPTION")
private String description;
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedBy="product")
private Set<Image> images;
#OneToMany(cascade=CascadeType.ALL, fetch = FetchType.EAGER, mappedBy="parent")
private Set<Product> children;
#ManyToOne
#JoinColumn(name = "PARENT_PRODUCT_ID")
private Product parent;
#Image
#Entity
#Table
public class Image implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer imageId;
#Column(name = "TYPE")
private String type;
#ManyToOne
#JoinColumn(name = "PRODUCT_ID", nullable = false)
private Product product;
At the #POST method, when print the Product object received, this is what returns:
Product [productId=null, name=pen, description=red pen, images=[Image [id=null, type=jpeg, product=null]], children=null, parent=null]
The correct way is to first persist the Product, and then persist the Image or the Hibernate can automatically persist the Image when I persist the Product?
Hibernate takes care of persisting your child entities if your bidirectional mapping is correctly implemented and you have set proper relationships between your entity objects.
You have a Product entity that has a collection of Image. Product entity is the parent entity here. You can simply set proper relations between Product and Image entities and persist only Product. Hibernate will persist your parent as well as your child entities.
What you need to do
Product product = new Product();
product.setName("PRODUCT_NAME");
Set<Image> productImages = new HashSet<>();
Image productProfileImage = new Image();
productProfileImage.setType("PROFILE");
productProfileImage.setProduct(product);
//..set other fields
productImages.add(productProfileImage);
Image productCoverImage = new Image();
productCoverImage.setType("COVER");
productCoverImage.setProduct(product);
//..set other fields
productImages.add(productCoverImage);
product.setImages(productImages);
productRepository.save(product); //Persist only your product entity and the mapped child entities will be persisted
Check out this similar answer.
PS: I have not tested the code but this should work.

jpa one-to-many self reference is fetching all levels

I'm trying to create a social app service. I have user with confirmed or nonconfirmed relationships.
When I load UserA, the result look like belove.
"result":{
"idUser":"UserA",
"unconFriendships":[
{
"idUser":"UserB",
"unconFriendships":[
{
"idUser":"UserC",
"unconFriendships":[
...
While it has to be look like
"result":{
"idUser":"UserA",
"unconFriendships":[
{
"idUser":"UserB",
"unconFriendships":null //only one level have to fetched
....
I thought that this was because jackson json library, I debbuged the code. Before serialization, I inspected userA object and I saw that userA.unconFriendships.userB.unconFriendships was not null and with size bigger than 0.
Nearly it has been 12 hours, still couldn't solve the problem. Please help me to solve this. Thanks in advence.
Here is UserEntity.java
#Entity
#Table(name="aduser",uniqueConstraints=#UniqueConstraint(columnNames = {"idUser","nmEmail"}))
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="cdUser")
public class UserEntity extends BaseEntity {
protected static final long serialVersionUID = 8864033727886664353L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "admin_seq")
#SequenceGenerator(name = "admin_seq", sequenceName = "CDUSER_SEQUENCE", allocationSize = 1)
#Column(name="cdUser")
private long cdUser;
#OneToMany(mappedBy = "owner", targetEntity=Friendship.class)
#JsonProperty
protected Set<UnconfirmedFriendship> unconFriendships;
#OneToMany(mappedBy = "owner", targetEntity=Friendship.class)
#JsonProperty
protected Set<UnconfirmedFriendship> conFriendships;
...
Friendship.java
#Entity
#Table(name="aduserfriend")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name = "verified")
#JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="friend_cduser",scope=UserEntity.class)
public abstract class Friendship extends BaseEntity{
protected static final long serialVersionUID = -670863816551430192L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "cdFriendship")
private long cdFriendship;
#ManyToOne
#JsonIgnore
#JoinColumn(name = "owner_cduser")
protected UserEntity owner;
#ManyToOne
#JoinColumn(name = "friend_cduser")
protected UserEntity friend;
#Column(name = "verified",insertable=false,updatable=false)
private boolean verified;
...
UnconfirmedFriendship.java and ConfirmedFriendship.java
#Entity
#DiscriminatorValue(value = "0")//this value is 1 for Confirmed relationship
public class UnconfirmedFriendship extends Friendship {
private static final long serialVersionUID = 57796452166904132L;
}

Categories