Spring/JPA: Multiple Relations between same Entities without circular references - jpa

Good morning everyone. Im trying to build an spring application that has two ManyToMany relations between the same entities: A team has several members and leaders.
First entity:
#Entity
#Table(name = "team")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Team implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "team2member", joinColumns = #JoinColumn(name = "team_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> members = new HashSet<User>();
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "team2leader", joinColumns = #JoinColumn(name = "team_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"))
private Set<User> leaders = new HashSet<User>();
// Members (ManyToMany)
public Set<User> getMembers() {
return members;
}
public void setMembers(Set<User> members) {
this.members = members;
}
public void addMember(User member) {
this.members.add(member);
}
public void removeMember(User member) {
this.members.remove(member);
}
// Leaders (ManyToMany)
public Set<User> getLeaders() {
return leaders;
}
public void setLeaders(Set<User> leaders) {
this.leaders = leaders;
}
public void addLeader(User leader) {
this.leaders.add(leader);
}
public void removeLeader(User leader) {
this.members.remove(leader);
}
}
Second entity:
#Entity
#Table(name = "user")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "team2member", joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "team_id", referencedColumnName = "id"))
private Set<Team> teams = new HashSet<Team>();
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "team2leader", joinColumns = #JoinColumn(name = "user_id", referencedColumnName = "id"), inverseJoinColumns = #JoinColumn(name = "team_id", referencedColumnName = "id"))
private Set<Team> leadedTeams = new HashSet<Team>();
// Teams (ManyToMany)
public Set<Team> getTeams() {
return teams;
}
public void setTeams(Set<Team> teams) {
this.teams = teams;
}
public void addTeam(Team team) {
this.teams.add(team);
}
public void removeTeam(Team team) {
this.teams.remove(team);
}
// LeadedTeams (ManyToMany)
public Set<Team> getLeadedTeams() {
return leadedTeams;
}
public void setLeadedTeams(Set<Team> leadedTeams) {
this.leadedTeams = leadedTeams;
}
public void addLeadedTeam(Team leadedTeam) {
this.leadedTeams.add(leadedTeam);
}
public void removeLeadedTeam(Team leadedTeam) {
this.leadedTeams.remove(leadedTeam);
}
}
My question: Cause im facing a stackoverflow issue im wondering if it is possible this way. Or maybe there is a better solution for this problem?
StackTrace (shorted):
2018-03-27 01:19:08.635 DEBUG 12656 --- [ XNIO-2 task-12] n.s.aop.logging.LoggingAspect : Exit: net.schwungkraft.service.DocumentService.findAllForOrderHeader() with result = Page 1 of 0 containing UNKNOWN instances
2018-03-27 01:19:08.636 DEBUG 12656 --- [ XNIO-2 task-12] n.s.aop.logging.LoggingAspect : Exit: net.schwungkraft.web.rest.OrderHeaderResource.getDocumentsForOrderHeader() with result = <200 OK,[],{X-Total-Count=[0], Link=[</api/order-headers/%7Bid%7D/documents?page=0&size=20>; rel="last",</api/order-headers/%7Bid%7D/documents?page=0&size=20>; rel="first"]}>
2018-03-27 01:19:08.645 DEBUG 12656 --- [ XNIO-2 task-13] n.s.aop.logging.LoggingAspect : Exit: net.schwungkraft.service.OrderHeaderService.findOneForCurrentUser() with result = OrderHeader{id=3102, orderScopeType='BEWERBUNG', dateStart='null', dateEnd='null', duration=null, classType='null', estimatedNoOfApplicants=null, isTaxLiable='false', amountWithoutTaxes=null, taxesPercent=null, taxesAmount=null, amountWithTaxes=null, extraGrantApplicants=null, extraGrantOthers=null, reminderDate='null', rating='null', ratingText='null', category='null', freeText='null', histComissionRateTitle=null, histPaymentTermDescription='3D', histPaymentTimeLimit=null, histPaymentTermTimeLimitForDiscount=null, histPaymentTermDiscount=null, histContactName='test', histContactStreet='null', histContactPostCode=null, histContactCity='null', histContactCountry='null', histContactContactPerson='null', histContactEmail='null', histContactPhoneNumber='null'}
2018-03-27 01:19:08.645 DEBUG 12656 --- [ XNIO-2 task-13] n.s.aop.logging.LoggingAspect : Exit: net.schwungkraft.web.rest.OrderHeaderResource.getOrderHeader() with result = <200 OK,OrderHeader{id=3102, orderScopeType='BEWERBUNG', dateStart='null', dateEnd='null', duration=null, classType='null', estimatedNoOfApplicants=null, isTaxLiable='false', amountWithoutTaxes=null, taxesPercent=null, taxesAmount=null, amountWithTaxes=null, extraGrantApplicants=null, extraGrantOthers=null, reminderDate='null', rating='null', ratingText='null', category='null', freeText='null', histComissionRateTitle=null, histPaymentTermDescription='3D', histPaymentTimeLimit=null, histPaymentTermTimeLimitForDiscount=null, histPaymentTermDiscount=null, histContactName='test', histContactStreet='null', histContactPostCode=null, histContactCity='null', histContactCountry='null', histContactContactPerson='null', histContactEmail='null', histContactPhoneNumber='null'},{}>
2018-03-27 01:19:09.162 ERROR 12656 --- [raft-Executor-2] n.s.c.audit.AsyncEntityAuditEventWriter : Exception while getting entity ID and content {}
com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: org.hibernate.collection.internal.PersistentSet[1]->net.schwungkraft.domain.User["leadedTeams"]->org.hibernate.collection.internal.PersistentSet[0]->net.schwungkraft.domain.Team["members"]->org.hibernate.collection.internal.PersistentSet[1]->net.schwungkraft.domain.User["leadedTeams"]->org.hibernate.collection.internal.PersistentSet[0]->net.schwungkraft.domain.Team["members"]->org.hibernate.collection.internal.PersistentSet[1]->net.schwungkraft.domain.User["leadedTeams"]->org.hibernate.collection.internal.PersistentSet[0]->net.schwungkraft.domain.Team["members"]->org.hibernate.collection.internal.PersistentSet[1]->net.schwungkraft.domain.User["leadedTeams"]->org.hibernate.collection.internal.PersistentSet[0]->net.schwungkraft.domain.Team["members"])
at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:705)
at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:149)

Related

How to delete entities in a chained one-to-many and many-to-many JPA relationship

I have a chain of entities as follows:
#Entity
#Table(name = "Patients")
public class Patient extends TimeStampedPersistable{
private static final long serialVersionUID = 1L;
#OneToMany(mappedBy="patient", cascade = CascadeType.ALL)
#PrivateOwned
private List<Insurance> insurances;
}
#Entity
#Table(name = "insurance")
public class Insurance extends PersistableEntity {
private static final long serialVersionUID = 1L;
#ManyToOne(optional=false)
#JoinColumn(name="patient_id", nullable=false)
private Patient patient;
#Column(name = "policy_number", unique = false, nullable = true)
private String policyNumber;
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinTable(name = "insurance_companycodes", joinColumns = {
#JoinColumn(name = "insurance_id", referencedColumnName = "id", nullable = false, updatable = false) }, inverseJoinColumns = {
#JoinColumn(name = "insuranceCompanyCode_id", referencedColumnName = "id", nullable = false, updatable = false) })
private Set<InsuranceCompanyCode> insuranceCompanyCodes = new HashSet<>();
}
#Entity
#Table(name = "insurance_company_codes")
public class InsuranceCompanyCode extends PersistableEntity {
private static final long serialVersionUID = 1L;
#Column(name = "identifier", unique = true, nullable = true)
private String identifier;
#ManyToMany(mappedBy = "insuranceCompanyCodes", fetch = FetchType.LAZY)
private Set<Insurance> insurances = new HashSet<>();
}
I need to remove insurance items from the Patient object. I am using the following code:
for (Iterator<Insurance> iterator = patient.getInsurances().iterator(); iterator.hasNext();) {
iterator.next();
iterator.remove();
}
This seems to work for child entities that don't have child entities, however in this situation the Insurance entity has child entities and is not actually removed (no exceptions are displayed). Note, I am using the EclipseLink specific annotation #PrivateOwned which I expected would have forced the removal of the Insurance entities.
Any guidance, suggestions appreciated!

How to add new records to a field with #OneToOne in spring Data?

I am making a jsf + spring application.
The database contains a table of games and it is displayed on one of the pages of the site.
Each game has a genre list and development status. These fields are annotated with #OneToMany and #OneToOne respectively and are also tables in the database.
But here's the question: How do I add new games now? How do I initialize these fields? Because the only way I see is to create a new genre for a new game every time. That is, even if game A and games B are of the same genre, then I have to create two different unique genres, not one.
And how to initialize these fields from JSF?
For example from the <p: selectOneMenu> tag
game.java
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "game")
public class Game
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "name")
private String name;
#Column(name = "budget")
private String budget;
#Column(name = "profit")
private String profit;
#Column(name = "number")
private String number;
#OneToOne(optional = false, cascade = CascadeType.REFRESH)
#JoinColumn(name = "platform")
private Platform platform;
#OneToOne(optional = false, cascade = CascadeType.REFRESH)
#JoinColumn(name = "status")
private Status status;
#Column(name = "start")
private Date start;
#Column(name = "end")
private Date end;
#OneToMany(fetch = FetchType.EAGER)
#JoinTable(name = "game_genre",
joinColumns = #JoinColumn(name= "game_id"),
inverseJoinColumns = #JoinColumn(name= "genre_id"))
private List<Genre> listGenre;
public void update(Game new_game)
{
this.name = new_game.name;
this.budget = new_game.budget;
this.profit = new_game.profit;
this.number = new_game.number;
this.platform = new_game.platform;
this.status = new_game.status;
this.start = new_game.start;
this.end = new_game.end;
}
}
development status
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "status")
public class Status implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "Название")
private String Name;
#Column(name = "Описание")
private String description;
public void update(Status new_game)
{
this.description = new_game.description;
this.Name = new_game.Name;
}
}
genre:
#Setter
#Getter
#NoArgsConstructor
#AllArgsConstructor
#Entity
#Table(name = "genre")
public class Genre implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
public void update(Genre new_game)
{
this.name = new_game.name;
this.description = new_game.description;
}
}
Bean
#Component(value = "listgames")
#SessionScope
public class GamesView {
#Autowired
private GamesService gamesService;
private Map<Long, Boolean> checked = new HashMap<Long, Boolean>();
private List<Game> All_games = new ArrayList<Game>();
private Game newGame=new Game();
public Game getNewGame() {
return newGame;
}
public void setNewGame(Game newGame) {
this.newGame = newGame;
}
public void onRowEdit(RowEditEvent event) {
Game new_game=(Game)event.getObject();
All_games.get(new_game.getId()-1).update(new_game);
FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_INFO, "INFO", "X/Y edit successful!");
FacesContext.getCurrentInstance().addMessage(null, msg);
int i=0;
i++;
}
public void createNew() {
gamesService.addBank(newGame);
newGame = new Game();
}
public List<Game> getAll_games() {
return gamesService.getAll();
}
public void setAll_games(List<Game> all_games) {
All_games = all_games;
}
}

Spring-data-jpa same table name on two datasources "Duplicate entity name"

I'm using spring-data-jpa with two datasources,
but my two schema elettroforesi and capillare both have a table ANALISI
and Eclipse show me the following error:
"Duplicate entity name "Analisi" found in the persistence unit. Entity names must be unique."
the Config are the following:
#Configuration
#PropertySource({ "classpath:persistence-multiple-db.properties" })
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.interlabsrl.elfolab.persistence.multiple.repository.elettroforesi",
entityManagerFactoryRef = "elettroforesiEntityManager",
transactionManagerRef = "elettroforesiTransactionManager")
#ComponentScan(basePackages={"com.interlabsrl.elfolab.controller",
"com.interlabsrl.elfolab.persistence.multiple.service",
"com.interlabsrl.elfolab.persistence.multiple.cache"})
public class ElettroforesiConfig {
#Autowired
private Environment env;
public ElettroforesiConfig() {
super();
}
#Bean
#Primary
public LocalContainerEntityManagerFactoryBean elettroforesiEntityManager() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitName("elettroforesi");
em.setDataSource(elettroforesiDataSource());
em.setPackagesToScan(new String[] { "com.interlabsrl.elfolab.persistence.multiple.model.elettroforesi" });
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
final HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
properties.put("hibernate.jdbc.batch_size", env.getProperty("hibernate.jdbc.batch_size"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
#Primary
public DataSource elettroforesiDataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("elettroforesi.jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("elettroforesi.jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("elettroforesi.jdbc.pass")));
return dataSource;
}
#Bean
#Primary
public PlatformTransactionManager elettroforesiTransactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(elettroforesiEntityManager().getObject());
return transactionManager;
}
}
and
#Configuration
#PropertySource({ "classpath:persistence-multiple-db.properties" })
#EnableTransactionManagement
#EnableJpaRepositories(
basePackages = "com.interlabsrl.elfolab.persistence.multiple.repository.capillare",
entityManagerFactoryRef = "capillareEntityManager",
transactionManagerRef = "capillareTransactionManager")
#ComponentScan(basePackages={"com.interlabsrl.elfolab.controller",
// , "com.interlabsrl.elfolab.persistence.multiple.service"
// "com.interlabsrl.elfolab.persistence.multiple.cache"
})
public class CapillareConfig {
#Autowired
private Environment env;
public CapillareConfig() {
super();
}
#Bean
public LocalContainerEntityManagerFactoryBean capillareEntityManager() {
final LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPersistenceUnitName("capillare");
em.setDataSource(capillareDataSource());
em.setPackagesToScan(new String[] { "com.interlabsrl.elfolab.persistence.multiple.model.capillare" });
final HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
final HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
properties.put("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
properties.put("hibernate.jdbc.batch_size", env.getProperty("hibernate.jdbc.batch_size"));
em.setJpaPropertyMap(properties);
return em;
}
#Bean
public DataSource capillareDataSource() {
final DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("capillare.jdbc.url")));
dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("capillare.jdbc.user")));
dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("capillare.jdbc.pass")));
return dataSource;
}
#Bean
public PlatformTransactionManager capillareTransactionManager() {
final JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(capillareEntityManager().getObject());
return transactionManager;
}
}
while the entities:
package com.interlabsrl.elfolab.persistence.multiple.model.elettroforesi;
#Entity
#NamedQueries({
#NamedQuery(name = "Analisi.findAll", query = "SELECT a FROM Analisi a")})
#Table(schema="elettroforesi")
public class Analisi implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ID_ANALISI", nullable = false)
private Integer idAnalisi;
#Basic(optional = false)
#NotNull
#Column(nullable = false)
private short tracciato;
#Size(max = 30)
#Column(length = 30)
private String campione;
#Size(max = 40)
#Column(length = 40)
private String reparto;
#Column(name = "TOTALE_PROTEINE", precision = 12)
private Float totaleProteine;
#Column(name = "RAPP_AG", precision = 12)
private Float rappAg;
#Column(name = "DATA_MODIFICA")
#Temporal(TemporalType.TIMESTAMP)
private Date dataModifica;
#Column(name = "DATA_VALIDAZIONE")
#Temporal(TemporalType.TIMESTAMP)
private Date dataValidazione;
#Column(name = "DATA_CANCELLAZIONE")
#Temporal(TemporalType.TIMESTAMP)
private Date dataCancellazione;
#OneToMany(mappedBy = "idAnalisiLink")
private Collection<Analisi> analisiCollection;
#JoinColumn(name = "ID_ANALISI_LINK", referencedColumnName = "ID_ANALISI")
#ManyToOne
private Analisi idAnalisiLink;
#JoinColumn(name = "ID_ANALISI_IFE", referencedColumnName = "ID_ANALISI_IFE")
#ManyToOne
private AnalisiIfe idAnalisiIfe;
#JoinColumn(name = "ID_ANALISI_NOTA", referencedColumnName = "ID_ANALISI_NOTA")
#ManyToOne
private AnalisiNota idAnalisiNota;
#JoinColumn(name = "ID_PATOLOGICO", referencedColumnName = "ID_PATOLOGICO")
#ManyToOne
private Patologico idPatologico;
#JoinColumn(name = "ID_PAZIENTE", referencedColumnName = "ID_PAZIENTE", nullable = false)
#ManyToOne(optional = false)
private Paziente idPaziente;
#JoinColumn(name = "ID_SESSIONE", referencedColumnName = "ID_SESSIONE", nullable = false)
#ManyToOne(optional = false)
private Sessione idSessione;
#JoinColumn(name = "ID_TIPO_VALIDAZIONE", referencedColumnName = "ID_TIPO_VALIDAZIONE", nullable = false)
#ManyToOne(optional = false)
private TipoValidazione idTipoValidazione;
#JoinColumn(name = "ID_UTENTE_CANCELLAZIONE", referencedColumnName = "ID_UTENTE")
#ManyToOne(fetch=FetchType.LAZY)
private Utente idUtenteCancellazione;
#JoinColumn(name = "ID_UTENTE_MODIFICA", referencedColumnName = "ID_UTENTE")
#ManyToOne(fetch=FetchType.LAZY)
private Utente idUtenteModifica;
#JoinColumn(name = "ID_UTENTE_VALIDAZIONE", referencedColumnName = "ID_UTENTE")
#ManyToOne(fetch=FetchType.LAZY)
private Utente idUtenteValidazione;
#OneToMany(mappedBy = "idAnalisi", fetch=FetchType.LAZY)
private Collection<AnalisiFrazione> analisiFrazioneCollection;
#OneToMany(mappedBy = "idAnalisi", fetch=FetchType.LAZY)
private Collection<AnalisiAntisiero> analisiAntisieroCollection;
#OneToMany(mappedBy = "idAnalisi", fetch=FetchType.LAZY)
private Collection<AnalisiSmc> analisiSmcCollection;
#OneToMany(mappedBy = "idAnalisi", fetch=FetchType.LAZY)
private Collection<AnalisiCampoFree> analisiCampoFreeCollection;
#OneToMany(mappedBy = "idAnalisi", fetch=FetchType.LAZY)
private Collection<AnalisiDati> analisiDatiCollection;
#OneToMany(mappedBy = "idAnalisi")
private Collection<AnalisiNefelometrico> analisiNefelometricoCollection;
...
}
and
package com.interlabsrl.elfolab.persistence.multiple.model.capillare;
...
#Entity
#NamedQueries({
#NamedQuery(name = "Analisi.findAll", query = "SELECT a FROM Analisi a")})
#Table(schema="capillare")
public class Analisi implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(nullable = false)
private Long id;
#Column(name = "id_macchina")
private Integer idMacchina;
#Column(name = "id_metodiche")
private Integer idMetodiche;
#Column(name = "numero_sessione")
private Integer numeroSessione;
#Temporal(TemporalType.TIMESTAMP)
private Date dataora;
#Temporal(TemporalType.DATE)
private Date data;
#Size(max = 20)
#Column(name = "barcode_provetta", length = 20)
private String barcodeProvetta;
#Size(max = 20)
#Column(name = "barcode_rack", length = 20)
private String barcodeRack;
#Size(max = 100)
#Column(name = "dati_lettura", length = 100)
private String datiLettura;
private Short acquisito;
...
}
Your entities are both named Analisi, try to change the second one to Capillare.
You named the table Capillare, but the class is named Analisi

Error in a ManyToMany Relationship on Hibernate-JPA

I have a large DB on MySql Workbench and I'm trying to map the relationship between the entities on Eclipse Mars thanks to Hibernate and the JPA module. The fact is that I receive the error:
"In attribute 'personAddresses', the "mapped by" attribute 'peopleAdd' has an invalid mapping type for this relationship."
This are the entities involved.
1
I've to say that making a forward engineering, Hibernate creating for me an AddressId class, where the composite primary key of Address is mapped. I suspect that the problem could be this, but I'm not certain, can you help me please?
Under I post the code so that it's more clear to understand how the classes are implemented.
#Entity
#IdClass(AddressId.class)
#Table(schema = "YouDroop", name = "Address")
public class Address implements Serializable
{
...
private Collection<Person> peopleAdd = new HashSet<Person>();
#Id
#Column(name = "Address", length = 45, unique = true, nullable = false)
private String address;
#Id
#Column(name = "Number", unique = true, nullable = false)
private int number;
...
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(
name = "PersonHasAddress",
joinColumns = {
#JoinColumn(name = "Address_Address", referencedColumnName = "Address", nullable = false),
#JoinColumn(name = "Address_Number", referencedColumnName = "Number", nullable = false)
},
inverseJoinColumns = {#JoinColumn(name = "Person_Email", referencedColumnName = "Email", nullable = false)}
)
public Collection<Person> getPeopleAddressed(){
return this.peopleAdd;
}
public void setPeopleAddressed(Collection<Person> people){
this.peopleAdd = people;
}
}
public class AddressId implements Serializable
{
private String address;
private int number;
public AddressId(){}
public AddressId(String address, int number) {
super();
this.address = address;
this.number = number;
}
...
}
#Entity
#Table(name = "Person", schema = "YouDroop", uniqueConstraints =
{ #UniqueConstraint(columnNames = "NickName"),
#UniqueConstraint(columnNames = "Password") })
public class Person implements Serializable
{
...
private Collection<Address> addresses = new HashSet<Address>();
...
#ManyToMany(fetch = FetchType.LAZY, mappedBy = "peopleAdd")
public Collection<Address> getPersonAddresses(){
return this.addresses;
}
public void setPersonAddresses(Collection<Address> addresses){
this.addresses = addresses;
}
}
Since you placed you #ManyToMany annotation on your getter method (or property) and not on the field. The mappedBy attribute should reference the property instead and not the field.
#ManyToMany
public Collection<Person> getPeopleAddressed() {
...
}
So your mappedBy attribute should have been
#ManyToMany(mappedBy="peopleAddressed")
public Collection<Address> getPersonAddresses() {
...
}

ORA-01400: cannot insert NULL in #manytomany unidierctional

I am inserting a User object with roles(existing) roles .
It is giving me unable insert null in user_role.id
Schema:
#Entity
#Table(name = "user_data")
public class User extends Serializable {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
/**
* user can have set of roles profiles
*/
#ManyToMany(cascade = {CascadeType.ALL} ,fetch=FetchType.EAGER)
#JoinTable(name = "user_role", joinColumns = { #JoinColumn(name = "user_id", referencedColumnName = "id") }, inverseJoinColumns = { #JoinColumn(name = "role_id", referencedColumnName = "id") })
private Set<Role> roles;
}
#Entity #Table(name = "role")
public class Role extends Serializable {
private static final long serialVersionUID = -5954247513572163065L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "name")
private String name;
#ManyToMany
#JoinTable(name = "role_permission", joinColumns = { #JoinColumn(name = "role_id",
referencedColumnName = "id") },
inverseJoinColumns = { #JoinColumn(name = "permission_id",
referencedColumnName = "id") })
private Set<Permission> permissions;
[...]
}
Now when i am trying to create user it is giving me the exception
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("USER_ROLE"."ID")
For creating a user I am using spring repository code as below:
#Override
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public User createUser(User user) throws BusinessException {
List<Error> errors = new ArrayList<Error>();
validateUserRoles(user ,errors);
if ( errors.size() > 0 )
{
throw new BusinessException(errors);
}
user.setUserIdentifier(user.getUserIdentifier().trim());
logger.info("Creating User with username: " + user.getUserIdentifier());
return this.userRepositotry.save(user);
}
private void validateUserRoles(User user ,List<Error> errors) {
Set<Role> roles = new HashSet<Role>();
if (user.getRoles() != null)
{
for(Role role : user.getRoles())
{
Role r = null;
if(role.getId() != null)
{
r = this.roleRepository.findOne(role.getId());
} else if( role.getName() != null )
{
r = this.roleRepository.findByName(role.getName());
}
if(r == null)
{
errors.add(new Error(ErrorCode.INVALID_ARGUMENTS,"Invalid user Role.",r));
} else
{
roles.add(r);
}
}
}
user.setRoles(roles);
}
Your user_role join table has an id column, that Hibernate doesn't know about. All hibernate knows about is the role_id and user_id columns. The id column isn't useful, and you should remove it from the user_role table. If you leave it there, you need to make it nullable, or to make it have a default value.