2010-12-15 12 views
6

Ho una tabella che ha una chiave primaria composta composta da una sequenza e due chiavi esterne Sono in grado di mantenere la mia classe entità ma non la generazione in base alla sequenza. La tabella che ha chiave primaria composito costituito da una sequenza e due chiavi esterne, hbm2java in Maven dà seguenti soggettiJPA @EmbeddedId non genera la sequenza

Ecco 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; 
} 

} 

 

Ecco la classe PK incorporato.

 

/** 
* 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; 
    } 


} 

 

Qui mi aspetto l'Id da generati automaticamente ... Ho aggiunto solo

 

@NaturalId 
 

e

 

@GeneratedValue(strategy=GenerationType.SEQUENCE) 
 

Ho anche provato con GenerationType.AUTO ma ha fatto non funziona. Si prega di suggerire.

+0

ho il sospetto che non hanno ricevuto una risposta perché non si può fare. Ho un caso d'uso simile (un campo chiave primario dei tre è autogenerato (bigserial in PostgreSQL)) e ho scoperto che @GeneratedValue può essere usato solo in congiunzione con @Id. –

+1

È incredibile che non possa essere eseguito data la quantità di post che ho visto chiedendo al riguardo.L'ho messo all'intransigenza da parte degli sviluppatori hibernate/jpa/eclipselink che non vogliono fornire un caso d'uso un po 'comune. Uno degli atteggiamenti "noi sappiamo meglio". – BillR

risposta

6

C'è una soluzione alternativa per questo problema. Ho affrontato la stessa condizione, ho 4 campi come chiavi composite, di cui 1 deve essere generato dalla sequenza. Non ho ancora creato la classe Embedded, ho solo 1 campo @Id che deve essere generato dalla sequenza. I valori di tutti i campi di riposo saranno semplici colonne, poiché l'integrità referenziale viene applicata nel DB e inoltre sto controllando i valori dei restanti 3 campi nel codice affinché non siano nulli.

In caso di errore, la transazione verrà ripristinata.

0

Voglio solo aggiungere il mio 2c. Funziona con chiavi primarie composite e singole. Prevenire la creazione di sequenze, invece, selezionare max + 1 dalla tabella.

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 come segue SingleKeyEntity esempio)

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; 
} 
Problemi correlati