0

I am currently learning Hibernate and the Java Persistence API with SPRING. I have an @Entity Class "profil" with bidirectionnal association @oneToMany to other @Entity Class "Category". I want to get profilA.Set and save into profilB.set but it does not seem to commit to database.

@Entity
@Table(name = "profil", catalog = "valife", uniqueConstraints = @UniqueConstraint(columnNames = {
        "email", "login" }))
public class Profil implements java.io.Serializable {

    private Long id;
    private int version;
    private String login;
    private String password;
    private String lastname;
    private String firstname;
    private Timestamp creationdate;
    private Timestamp lastaccesdate;
    private boolean enabled;
    private String email;
    private FinancialAccountbook financialAccountbook;
    private NeedsAccountbook needsAccountbook;
    private StockAccountbook stockAccountbook;

    private Set<Category> categories = new HashSet<Category>(0);;
    private Set<Payee> payees = new HashSet<Payee>(0);

    public Profil() {
    }

    public Profil(String login, String password, Timestamp creationdate,
            Timestamp lastaccesdate, boolean enabled, String email) {
        this.login = login;
        this.password = password;
        this.creationdate = creationdate;
        this.lastaccesdate = lastaccesdate;
        this.enabled = enabled;
        this.email = email;
    }

    public Profil(String login, String password, String lastname,
            String firstname, Timestamp creationdate, Timestamp lastaccesdate,
            boolean enabled, String email) {
        this.login = login;
        this.password = password;
        this.lastname = lastname;
        this.firstname = firstname;
        this.creationdate = creationdate;
        this.lastaccesdate = lastaccesdate;
        this.enabled = enabled;
        this.email = email;
    }

    @Id
    @GeneratedValue(strategy = IDENTITY)
    @Column(name = "id", unique = true, nullable = false)
    public Long getId() {
        return this.id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Version
    @Column(name = "version", nullable = false)
    public int getVersion() {
        return this.version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    @Column(name = "login", nullable = false, length = 50)
    @NotNull
    public String getLogin() {
        return this.login;
    }

    public void setLogin(String login) {
        this.login = login;
    }

    @Column(name = "password", nullable = false, length = 50)
    @NotNull
    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Column(name = "lastname", length = 50)
    public String getLastname() {
        return this.lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    @Column(name = "firstname", length = 50)
    public String getFirstname() {
        return this.firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "creationdate", nullable = false, length = 19)
    public Date getCreationdate() {
        return this.creationdate;
    }

    public void setCreationdate(Timestamp creationdate) {
        this.creationdate = creationdate;
    }

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "lastaccesdate", nullable = false, length = 19)
    public Date getLastaccesdate() {
        return this.lastaccesdate;
    }

    public void setLastaccesdate(Timestamp lastaccesdate) {
        this.lastaccesdate = lastaccesdate;
    }

    @Column(name = "enabled", nullable = false)
    public boolean isEnabled() {
        return this.enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    @Column(name = "email", nullable = false, length = 50)
    @NotNull
    @Email
    public String getEmail() {
        return this.email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @OneToOne(mappedBy = "profil")
    public FinancialAccountbook getFinancialAccountbook() {
        return financialAccountbook;
    }

    public void setFinancialAccountbook(
            FinancialAccountbook financialAccountbook) {
        this.financialAccountbook = financialAccountbook;
    }

    @OneToOne(mappedBy = "profil")
    public NeedsAccountbook getNeedsAccountbook() {
        return needsAccountbook;
    }

    public void setNeedsAccountbook(NeedsAccountbook needsAccountbook) {
        this.needsAccountbook = needsAccountbook;
    }

    @OneToOne(mappedBy = "profil")
    public StockAccountbook getStockAccountbook() {
        return stockAccountbook;
    }

    public void setStockAccountbook(StockAccountbook stockAccountbook) {
        this.stockAccountbook = stockAccountbook;
    }

    @OneToMany(mappedBy = "profil", fetch = FetchType.LAZY, cascade = { CascadeType.ALL })
    public Set<Category> getCategories() {
        return categories;
    }

    @Transactional
    public void setCategories(Set<Category> catSet) {

        this.categories = catSet;

    }

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "profil")
    public Set<Payee> getPayees() {
        return payees;
    }

    public void setPayees(Set<Payee> payees) {
        this.payees = payees;
    }

    @Transient
    @SuppressWarnings("unchecked")
    protected <T extends Appendix> Set<T> getAppendixInternal(Class<T> type) {
        Set<T> appendix = null;
        if (type == Category.class) {
            if (this.getCategories() == null) {
                this.categories = new HashSet<Category>();
            }
            appendix = (Set<T>) this.categories;

        }
        if (type == Payee.class) {
            if (this.getPayees() == null) {
                this.payees = new HashSet<Payee>();
            }
            appendix = (Set<T>) this.payees;

        }
        return appendix;
    }

    @Transient
    protected <T extends Appendix> List<T> getSortedAppendix(Class<T> type) {
        List<T> sortedPets = new ArrayList<T>(getAppendixInternal(type));
        PropertyComparator.sort(sortedPets, new MutableSortDefinition("name",
                true, true));
        return Collections.unmodifiableList(sortedPets);
    }

    @Transient
    @SuppressWarnings("unchecked")
    public List<Payee> getSortedPayees() {
        return (List<Payee>) this.getAppendixInternal(Payee.class);
    }

    @Transient
    @SuppressWarnings("unchecked")
    public List<Category> getSortedCategories() {
        return (List<Category>) this.getAppendixInternal(Category.class);
    }

    public void addPayee(Payee payee) {
        this.getPayees().add(payee);
        payee.setProfil(this);
    }

    @Transactional
    public void addCategory(Category cat) {
        cat.setProfil(this);
        this.getCategories().add(cat);

    }
}

here the code for the test:

        java.util.Date date = new java.util.Date();
        Timestamp currentdate = new Timestamp(date.getTime());
        assertTrue(true);
        Profil profil = new Profil();
        profil.setLogin("default_EN");
        profil.setEnabled(false);
        profil.setPassword("default_EN");
        profil.setCreationdate(currentdate);
        profil.setLastaccesdate(currentdate);
        profil.setEmail("defaultEN@valife.org");
        Profil defaultFRprofil = (Profil) dao.find(new Long(1));
        assertEquals("default_FR", defaultFRprofil.getLogin());
        // dao.deleteObject(dao.find(new Long(8)));
        assertTrue(true);
        Set<Category> cat = new HashSet<Category>(
                defaultFRprofil.getCategories());

        assertTrue(true);
        profil.setCategories(cat);
        assertTrue(true);

        dao.saveObject(profil);

What i want: get profilA.categories (set) and save a new set persistent into profilB.catagories so that in database i will have:

#

|//id//|bigint(20) |version|int(11) |name|varchar(50) |profilid|bigint(20)

|1|1|AUTOMOBILE|1 <- profilA

|15|1|AUTOMOBILE|2 <- profilB

Here the code for @Entity Category

package org.egilbox.valife_springMVC.java.domain.model;

import static javax.persistence.GenerationType.IDENTITY;

import java.io.Serializable;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;

import org.hibernate.validator.constraints.NotEmpty;

@MappedSuperclass
public abstract class Appendix implements Serializable {

private Long id;
private int version;
private String name;

private Profil profil;

@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Long getId() {
    return this.id;
}

public void setId(Long id) {
    this.id = id;
}

@Version
@Column(name = "version", nullable = false)
public int getVersion() {
    return this.version;
}

public void setVersion(int version) {
    this.version = version;
}

@Column(name = "name", unique = false, nullable = false, length = 50)
@NotNull
@NotEmpty
public String getName() {
    return this.name;
}

public void setName(String name) {
    this.name = name;
}

@ManyToOne(cascade = { CascadeType.ALL })
@JoinColumn(name = "profilid", nullable = false)
@NotNull
public Profil getProfil() {
    return this.profil;
}

public void setProfil(Profil profil) {
    this.profil = profil;
}

}



  @Entity
  @Table(name = "category", catalog = "valife", uniqueConstraints =               @UniqueConstraint(columnNames = "name"))
  public class Category extends Appendix {}

Code for DAO:

  public abstract class GenericDAOWithHibernate<T, ID extends Serializable> {

private Class<T> persistentClass;
@PersistenceContext(unitName = "entityManager", properties = @PersistenceProperty(name = "org.hibernate.flushMode", value = "AUTO"))
protected EntityManager entityManager;

@SuppressWarnings("unchecked")
public GenericDAOWithHibernate() {
    this.persistentClass = (Class<T>) ((ParameterizedType) getClass()
            .getGenericSuperclass()).getActualTypeArguments()[0];
}

public void setEntityManager(EntityManager entityManager) {
    this.entityManager = entityManager;
}

public Class<T> getPersistentClass() {
    return persistentClass;
}

public T find(ID id) {
    return entityManager.find(persistentClass, id);
}

@Transactional(propagation = Propagation.MANDATORY)
public void saveObject(T entity) {
    entityManager.persist(entity);
}

@Transactional(propagation = Propagation.MANDATORY)
public void deleteObject(T entity) {
    entityManager.remove(entity);
}

public List<T> findAll() {
    CriteriaQuery cq = this.entityManager.getCriteriaBuilder()
            .createQuery();
    cq.select(cq.from(persistentClass));
    return this.entityManager.createQuery(cq).getResultList();
}
// Inner classes

 } // end class GenericDAOWithHibernate

XML configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans  http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">

<!--  RESOURCES DEFINITION -->
<bean id ="datasource"
class ="org.springframework.jdbc.datasource.DriverManagerDataSource">
 <property name="driverClassName" value= "com.mysql.jdbc.Driver" />
 <property name="password" value="XXX" />
 <property name="url" value ="jdbc:mysql://localhost/valife" />
 <property name="username" value="XXX" />
</bean>
<context:component-scan
        base-package="org.egilbox.valife_springMVC.java.domain"/>
<bean id ="persistenceUnitManager"
class ="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManager" >
<property name="defaultDataSource" ref="datasource" />

<property name="persistenceXmlLocations">
    <list>
    <value>classpath*:META-INF/persistance.xml</value>
    </list>
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" >
<property name="persistenceUnitManager" ref="persistenceUnitManager" />
<property name="persistenceUnitName" value="entityManager" />
</bean>

<bean id ="transactionManager"
class ="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
<context:annotation-config></context:annotation-config>
</beans>

Persitance.xml:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence   http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd ">
<persistence-unit name="entityManager" transaction-type ="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
 <property name="hibernate.dialect" value ="org.hibernate.dialect.MySQLDialect" />
 <property name= "hibernate.show_sql" value ="true" />
</properties>
</persistence-unit>
</persistence>

4 Answers4

0

There are two options to save Set:

Save the serializable version, hence you must annotate the field as:

 @Lob
 private Set<Category> categories;

This is not normally we do it.

Have a relationship (I assume that Category is an entity)

@OneToMany
@LazyCollection(FALSE) //whether you want eager fetching or not, this is the way hibernate handles it
private List<Category> categories;
maress
  • 3,533
  • 1
  • 19
  • 37
  • have added this @lazyCollection (False) but still nothing in database. – user3770624 Jun 24 '14 at 10:47
  • remove the fetch=FetchType.LAZY on the OneToMany relationship, for hibernate, it should be actually throwing for you some errors – maress Jun 24 '14 at 11:05
  • thank you for your response. I put annotation on method, should i annote fields instead? – user3770624 Jun 24 '14 at 11:43
  • It really does not matter, just make sure you dont mix both field and method annotation – maress Jun 24 '14 at 11:49
  • To use @lazyCollection, i have to get a hibernate session but in my DAO i declare '@PersistenceContext(unitName = "entityManager", properties = @PersistenceProperty(name = "org.hibernate.flushMode", value = "AUTO")) protected EntityManager entityManager;' with the common XMl configuration. How to ensure that Spring delegates the entityManager to hibernate session? – user3770624 Jun 24 '14 at 14:50
0

You should add @JoinColumn(name = "your_foreign_key_id") to specify where to store the relation

StanislavL
  • 56,971
  • 9
  • 68
  • 98
  • i have this in my @Entity class "Category". When i use test with the method addCategory , it wokrs well for just one Category. it means that hibernate knows how to store the relation. – user3770624 Jun 24 '14 at 11:21
0

try to override equals and hashCode on the Category Class so you can use the Collection (set or hashset ) properly.

this is an example as it depands on the logic that you applied :

import com.google.common.base.Objects;
import static com.google.common.base.Objects.equal;

@Override
public boolean equals(Object obj) {
    return obj == this
            || (obj instanceof Category && equals((Category) obj));
}

private final boolean equals(Category other) {
    return other != null && equal(name, other.name)
            && equal(profil, other.profil);
}

@Override
public int hashCode() {
    return Objects.hashCode(name, profil, getClass());
}
Rafik BELDI
  • 4,140
  • 4
  • 24
  • 38
0

I have figured it out. My issue is about copying or cloning JPA entity already persisted in the database. So, this topic Cloning JPA entity may help. I also use the JpaCloner to clone my entity, so i get new transient cloned entity and i can therefore save a new instance in database with the same fields but the profilID field.

Community
  • 1
  • 1