2010-12-15 18 views
6

Ich habe eine Tabelle, die zusammengesetzte Primärschlüssel besteht aus einer Sequenz und zwei Fremdschlüssel Ich bin in der Lage, meine Entity-Klasse zu persistent, aber es wird nicht nach der Reihenfolge generiert. Die Tabelle, die zusammengesetzten Primärschlüssel aus einer Sequenz und zwei Fremdschlüssel, hbm2java in Maven hat ergibt folgende EinheitenJPA @EmbeddedId erzeugt keine Sequenz

Hier ist die Haupt Entity

 

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

} 

 

Hier ist die PK-Klasse eingebettet ist.

 

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


} 

 

Hier erwarte ich die Id automatisch generiert ... ich nur

 

@NaturalId 
 

und

 

@GeneratedValue(strategy=GenerationType.SEQUENCE) 
 

Ich habe auch mit GenerationType.AUTO aber haben versucht, hinzugefügt werden nicht arbeiten. Bitte vorschlagen.

+0

Ich vermute, Sie haben nicht empfangen eine Antwort, weil es einfach nicht gemacht werden kann. Ich habe einen ähnlichen Anwendungsfall (ein Primärschlüsselfeld von den dreien ist automatisch generiert (Bigserial in PostgreSQL)) und haben festgestellt, dass @GeneratedValue nur in Verbindung mit @Id verwendet werden kann. –

+1

Es ist erstaunlich, dass es nicht getan werden kann angesichts der Menge an Posts, die ich gesehen habe, nachdem ich danach gefragt habe.Ich habe es auf Unnachgiebigkeit seitens der Entwickler von Hibernate/Jpa/Eclipselink abgesehen, die nicht für einen etwas verbreiteten Anwendungsfall sorgen wollen. Eine der "wir wissen besser" Einstellungen. – BillR

Antwort

6

Es gibt eine Problemumgehung für dieses Problem. Ich habe die gleiche Bedingung, haben 4 Felder als zusammengesetzte Schlüssel, von denen 1 durch Sequenz generiert werden müssen. Ich habe überhaupt keine eingebettete Klasse erstellt, nur 1 @ Id-Feld, das durch Sequenz generiert werden muss. Rest alle Feldwerte werden einfache Spalten sein, wie referenzielle Integrität in DB erzwungen werden, und ich überprüfe auch Werte von Rest von 3 Feldern in Code, um nicht null zu sein.

Im Fehlerfall wird die Transaktion zurückgesetzt.

0

Ich möchte nur meine 2c hinzufügen. Dies funktioniert mit zusammengesetzten und einzelnen Primärschlüsseln. Verhindern Sie das Erstellen von Sequenzen, wählen Sie stattdessen max + 1 aus der Tabelle.

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 wie es SingleKeyEntity Beispiel folgt)

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