"Save transient object before flushing" error [duplicate] - java

This question already has answers here:
How to fix the Hibernate "object references an unsaved transient instance - save the transient instance before flushing" error
(33 answers)
Closed 7 years ago.
I tried to save one of my entity Site containing a User, this User is registered in database and I don't want to save it too. The problem is when I try to save the site, I get the following error :
org.springframework.dao.InvalidDataAccessApiUsageException: object references an unsaved transient instance - save the transient instance before flushing: com.project.netmg.bo.impl.User; nested exception is org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.project.netmg.bo.impl.User
I think, it try to save the user too but it's not that I want. I just want to search the good user and assign it to the site.
java code :
public String saveSite(#Valid #ModelAttribute SiteForm siteForm, BindingResult bindingResult, Model uiModel) {
populateSiteforSave(siteForm);
_siteService.saveSite(siteForm.getSite());
return WebConstants.REDIRECT_TO_VIEW_SITE_URL + siteForm.getSite().getSiteName();
}
private void populateSiteforSave(SiteForm siteForm) {
siteForm.getSite().setCountry((Country) _countryService.getCountryByName(siteForm.getSite().getCountry().getName()));
siteForm.getSite().setBusiness((Business) _businessService.getBusinessById(siteForm.getSite().getBusiness().getId()));
siteForm.getSite().setStatus((Status) _statusService.getStatusById(siteForm.getSite().getStatus().getId()));
if (!siteForm.getLocalItFullName().isEmpty()) {
siteForm.getSite().setLocalIt(_userService.findUserByUserFullName(siteForm.getLocalItFullName())); // user
} else {
siteForm.getSite().setLocalIt(null);
}
if (!siteForm.getRifFullName().isEmpty()) {
siteForm.getSite().setRif(_userService.findUserByUserFullName(siteForm.getRifFullName())); //user
} else {
siteForm.getSite().setRif(null);
}
if (siteForm.getSite().getLocalContact().getId() != null) {
siteForm.getSite().setLocalContact((User) _userService.findUserByUsername(siteForm.getSite().getLocalContact().getUsername())); //user
}
}
Site class:
#Entity
#Table(name = "SITE", uniqueConstraints = { #UniqueConstraint(columnNames = { "SITE_COUNTRY_ID", "SITE_NAME" }) })
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED, withModifiedFlag = true)
public class Site implements ISite {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -390717603276436784L;
/** The id. */
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "SITE_ID", unique = true, nullable = false)
private long id;
/** The site address. */
#Column(name = "SITE_ADDRESS", length = BusinessConstants.SITE_ADDRESS)
private String address;
/** The site analog phone number. */
#Column(name = "SITE_ANALOG_PHONE_NUMBER", length = BusinessConstants.SITE_ANALOG_PHONE_NUMBER)
private String analogPhoneNumber;
/** The site comment. */
#Column(name = "SITE_COMMENT", length = BusinessConstants.SITE_COMMENT)
private String comment;
/** The site entity code. */
#Digits(integer = 3, fraction = 0, message = "Please enter max 3 digits")
#Column(name = "SITE_ENTITY_CODE", nullable = false)
private long entityCode;
/** The site invoice code. */
#Digits(integer = 10, fraction = 0, message = "Please enter max 10 digits")
#Column(name = "SITE_INVOICE_CODE", nullable = false)
private long invoiceCode;
/** The site local it phone. */
#Column(name = "SITE_LOCAL_IT_PHONE", length = BusinessConstants.SITE_LOCAL_IT_PHONE)
private String localItPhone;
/** The site name. */
#NotBlank
#Column(name = "SITE_NAME", nullable = false, length = BusinessConstants.SITE_NAME)
private String siteName;
/** The site subnet. */
#NotBlank
#Column(name = "SITE_SUBNET", nullable = false, length = BusinessConstants.SITE_SUBNET)
private String subnet;
/** The site user number. */
#Digits(integer = 4, fraction = 0, message = "Please enter max 4 digits")
#Column(name = "SITE_USER_NUMBER")
private Long userNumber;
/** The business. */
#Valid
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SITE_BUSINESS_ID", nullable = false)
private Business business;
/** The country. */
#Valid
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "SITE_COUNTRY_ID")
private Country country;
/** The local contact. */
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SITE_LOCAL_CONTACT", nullable = true)
private User localContact;
/** The local it. */
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SITE_LOCAL_IT", nullable = true)
private User localIt;
/** The rif. */
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SITE_RIF", nullable = true)
private User rif;
/** The status. */
#Valid
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "SITE_STATUS_ID", nullable = false)
private Status status;
/** The end date. */
#Column(name = "SITE_END_DATE")
#Temporal(TemporalType.TIMESTAMP)
#DateTimeFormat(iso = ISO.DATE_TIME)
private Date endDate = null;
#ManyToMany(targetEntity = User.class, mappedBy = "userSites", fetch = FetchType.LAZY)
#NotAudited
private Set<IUser> siteUsers;
User class :
#Entity
#Table(name = "USERS")
public class User implements IUser {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 6741623705511494367L;
private static final String USER_ID = "USER_ID";
/** The user id. */
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = USER_ID)
private Long id;
/** The user first name. */
#Column(name = "FIRSTNAME", length = BusinessConstants.USER_FIRSTNAME, nullable = false)
#NotNull
private String userFirstName;
/** The user last name. */
#Column(name = "LASTNAME", length = BusinessConstants.USER_LASTNAME, nullable = false)
#NotNull
private String userLastName;
/** The user email. */
#Column(name = "EMAIL", length = BusinessConstants.USER_EMAIL)
#NotNull
private String userEmail;
/** The user uid. */
#Column(name = "LOGIN", length = BusinessConstants.USER_LOGIN, nullable = false, unique = true)
#NotNull
private String username;
#Valid
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "PROFILE_ID", referencedColumnName = "PROF_ID", nullable = false)
private Profile profile;
#BatchSize(size = 20)
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST }, fetch = FetchType.LAZY,targetEntity=Site.class)
#JoinTable(name = "USER_SITE",
joinColumns = { #JoinColumn(name = USER_ID, nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "SITE_ID", nullable = false) })
private Set<ISite> userSites;
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST }, fetch = FetchType.LAZY,targetEntity=Region.class)
#JoinTable(name = "USER_REGION",
joinColumns = { #JoinColumn(name = USER_ID, nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "REGION_ID", nullable = false) })
private Set<IRegion> userRegions;
#BatchSize(size = 20)
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST }, fetch = FetchType.LAZY,targetEntity=Zone.class )
#JoinTable(name = "USER_ZONE",
joinColumns = { #JoinColumn(name = USER_ID, nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "ZONE_ID", nullable = false) })
private Set<IZone> userZones;
#BatchSize(size = 20)
#ManyToMany(cascade = { CascadeType.MERGE, CascadeType.PERSIST }, fetch = FetchType.LAZY,targetEntity=Country.class )
#JoinTable(name = "USER_COUNTRY",
joinColumns = { #JoinColumn(name = USER_ID, nullable = false) },
inverseJoinColumns = { #JoinColumn(name = "COUNTRY_ID", nullable = false) })
private Set<ICountry> userCountries;
#Transient
private Collection<? extends GrantedAuthority> authorities;
#Transient
private String userFullName;

You can't really have it both ways. If the object graph includes the User, then it will (have to) be persisted if changed in your code. Have you considered what it evens means to fetch a Site (including a User), then change the localContact and persist the Site again?
If you want the localContact to be settable in the object graph, but not persisted, then it can be annotated with #Transient:
/** The local contact. */
#Transient
private User localContact;
Hope that helps.
Cheers,

Have you annotate cascade=CascadeType.ALL to your entity object mapping
eg :
#ManyToOne(cascade = CascadeType.ALL)
private String entityType;

Related

JPA created too many fields in table

enter image description here
I am trying to map some entities to tables in MySQL database using Spring Boot JPA. I have a problem with one of the tables because in that one too many foreign keys are added. I highlighted the columns in the picture. I suppose that the problem might be linked with the fact that the Tutorial table has either One to Many or Many to Many relations with the other 3 tables, but I am not sure
#Entity(name = "authors")
public class Author {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "author_id")
private Long authorId;
#Column(name = "first_name", nullable = false, length = 100)
private String firstName;
#Column(name = "last_name", nullable = false, length = 100)
private String lastName;
#Column(name = "email", length = 320, unique = true)
private String email;
#Column(name = "job_title", length = 255)
private String jobTitle;
#Lob
#Type(type = "org.hibernate.type.BinaryType")
#Column(name = "profile_picture")
private byte[] profilePicture;
#Column(name = "about", length = 2000)
private String about;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "author_id")
private List<Tutorial> tutorials;
}
#Entity(name = "categories")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "category_id")
private Long categoryId;
#Column(name = "category_name", nullable = false, unique = true, length = 100)
private String categoryName;
#OneToMany(fetch = FetchType.LAZY)
#JoinColumn(name = "category_id")
private List<Tutorial> tutorials;
}
#Entity(name = "tutorials")
public class Tutorial {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "tutorial_id")
private Long tutorialId;
#Column(name = "tutorial_title", nullable = false, length = 150)
private String tutorialTitle;
#Column(name = "tutorial_description", nullable = false, length = 2000)
private String tutorialDescription;
#Column(name = "time_to_complete")
private Integer timeToComplete;
#Column(name = "date_published")
private Long datePublished;
#Column(name = "last_updated")
private Long lastUpdated;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
},
mappedBy = "tutorials")
private List<User> users = new ArrayList<>();
#ManyToOne(fetch = FetchType.EAGER)
private Category category;
#ManyToOne(fetch = FetchType.EAGER)
private Author author;
}
Tutorials is the table where the problems appear as 4 foreign keys are generate instead of two
#Entity(name = "users")
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "user_id")
private Long userId;
#Column(name = "first_name", nullable = false, length = 100)
private String firstName;
#Column(name = "last_name", nullable = false, length = 100)
private String lastName;
#Column(name = "user_name", nullable = false, unique = true, length = 100)
private String userName;
#Column(name = "age")
private Integer age;
#Column(name = "email", length = 320, unique = true)
private String email;
#ManyToMany(fetch = FetchType.LAZY,
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
})
#JoinTable(name = "users_tutorials",
joinColumns = { #JoinColumn(name = "user_id") },
inverseJoinColumns = { #JoinColumn(name = "tutorial_id") })
private List<Tutorial> tutorials = new ArrayList<>();
}
Try this changes:
remove #JoinColumn(name = "author_id")from Author and place in Tutorial:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "author_id")
private Author author;
remove #JoinColumn(name = "category_id")from Category and place it in Tutorial as well:
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "category_id")
private Author author;
To get more information look here: Baeldung - Hibernate One to Many

spring-boot-starter-data-jpa#ManyToMany collection not populating

I'm getting a problem with the #ManyToMany collections not populating on data load. I've tried FetchType.LAZY and FetchType.EAGER with no changes in the result.
When I am printing the User Object the collection Object of Roles is empty.
User [userId=2, firstName=Ajay, lastName=C, email=admin.demo#gmail.com, password=12345, roles=[]]
Also tried by adding referenced columns. But not worked.
Please assist in this.
User and Roles Entities as follows.
#Entity
#Table(name = "\"USER\"", schema = "\"PLATFORM_PROD_IOT\"", uniqueConstraints = {
#UniqueConstraint(columnNames = { "\"EMAIL_ID\"" }) })
public class User {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Size(min = 1, max = 50)
#Column(name = "\"USER_ID\"")
private Long userId;
#NotBlank
#Size(min = 3, max = 50)
#Column(name = "\"FIRST_NAME\"")
private String firstName;
#NotBlank
#Size(min = 3, max = 50)
#Column(name = "\"LAST_NAME\"")
private String lastName;
#NaturalId
#NotBlank
#Size(max = 50)
#Email
#Column(name = "\"EMAIL_ID\"")
private String email;
#NotBlank
#Size(min = 3, max = 100)
#Column(name = "\"PASSWORD\"")
private String password;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "\"USER_ROLE_MAPPING\"", schema = "\"\PLATFORM_PROD_IOT\"", joinColumns = #JoinColumn(name = "\"USER_ID\""), inverseJoinColumns = #JoinColumn(name = "\"ROLE_ID\""))
private Set<Role> roles = new HashSet<>();
//Getters and Setters
}
#Entity
#Table(name = "\"ROLE\"",schema="\"PLATFORM_PROD_IOT\"")
public class Role {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="\"ROLE_ID\"")
private Long roleId;
#Column(name="\"ROLE_NAME\"")
private RoleName name;
//Getters and Setters
}
You could try this -
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "\"USER_ROLE_MAPPING\"", catalog = "\"PLATFORM_PROD_IOT\"", joinColumns = {
#JoinColumn(name = "\"USER_ID\"", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "\"ROLE_ID\"",
nullable = false, updatable = false) })
private Set<Role> roles = new HashSet<>();
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
Here I have added
cascade = CascadeType.ALL
catalog = "\"PLATFORM_PROD_IOT\"" instead of schema = "\"PLATFORM_PROD_IOT\""
nullable = false, updatable = false in #JoinColumn
Also have found an related -
collection not populating in many to many relationship

The constructor Category(String, String) is not visible - create constructor for some field using lombok?

I did googled a lot, still dont find any solution hence posting a question here..
I am developing Many-To-Many relationship example using lombok. I just want to create argument constructor for only two fields out of four. How we can do that ?
#Data
#Entity
#Table(name = "stock")
public class Stock implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "STOCK_ID", unique = true, nullable = false)
private Integer stockId;
#Column(name = "STOCK_CODE", unique = true, nullable = false, length = 10)
private String stockCode;
#Column(name = "STOCK_NAME", unique = true, nullable = false, length = 20)
private String stockName;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "stock_category", joinColumns = {
#JoinColumn(name = "STOCK_ID", nullable = false, updatable = false)},
inverseJoinColumns = {#JoinColumn(name = "CATEGORY_ID", nullable = false, updatable = false)})
private Set<Category> categories = new HashSet<Category>(0);
}
Category
#Data
#RequiredArgsConstructor(staticName = "of")
#Entity
#Table(name = "category")
public class Category {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "CATEGORY_ID", unique = true, nullable = false)
private Integer categoryId;
#Column(name = "NAME", nullable = false, length = 10)
#NonNull
private String name;
#Column(name = "[DESC]", nullable = false)
#NonNull
private String desc;
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "categories")
private Set<Stock> stocks = new HashSet<Stock>(0);
}
App.java
Why cant I set the limitted field constructor
public class App {
public static void main(String[] args) {
System.out.println("Hello World!");
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("7052");
stock.setStockName("PADINI");
Category category1 = new Category("CONSUMER", "CONSUMER COMPANY");
Category category2 = new Category("INVESTMENT", "INVESTMENT COMPANY");
Set<Category> categories = new HashSet<Category>();
categories.add(category1);
categories.add(category2);
stock.setCategories(categories);
session.save(stock);
session.getTransaction().commit();
System.out.println("Done");
}
}
The reason is that
If staticName set, the generated constructor will be private, and an additional
static 'constructor' is generated with the same argument list that
wraps the real constructor.
Please, don't forget about #NoArgsConstructor because Hibernate needs it.

Using Criteria api in hibernate how can I achieve Lazy loaded list using projection?

I have three entity class Employee , ContactDetail and ReportingPerson. Here is my code an relationship among them you can easily understand .And I have to use Criteria API for get all details of ReportingPerson from Employee . Employee and ReportingPerson have onetoone relationship.
#Entity
#Table(name = "tbl_employee")
public class Employee implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3919524684485334176L;
/** The id. */
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
/** The contact details. */
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "tbl_employee_contact", joinColumns = { #JoinColumn(name = "id", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "contact_id", nullable = false, updatable = false) })
private List<ContactDetail> contactDetails;
/** The company. */
#Column
private String company;
/** The website. */
#Column
private String website;
#OneToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "person_id", nullable = true)
private ReportingPerson reportingPerson;
#Entity
#Table(name = "tbl_contact")
public class ContactDetail implements Serializable {
/**
*
*/
private static final long serialVersionUID = -3022172440588672233L;
/** The id. */
#Id
#Column(name = "contact_id")
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
/** The type. */
#Column
private String type;
/** The detail. */
#Column
private String detail;
/** The description. */
#Column
private String description;
/** The preferred. */
#Column
private boolean preferred;
#Entity
#Table(name = "tbl_reporting_person")
public class ReportingPerson{
/** The id. */
#Id
#Column(name = "person_id")
#GeneratedValue(generator = "uuid")
private String id;
/** The contact details. */
#OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinTable(name = "tbl_reporting_person", joinColumns = { #JoinColumn(name = "person_id", nullable = false, updatable = false) }, inverseJoinColumns = { #JoinColumn(name = "contact_id", nullable = false, updatable = false) })
private List<ContactDetail> contactDetails;
/** The company. */
#Column
private String company;
/** The website. */
#Column
private String website;
Here is what I am trying to achieve but I get null values of contactDetails.Please anybody can tell me where I am wrong ?
public ReportingPerson getEmployeeReportingPerson (final String employeeId) {
final Criteria criteria = getDatabaseSession().createCriteria(Employee.class, "employee").createAlias(
"employee.reportingPerson", "person", JoinType.INNER_JOIN);
criteria.add(Restrictions.and(Restrictions.eq("employee.id", employeeId)));
criteria.setProjection(Projections.distinct(Projections.projectionList()
.add(Projections.property("person.id").as("id"))
.add(Projections.property("person.website").as("website"))
.add(Projections.property("person.contactDetails").as("contactDetails"))
.add(Projections.property("person.company").as("company"))));
final ReportingPerson person= (ReportingPerson ) criteria.setResultTransformer(
Transformers.aliasToBean(ReportingPerson .class)).uniqueResult();
return person;
}
I hope this will solve your query
https://github.com/samiandoni/AliasToBeanNestedResultTransformer

JPA - Issues removing child entities on bidirectional mapping

I need to remove a child entity called "SystemParamater" based on the it´s id.
What i was trying to do:
- Begin Tran
SystemParameter param EntityManager.find(SystemParameter.class,<paremeter.id>)
EntityManager.remove(param)
-Commit tran
But the entity was not removed.
What´s the correct way to remove a child entity?
Below, you could find my entities:
SystemParameter:
#Entity
#Table(name = "system_parameters")
#Cacheab le
#Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class SystemParameter extends BasicEntity {
private static final long serialVersionUID = -6416605270912358340L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "paramName", length = 50, nullable = false)
private String paramName;
#Column(name = "paramValue", length = 255, nullable = false)
private String paramValue;
#Column(name = "encrypted", nullable = false)
#Type(type = "yes_no")
private Boolean encrypted = Boolean.FALSE;
#ManyToOne
#JoinColumn(name = "groupId", nullable = false)
private SystemParameterGroup parameterGroup;
}
SystemParameterGroup:
#Entity
#Table(name = "system_parameter_groups", uniqueConstraints = { #UniqueConstraint(columnNames = { "searchKey" }) })
#Cacheable
public class SystemParameterGroup extends BasicEntity {
private static final long serialVersionUID = -1762633144642103487L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name", length = 50, nullable = false)
private String name;
/**
* Description.
*/
#Column(name = "description", length = 255, nullable = false)
private String description;
/**
* Search key.
*/
#Column(name = "searchKey", length = 50, nullable = false)
private String searchKey;
/**
* System parameter list.
*/
#OneToMany(fetch = FetchType.EAGER, mappedBy = "parameterGroup", cascade = CascadeType.ALL, orphanRemoval = true)
#OrderBy("paramName")
private List<SystemParameter> systemParameterList;
}
You have to remove the SystemParameter entity also from the SystemParameterGroup's list of SystemParameter:
systemParameterGroup.getSystemParameterList().remove(systemParameter);
This issue is related to this one.

Categories

Resources