#OneToMany unknown target entity property, with several #ManyToOne in children Entity - java

I have a error with Hibernate:
org.hibernate.AnnotationException: mappedBy reference
an unknown target entity property: ch.zkb.documenz.backend.model.Template.user
in ch.zkb.documenz.backend.model.User.templates
I have two Tables: User and Template, but in Template I need to use the id of the user in: createdBy, lockBy or lastUpdateBy, I think I have to use the #onetomany like in my example, but something it's incorrect, What is the best practice to do this then?
public class User implements Serializable {
#Id
#Column(name = "user_id", unique = true, nullable = false)
private Long id;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private Set<Template> templates;
public class Template implements Serializable {
#Id
#Column(name = "template_id", unique = true, nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "createdBy")
private User createdBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lastUpdateBy")
private User lastUpdateBy;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "lockBy")
private User lockBy;
EDIT, I have now a Problem with the Bidirectional LAZY load, I want to get the user wo created the template but I can't.. always is NULL, but in the DB is stored properly
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "createdBy")
private Set<Template> createdTemplates;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "createdBy", referencedColumnName = "user_id", nullable = false)
private User createdBy;

You schould map to your private keys seperately, then in an transient method you can merge them.
private Set<Template> templates = new HasSet<Template>();
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "createdBy")
private Set<Template> createdByTemplates;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "lastUpdateBy")
private Set<Template> lastUpdateByTemplates;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "lockBy")
private Set<Template> lockByTemplates;
#Transient
public Set<Template> getTemplates(){
if(getCreatedByTemplates() != null){
templates.addAll(getCreatedByTemplates());
}
if(getLockByTemplates() != null){
templates.addAll(getLockByTemplates());
}
if(getLastUpdateByTemplates() != null){
templates.addAll(getLastUpdateByTemplates());
}
return templates;
}

The exception message is clear about what doesn't work, the mappedBy must refer to the attribute name that you do have in the other entity,
in your Template entity there's no attribute named "user", try to remove the mappedBy.

I believe mapped by is looking for bean name "user" in Template.
public class User implements Serializable {
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "user")
private Set<Template> templates;
public class Template implements Serializable {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
Change is variable name createdby to user in Template Class would help

Related

object references an unsaved transient instance - save the transient instance before flushing - with CascadeType.ALL present

To start off, I will say that I have seen a lot of questions with the exact same exception message, however I did not find one that corresponded to the problem I'm having personally.
I have two classes that are related to one another as follows:
Parent class
public class MapArea {
#Id
#Column(nullable = false, unique = true)
private String name;
#ManyToOne(cascade=CascadeType.PERSIST)
#OnDelete(action = OnDeleteAction.NO_ACTION)
private MapArea parent;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "area")
#JsonIgnore
private Set<AlternativeAreaName> alternativeNames;
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "data")
private Set<MapAreaData> mapAreaData;
#OneToOne(targetEntity = Expenses.class,
cascade = CascadeType.ALL)
#JoinColumn(name = "name", referencedColumnName = "area")
private Expenses expenses;
#OneToOne(targetEntity = Consumption.class,
cascade = CascadeType.ALL)
#JoinColumn(name = "name", referencedColumnName = "area")
#JsonIgnore
private Consumption consumption;
#Transient
private Set<RelatedMapArea> siblings;
#Transient
private Set<RelatedMapArea> children;
...
}
Child class
public class MapAreaData {
#Id
#JsonIgnore
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "num_bedrooms", nullable = false)
private Integer numBedrooms;
#Column(name = "property_type", nullable = false)
#Enumerated(EnumType.STRING)
private PropertyType propertyType;
#OneToOne(targetEntity = Property.class,
cascade = CascadeType.ALL)
#JoinColumn(name = "property_id")
private Property property;
#OneToOne(targetEntity = Rent.class,
cascade = CascadeType.ALL)
#JoinColumn(name = "rent_id")
private Rent rent;
#OneToOne(targetEntity = CalculatedStats.class,
cascade = CascadeType.ALL)
#JoinColumn(name = "calculated_stats_id")
private CalculatedStats calculatedStats;
...
}
Now the full error message that I get is this:
Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.topfind.search_api_common.map_area_data.MapAreaData
In similar questions, I have found that most people did not use a CascadeType which was their issue. However, in this case I am using CascadeType.ALL everywhere and I'd expect it to be able to save new children MapAreaData whenever I attempt to save MapArea.
I'd appreciate any ideas towards fixing the issue.
Edit 1
I'm initializing the data in one with the following code (keep in my any method starting with createMock* creates a new object with ALL variables (including nested objects that are related) populated, however it does not persist the created object.
int top = 2;
DataQuality dataQuality = DataQuality.ROUGH;
MapArea ROUGH_mapArea = createMockArea("W5", null);
MapAreaData ROUGH_mapAreaData = ROUGH_mapArea.getMapAreaData().iterator().next();
ROUGH_mapAreaData.setCalculatedStats(createMockCalculatedStats(doubleToBigDecimal(15.43),
DataQuality.ROUGH.getMinNumAnalysed(), DataQuality.GOOD.getMinNumAnalysed()));
//ROUGH_mapAreaData = dataRepository.save(ROUGH_mapAreaData); - WORKS if this is used
ROUGH_mapArea = mapAreaRepository.save(ROUGH_mapArea);
Turns out I had to specify a targetEntity to make it all work nicely together for Set<MapAreaData> in MapArea class as follows:
#OneToMany(targetEntity = MapAreaData.class, cascade = CascadeType.ALL, orphanRemoval = true)
#JoinColumn(name = "data")
private Set<MapAreaData> mapAreaData;

HIbernate ignore fetching data from OnetoMany field

I would like to ignore #OnetoMany field in my entity. fetch data need to get actual fields but don't want to fire query to dependent table. But deleting data from parent table needs deletion from dependent table
I have tried #Transient that ignores but the delete is also being ignored. Is there any other option to tell JPA not to fetch data from childs table when i call the parent entity?
#Entity
Table(name = "User")
public class UserEntity implements Serializable {
#Id
#Column(name = "id")
private int id;
#Column(name = "SERIAL", unique = true, nullable = false)
private String serial;
#OneToMany(mappedBy = "serialBySerialId", cascade = CascadeType.ALL)
private Set<UserActionEntity> userActionsById;
}
#Table(name = "user_action")
public class UserActionEntity implements Serializable {
#Id
#Column(name = "id")
private int id;
#Column(name = "action")
private String action;
#ManyToOne
#JoinColumn(name = "USER_ID", referencedColumnName = "ID", nullable = false)
private UserEntity userByUserId;
If you don't want to fire query to dependent table, you can use (fetch = FetchType.LAZY) on UserActionEntity property.
#OneToMany(mappedBy = "serialBySerialId", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private Set<UserActionEntity> userActionsById;

Hibernate identity generator issue

I am having a particular issue when trying to save a collection of objects with hibernate. It seems that when I have more than one object of the same type, hibernate fails to generate the identifier, so I get a org.hibernate.NonUniqueObjectException .
Example:
App1 --> urls
{strApplicationId:1;URLTypeEntity{strCode:1,strDescription:Reply},strURL:www.address1.com},
{strApplicationId:1;URLTypeEntity{strCode:1,strDescription:Reply},strURL:www.address2.com},
{strApplicationId:1;URLTypeEntity{strCode:2,strDescription:Home},strURL:www.address3.com}
If I do not have two URLs with the same URLTypeEntity on the collection, the error is not triggered
#Entity
#Table(name = "tbl_urls")
public class URLEntity
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="intCode")
private Integer intCode;
private String strApplicationID;
#OneToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "intType", referencedColumnName = "intCode")
private URLTypeEntity objURLType;
private String strURL;
}
#Entity
#Table(name = "tbl_applications")
public class ApplicationEntity
{
#OneToMany(cascade = CascadeType.ALL, mappedBy = "strApplicationID")
private List<URLEntity> colURLs;
}
ApplicationEntity must also have an id.
The solution was changing the CascadeType from ALL To Merge
#OneToMany(cascade = CascadeType.ALL, mappedBy = "strApplicationID")
Changed To
#OneToMany(cascade = CascadeType.MERGE, mappedBy = "strApplicationID")

Hibernate #OneToMany #ManyToOne mapping

everyone i have a question with using annotation #OneToMany/#ManyToOne; is it possible to create one user model with two sets of subjects in this model (conducted for the teacher and attending the student) instead of creating separate student and teacher models? I wrote such a code but when I want to get data about item and user, hibernate crashes the "Stack overflow" error.I will add that I use H2 Database.
User Entity:
#Entity
public class User{
#OneToMany(
mappedBy = "student",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
orphanRemoval = true
)
private Set<Item> items = new HashSet<>();
#OneToMany(mappedBy = "teacher",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
orphanRemoval = true
)
private Set<Item> carriedItems= new HashSet<>();
}
//id and other data
Item entity:
#Entity
public class Item{
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "student_id", nullable = false)
private User student;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "teacher_id", nullable = false)
private User teacher;
}
//id and other data
Thanks for help #Leviand
Based on your comments, looks like your code and logic needs some rework.
First, use instead of Item pojo two dedicated classes:
#Entity
#Table(name = Studend) // I'm guessing a table name
public class Student{
#JoinColumn(name = "student_id", nullable = false)
private User user;
}
#Entity
#Table(name = Teacher) // I'm guessing a table name
public class Teacher{
#JoinColumn(name = "teacher_id", nullable = false)
private User user;
}
Then since an User can only be connected to a single Teacher or Student, refact that in something like:
#Entity
#Table(name = User) // I'm guessing a table name
public class User{
#OneToOne(
mappedBy = "student",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
orphanRemoval = true
)
private Student student;
#OneToMany(mappedBy = "teacher",
cascade = CascadeType.ALL,
fetch = FetchType.EAGER,
orphanRemoval = true
)
private Teacher teacher;
}
Hope this helps :)

jpa mapping two properties

I need CompanyUser.companyRolCompanyUsers property with OneToMany relation, completed in each query.
JPA company_usr entity:
#Entity
#Table(name = "company_usr")
public class CompanyUser extends BaseModel implements Serializable {
#Id
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(nullable = false)
private Company company;
#Id
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "usr_id", nullable = false)
private User user;
#Column(nullable = false)
private Boolean external;
#OneToMany(fetch = FetchType.EAGER)
private List<CompanyRolCompanyUser> companyRolCompanyUsers;
....
JPA companyRol_companyUsr entity:
#Entity
#Table(name = "companyRol_companyUsr")
public class CompanyRolCompanyUser extends BaseModel implements Serializable {
#Id
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumns({
#JoinColumn(name="companyuser_company_id", referencedColumnName="company_id"),
#JoinColumn(name="companyuser_usr_id", referencedColumnName="usr_id")
})
private CompanyUser companyUser;
#Id
#ManyToOne(fetch = FetchType.EAGER)
private CompanyRol companyRol;
....
How to set mappedBy in companyRolCompanyUsers property correctly?
If i get what you want to achieve i think you need something like :
#OneToMany(fetch = FetchType.EAGER, mappedBy="companyUser")
private List<CompanyRolCompanyUser> companyRolCompanyUsers;
You can have two properties for the same column like this :
#JoinColumn(name = "CGRADO_CODIGO", referencedColumnName = "CGRADO_CODIGO")
#ManyToOne
#NotFound(action=NotFoundAction.IGNORE)
private SipreGrado sipreGrado;
#Column(name = "CGRADO_CODIGO",insertable=false,updatable=false)
private String sipreGradoCodigo;
Remember if you have sometimes the entity NULL you can skip it with that annotation
#NotFound(action=NotFoundAction.IGNORE)
Also,Remember to set
insertable=false,updatable=false
for the one that you dont want to include in the insert/update queries.

Categories