2010-12-15 33 views
6

Tengo una tabla que tiene una clave primaria compuesta que consta de una secuencia y dos claves externas Soy capaz de persistir en mi clase de entidad pero no está generando según la secuencia. La tabla que tiene la clave principal compuesta que consiste en una secuencia y dos claves externas, en hbm2java experto da siguientes entidadesJPA @EmbeddedId no está generando la secuencia

Esta es la principal entidad

 

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

} 

 

Aquí está la clase PK incrustado.

 

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


} 

 

Aquí estoy esperando la identificación que se genera automáticamente ... Sólo he añadido

 

@NaturalId 
 

y

 

@GeneratedValue(strategy=GenerationType.SEQUENCE) 
 

También he tratado con GenerationType.AUTO pero lo hizo no trabajo. Por favor sugiera.

+0

Sospecho que no han recibido una respuesta porque simplemente no se puede hacer. Tengo un caso de uso similar (un campo de clave principal de los tres es autogenerado (bigserial en PostgreSQL)) y descubrí que @GeneratedValue solo se puede usar junto con @Id. –

+1

Es increíble que no se pueda hacer dada la cantidad de publicaciones que he visto al respecto.Lo atribuyo a la intransigencia de los desarrolladores de hibernate/jpa/eclipselink que no desean proporcionar un caso de uso común. Una de las actitudes de 'nosotros sabemos mejor'. – BillR

Respuesta

6

Hay una solución para este problema. He enfrentado la misma condición, tengo 4 campos como claves compuestas, de los cuales 1 debe generarse por secuencia. No he creado clase Embedded en absoluto, solo tengo 1 campo @Id que debe generarse por secuencia. Todos los valores de campo serán columnas simples, ya que la integridad referencial se aplica en DB y también estoy verificando los valores del resto de 3 campos en el código para que no sean nulos.

En caso de error, la transacción se retrotraerá.

0

Solo quiero agregar mi 2c. Esto funciona con claves primarias compuestas y únicas. Evite crear secuencias, en su lugar, seleccione max + 1 de la tabla.

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 omite, ya que sigue SingleKeyEntity ejemplo)

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; 
} 
Cuestiones relacionadas