2010-12-15 5 views
6

J'ai une table qui a une clé primaire composite constituée d'une séquence et de deux clés étrangères Je suis capable de persister Ma classe d'entité mais elle ne génère pas selon la séquence. Le tableau qui a la clé primaire composite constitué d'une séquence et deux clés étrangères, hbm2java Maven suit donne des entitésJPA @EmbeddedId ne génère pas de séquence

Voici la principale entité

 

package aop.web.teacher.rmodels; 

// Generated Dec 14, 2010 8:45:32 PM by Hibernate Tools 3.2.2.GA 

import java.util.Date; 
import javax.persistence.AttributeOverride; 
import javax.persistence.AttributeOverrides; 
import javax.persistence.Column; 
import javax.persistence.EmbeddedId; 
import javax.persistence.Entity; 
import javax.persistence.FetchType; 
import javax.persistence.JoinColumn; 
import javax.persistence.ManyToOne; 
import javax.persistence.Table; 
import javax.persistence.Temporal; 
import javax.persistence.TemporalType; 

/** 
* Schoolmaster generated by hbm2java 
*/ 
@Entity 
@Table(name = "schoolmaster", schema = "public") 
public class Schoolmaster implements java.io.Serializable { 

private SchoolmasterId id; 
     ... 


@EmbeddedId 
@AttributeOverrides({ 
    @AttributeOverride(name = "id", column = @Column(name = "id", nullable = false)), 
    @AttributeOverride(name = "districtId", column = @Column(name = "district_id", nullable = false)), 
    @AttributeOverride(name = "typeOfSchool", column = @Column(name = "type_of_school", nullable = false)) }) 
public SchoolmasterId getId() { 
    return this.id; 
} 

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

@ManyToOne(fetch = FetchType.LAZY) 
@JoinColumn(name = "type_of_school", nullable = false, insertable = false, updatable = false) 
public AopTeachersTypeMaster getAopTeachersTypeMaster() { 
    return this.aopTeachersTypeMaster; 
} 

public void setAopTeachersTypeMaster(
    AopTeachersTypeMaster aopTeachersTypeMaster) { 
    this.aopTeachersTypeMaster = aopTeachersTypeMaster; 
} 

@ManyToOne(fetch = FetchType.LAZY) 
@JoinColumn(name = "school_nature") 
public AopTeachersSchoolNatureMaster getAopTeachersSchoolNatureMaster() { 
    return this.aopTeachersSchoolNatureMaster; 
} 

public void setAopTeachersSchoolNatureMaster(
    AopTeachersSchoolNatureMaster aopTeachersSchoolNatureMaster) { 
    this.aopTeachersSchoolNatureMaster = aopTeachersSchoolNatureMaster; 
} 

@ManyToOne(fetch = FetchType.EAGER) 
@JoinColumn(name = "district_id", nullable = false, insertable = false, updatable = false) 
public AopTeachersDistrictMaster getAopTeachersDistrictMaster() { 
    return this.aopTeachersDistrictMaster; 
} 

public void setAopTeachersDistrictMaster(
    AopTeachersDistrictMaster aopTeachersDistrictMaster) { 
    this.aopTeachersDistrictMaster = aopTeachersDistrictMaster; 
} 

@Column(name = "school_name", length = 50) 
public String getSchoolName() { 
    return this.schoolName; 
} 

public void setSchoolName(String schoolName) { 
    this.schoolName = schoolName; 
} 

@Column(name = "school_address") 
public String getSchoolAddress() { 
    return this.schoolAddress; 
} 

public void setSchoolAddress(String schoolAddress) { 
    this.schoolAddress = schoolAddress; 
} 

@Column(name = "school_phone_number", length = 12) 
public String getSchoolPhoneNumber() { 
    return this.schoolPhoneNumber; 
} 

public void setSchoolPhoneNumber(String schoolPhoneNumber) { 
    this.schoolPhoneNumber = schoolPhoneNumber; 
} 

@Temporal(TemporalType.DATE) 
@Column(name = "establishment_date", length = 13) 
public Date getEstablishmentDate() { 
    return this.establishmentDate; 
} 

public void setEstablishmentDate(Date establishmentDate) { 
    this.establishmentDate = establishmentDate; 
} 

@Column(name = "school_no_of_teachers") 
public Integer getSchoolNoOfTeachers() { 
    return this.schoolNoOfTeachers; 
} 

public void setSchoolNoOfTeachers(Integer schoolNoOfTeachers) { 
    this.schoolNoOfTeachers = schoolNoOfTeachers; 
} 

@Column(name = "school_no_of_students") 
public Integer getSchoolNoOfStudents() { 
    return this.schoolNoOfStudents; 
} 

public void setSchoolNoOfStudents(Integer schoolNoOfStudents) { 
    this.schoolNoOfStudents = schoolNoOfStudents; 
} 

} 

 

Voici la classe PK intégrée.

 

/** 
* SchoolmasterId generated by hbm2java 
*/ 
@Embeddable 
public class SchoolmasterId implements java.io.Serializable { 


    private long id; 
    private long districtId; 
    private long typeOfSchool; 

    public SchoolmasterId() { 
    } 

    public SchoolmasterId(long id, long districtId, long typeOfSchool) { 
     this.id = id; 
     this.districtId = districtId; 
     this.typeOfSchool = typeOfSchool; 
    } 


    @Column(name="id", nullable=false) 
    @GeneratedValue(strategy=GenerationType.SEQUENCE) 
    public long getId() { 
     return this.id; 
    } 

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

    @NaturalId 
    @Column(name="district_id", nullable=false) 
    public long getDistrictId() { 
     return this.districtId; 
    } 

    public void setDistrictId(long districtId) { 
     this.districtId = districtId; 
    } 
    @NaturalId 
    @Column(name="type_of_school", nullable=false) 
    public long getTypeOfSchool() { 
     return this.typeOfSchool; 
    } 

    public void setTypeOfSchool(long typeOfSchool) { 
     this.typeOfSchool = typeOfSchool; 
    } 


    public boolean equals(Object other) { 
     if ((this == other)) return true; 
    if ((other == null)) return false; 
    if (!(other instanceof SchoolmasterId)) return false; 
    SchoolmasterId castOther = (SchoolmasterId) other; 

    return (this.getId()==castOther.getId()) 
&& (this.getDistrictId()==castOther.getDistrictId()) 
&& (this.getTypeOfSchool()==castOther.getTypeOfSchool()); 
    } 

    public int hashCode() { 
     int result = 17; 

     result = 37 * result + (int) this.getId(); 
     result = 37 * result + (int) this.getDistrictId(); 
     result = 37 * result + (int) this.getTypeOfSchool(); 
     return result; 
    } 


} 

 

Ici, je me attends Id à ... autogénéré je n'ai ajouté

 

@NaturalId 
 

et

 

@GeneratedValue(strategy=GenerationType.SEQUENCE) 
 

J'ai aussi essayé avec GenerationType.AUTO mais a fait ne fonctionne pas. Veuillez nous suggérer.

+0

Je soupçonne que vous ne recevez pas une réponse parce que cela ne peut tout simplement pas être fait. J'ai un cas d'utilisation similaire (un champ de clé primaire sur les trois est autogénéré (bigserial dans PostgreSQL)) et a découvert que @GeneratedValue ne peut être utilisé qu'avec @Id. –

+1

C'est incroyable que cela ne puisse pas être fait étant donné le nombre de messages que j'ai vu poser à ce sujet.Je le mets à l'intransigeance de la part des développeurs hibernate/jpa/eclipselink qui ne veulent pas fournir un cas d'utilisation assez commun. Une des attitudes "nous savons mieux". – BillR

Répondre

6

Il existe une solution de contournement pour ce problème. J'ai fait face à la même condition, j'ai 4 champs en tant que clés composites, dont 1 doit être généré par séquence. Je n'ai pas créé de classe Embedded, j'ai seulement 1 champ @Id qui doit être généré par séquence. Reste toutes les valeurs de champs seront des colonnes simples, car l'intégrité référentielle est appliquée dans la base de données et aussi je vérifie les valeurs du reste de 3 champs dans le code pour être non nul.

En cas d'erreur, la transaction sera annulée.

0

Je veux juste ajouter mon 2c. Cela fonctionne avec les clés primaires composites et uniques. Empêcher de créer des séquences, sélectionnez à la place max + 1 dans la table.

Identifiable.java

package my.app.hibernate; 

import java.io.Serializable; 

public interface Identifiable<T extends Serializable> { 
    T getId(); 
} 

CompositeKeyEntity.java

package my.app.hibernate; 

import java.io.Serializable; 

public interface CompositeKeyEntity<T extends Serializable> extends Identifiable<T> { 
} 

SingleKeyEntity.java

package my.app.hibernate; 

import java.io.Serializable; 

public interface SingleKeyEntity<T extends Serializable> extends Identifiable<T> { 
} 

AssignedIdentityGenerator.java

package my.app.hibernate; 

import java.io.Serializable; 
import java.lang.reflect.Field; 
import java.util.Arrays; 
import java.util.List; 

import org.hibernate.Criteria; 
import org.hibernate.criterion.Projections; 
import org.hibernate.criterion.Restrictions; 
import org.hibernate.engine.spi.SessionImplementor; 
import org.hibernate.id.IdentityGenerator; 
import org.hibernate.internal.CriteriaImpl; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.security.util.FieldUtils; 

public class AssignedIdentityGenerator extends IdentityGenerator { 
    private static final String ID_FIELD_NAME = "id"; 
    private final Logger LOG = LoggerFactory.getLogger(this.getClass()); 
    private Field sequenceField; 
    private String entityClassName; 

    @Override 
    public Serializable generate(SessionImplementor session, Object obj) { 
     @SuppressWarnings("unchecked") 
     Identifiable<Serializable> identifiable = (Identifiable<Serializable>)obj; 

     entityClassName = obj.getClass().getName(); 
     Criteria criteria = new CriteriaImpl(entityClassName, session); 
     criteria.setReadOnly(true); 
     Object toSet = null; 

     if (identifiable instanceof CompositeKeyEntity) { 
      Serializable id = identifiable.getId(); 
      if (id != null) { 
       String embaddebleClassName = id.getClass().getName(); 
       buildCriteriaForEmbeddedId(id, embaddebleClassName, criteria); 
       toSet = id; 
      } 
     } else if (obj instanceof SingleKeyEntity) { 
      toSet = identifiable; 
      sequenceField = FieldUtils.getField(identifiable.getClass(), ID_FIELD_NAME); 
      buildCriteriaForSingleId(criteria); 
     } 

     Number one = castToSequenceNumberType(1L); 
     Number value = (Number) criteria.uniqueResult(); 

     if(value != null) { 
      value = castToSequenceNumberType(value.longValue() + one.longValue()); 

      setFieldValue(sequenceField, value, toSet); 
     } else { 
      value = one; 
      setFieldValue(sequenceField, value, toSet); 
     } 

     return identifiable.getId(); 
    } 

    private void buildCriteriaForSingleId(Criteria criteria) { 
     criteria.setProjection(Projections.max(ID_FIELD_NAME).as("seq")); 
    } 

    private void buildCriteriaForEmbeddedId(Serializable id, String embaddebleClassName, Criteria criteria) { 
     List<Field> fields = Arrays.asList(id.getClass().getDeclaredFields()); 

     class Utils { 
      Field field; 
      boolean numberFound = false; 
     } 
     final Utils utils = new Utils(); 

     for (Field field : fields) { 
      if ("serialVersionUID".equals(field.getName()) || "$jacocoData".equals(field.getName())) { 
       continue; 
      } 

      if (Number.class.isAssignableFrom(field.getType())) { 
       if (utils.numberFound) { 
        throw new IllegalArgumentException(
          embaddebleClassName + " has more then one sequence field: " + field.getName() + ", " 
            + utils.field.getName() + ",..."); 
       } 

       utils.numberFound = true; 
       utils.field = field; 
       sequenceField = field; 

       criteria.setProjection(Projections.max(ID_FIELD_NAME + "." + sequenceField.getName()).as("seq")); 
      } else { 
       criteria.add(Restrictions.eq(ID_FIELD_NAME + "." + field.getName(), getFieldValue(field, id))); 
      } 
     } 
    } 

    private Number castToSequenceNumberType(Number n) { 
     return (Number) sequenceField.getType().cast(n); 
    } 

    private void setFieldValue(Field field, Object value, Object to) { 
     try { 
      field.setAccessible(true); 
      field.set(to, value); 
     } catch (IllegalArgumentException | IllegalAccessException e) { 
      LOG.error(e.getMessage(), e); 
     } 
    } 

    private Object getFieldValue(Field field, Object from) { 
     try { 
      field.setAccessible(true); 
      return field.get(from); 
     } catch (IllegalArgumentException | IllegalAccessException e) { 
      LOG.error(e.getMessage(), e); 
     } 

     return null; 
    } 
} 

Customer.java

package my.app.entities; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import org.hibernate.annotations.GenericGenerator; 

import my.app.hibernate.SingleKeyEntity; 

@Entity(name = "whatever_entity_name") 
@GenericGenerator(name = "WHATEVER_NAMED_GENERATOR", strategy = "my.app.hibernate.AssignedIdentityGenerator") 
public class Customer implements SingleKeyEntity<Long> { 

    @Id 
    @GeneratedValue(generator = "WHATEVER_NAMED_GENERATOR") 
    private Long id; 
    @Column(nullable = false) 
    private String name; 
} 

CustomerItemsId.java (Item.java ommited comme suit par exemple SingleKeyEntity)

package my.app.entities; 

import javax.persistence.Embeddable; 
import javax.persistence.JoinColumn; 
import javax.persistence.ManyToOne; 

@Embeddable 
public class CustomerItemsId implements Serializable { 
    private static final long serialVersionUID = 1L; //generate one 

    @ManyToOne 
    @JoinColumn(name = "customer_id") 
    private Customer customer; 
    @ManyToOne 
    @JoinColumn(name = "item_id") 
    private Item item; 
    private Long seq; //name as you wish 
} 

CustomerItems.java

package my.app.entities; 

import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.GeneratedValue; 
import javax.persistence.Id; 
import org.hibernate.annotations.GenericGenerator; 

import my.app.hibernate.CompositeKeyEntity; 

@Entity(name = "whatever_entity_name") 
@GenericGenerator(name = "WHATEVER_NAMED_GENERATOR", strategy = "my.app.hibernate.AssignedIdentityGenerator") 
public class CustomerItems implements CompositeKeyEntity<CustomerItemsId> { 

    @GeneratedValue(generator = "WHATEVER_NAMED_GENERATOR") 
    private CustomerItems id; 
    @Column(nullable = false) 
    private String randomColumn1; 
    @Column(nullable = false) 
    private String randomColumn2; 
} 
Questions connexes