JPA比较罕见的应用
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name= "file_type")
@Table(name="t_file")
public abstract class FileParent implements Serializable{
    @Id
    @TableGenerator(name="t_file_seq",allocationSize=1)
    @GeneratedValue(strategy=GenerationType.TABLE, generator="t_file_seq")
    private String id;
    
   //getters/setters;
}
@Embeddable
public class FileHeader{
  @Column(name="header_attr1")
  protected String headerAttr1;
  @Column(name="header_attr2")
  protected String headerAttr2;
  // getters/setters...
}
@Embedabble
public class FileBody{
  
}
@Entity
@DiscriminatorValue(value="0")
public class TypeAFile extends FileParent implements Serializable{
  @Embedded
  private TypeAFileHeader fileHeader;
  @Embedded
  private TypeAFileBody fileBody;
  
  public FileHeader getFileHeader(){
     return this.fileHeader
  }
 
  public void setFileHeader(FileHeader fileHeader){
     this.fileHeader = (TypeAFileHeader)fileHeader;
  }  public FileBody getFileBody(){
     return this.fileBody;
  }
 
  public void setFileBody(FileBody fileBody){
    this.fileBody = (TypeAFileBody)fileBody;
  }
}@Embeddable
public class TypeAFileHeader extends FileHeader{
  @Column(name="header_attr1")
  public String getHeaderAttr1(){
     return this.headerAttr1;
  }
  
  public void setHeaderAttr1(String headerAttr1){
    this.headerAttr1 = headerAttr1;
  }  @Column(name="header_attr2")
  public String getHeaderAttr2(){
     return this.headerAttr2;
  }
  
  public void setHeaderAttr2(String headerAttr2){
    this.headerAttr2 = headerAttr2;
  }
}
@Embedabble
public class TypeAFileBody{
  @Column(name="type_a_body_attr1")
  private String typeAbodyAttr1;
  @Column(name="type_a_body_attr2")
  private String typeAbodyAttr2;
  // getters/setters...
}@Entity
@DiscriminatorValue(value="1")
public class TypeBFile extends FileParent implements Serializable{
  @Embedded
  private TypeBFileHeader fileHeader;
  @Embedded
  private TypeBFileBody fileBody;
  
  public FileHeader getFileHeader(){
     return this.fileHeader
  }
 
  public void setFileHeader(FileHeader fileHeader){
     this.fileHeader = (TypeBFileHeader)fileHeader;
  }  public FileBody getFileBody(){
     return this.fileBody;
  }
 
  public void setFileBody(FileBody fileBody){
    this.fileBody = (TypeBFileBody)fileBody;
  }
}@Embeddable
public class TypeBFileHeader extends FileHeader{
  @Column(name="header_attr1")
  public String getHeaderAttr1(){
     return this.headerAttr1;
  }
  
  public void setHeaderAttr1(String headerAttr1){
    this.headerAttr1 = headerAttr1;
  }  @Column(name="header_attr2")
  public String getHeaderAttr2(){
     return this.headerAttr2;
  }
  
  public void setHeaderAttr2(String headerAttr2){
    this.headerAttr2 = headerAttr2;
  }
}
@Embedabble
public class TypeBFileBody{
  @Column(name="type_a_body_attr1")
  private String typeBbodyAttr1;
  @Column(name="type_b_body_attr2")
  private String typeBbodyAttr2;
  @Column(name="type_b_body_attr3")
  private String typeBbodyAttr3;
  // getters/setters...
}请问以上的JPA代码为什么不能生成以下的表结构:
t_file(id,dtype,header_attr1,header_attr2,type_a_body_attr1,type_a_body_attr2,type_b_body_attr1,type_b_body_attr2,type_b_body_attr3)
??
在这个里面,综合了@Inheritance与@Embedded批注的应用,
照理说应该可以生成以上的表结构的,但是在运行总是不行。
麻烦大虾指点下,谢谢。

解决方案 »

  1.   

    public class TypeBFileHeader extends FileHeader{ 我没测试过集成是否可以?我直接使用Entity的集成,上一级的是拿不到的。 我很奇怪为什么会这样。 给你个建议1 把所有的 Emb 都集中到一个类里面,先保证能成功
    2 然后再逐步修改代码,变成你期望的模样总之,不要一下子变动的因素太多,让你根本找不到头绪。一点一点refactor的过程
      

  2.   


    楼主:你说得很对,直接使用Entity的集成,上一级的是拿不到的。
    在子类中再get一下父类中的属性
    再加上@Column批注,就可以了,如下:
    @Embeddable 
    public class TypeAFileHeader extends FileHeader{ 
      @Column(name="header_attr1") 
      public String getHeaderAttr1(){ 
        return this.headerAttr1; 
      } 
      
      public void setHeaderAttr1(String headerAttr1){ 
        this.headerAttr1 = headerAttr1; 
      }   @Column(name="header_attr2") 
      public String getHeaderAttr2(){ 
        return this.headerAttr2; 
      } 
      
      public void setHeaderAttr2(String headerAttr2){ 
        this.headerAttr2 = headerAttr2; 
      } 
    } 谢谢你的建议,经过一上午的调试,这个表结构能够生成了。
    但是现在有另外一个问题:@Embeddable的实体中能不能有一个
    @OneToMany属性?如

    @Embedabble 
    public class TypeBFileBody{ 
      @Column(name="type_a_body_attr1") 
      private String typeBbodyAttr1; 
      @Column(name="type_b_body_attr2") 
      private String typeBbodyAttr2; 
      @Column(name="type_b_body_attr3") 
      private String typeBbodyAttr3;   @OneToMany(mappedBy="typeBFileBody")
      private List<AppendixFile> list;
      // getters/setters... 

    @Entity
    public class AppendixFile{
      @Id
      private String id;
      @JoinColumn(name="type_b_file_body_id",referencedColumnName="...")
      @ManyToOne
      private TypeBFileBody typeBFileBody;
      // getters/setter...
    }这样能行吗???
    谢谢,帮帮忙。
      

  3.   

    此问题已解决:
    为方法大家借鉴,现将解决方法给出如下:
    把TypeBFileBody类中的
    @OneToMany(mappedBy="typeBFileBody") 
      private List <AppendixFile> list; 放到
    @Entity 
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
    @DiscriminatorColumn(name= "file_type") 
    @Table(name="t_file") 
    public abstract class FileParent implements Serializable{ 
        @Id 
        @TableGenerator(name="t_file_seq",allocationSize=1) 
        @GeneratedValue(strategy=GenerationType.TABLE, generator="t_file_seq") 
        private String id; 
        
      //getters/setters; 

    中,并把类AppendixFile改成如下就行:
    @Entity 
    public class AppendixFile{ 
      @Id 
      private String id; 
      @JoinColumn(name="type_b_file_body_id")
    //注意一定不能是@JoinColumn(name="type_b_file_body_id",referencedColumnName="id")
    // 否则会报类FileParent.id没有映射的异常
      @ManyToOne 
      private TypeBFileBody typeBFileBody; 
      // getters/setter... 

      

  4.   

    不好意思,弄错了个地方
    embeddable类中不适合加@OneToMany的映射,因为它没有@Id
    (目前我是这么理解的,不知道是不是)
    应该是:把AppendixFile外键关联到TypeBFile.
    解决方法如下:
    把TypeBFileBody类中的 
    @OneToMany(mappedBy="typeBFileBody") 
      private List <AppendixFile> list; 
    修改一下
    放到 TypeBFile  中,如下
    @Entity 
    @DiscriminatorValue(value="1") 
    public class TypeBFile extends FileParent implements Serializable{ 
      @Embedded 
      private TypeBFileHeader fileHeader; 
      @Embedded 
      private TypeBFileBody fileBody; 
      
      @OneToMany(mappedBy="typeBFile") 
      private List <AppendixFile> list; 
      public FileHeader getFileHeader(){ 
        return this.fileHeader 
      }   public void setFileHeader(FileHeader fileHeader){ 
        this.fileHeader = (TypeBFileHeader)fileHeader; 
      }   public FileBody getFileBody(){ 
        return this.fileBody; 
      }   public void setFileBody(FileBody fileBody){ 
        this.fileBody = (TypeBFileBody)fileBody; 
      } 

    ,并把类AppendixFile改成如下就行: 
    @Entity 
    public class AppendixFile{ 
      @Id 
      private String id; 
      @JoinColumn(name="type_b_file_body_id") 
    //注意一定不能是@JoinColumn(name="type_b_file_body_id",referencedColumnName="id") 
    // 否则会报类FileParent.id没有映射的异常 
      @ManyToOne 
      private TypeBFile typeBFile ; 
      // getters/setter... 

      

  5.   

    class MyFile{
      @Embedded
      FileHeader header;  // getter/setter
    }@Embeddable
    abstract class FileHeader{  // @Embeddable 能是Abstract吗?
    }@Embeddable
    class MyFileHeader{
      //...
    }main(..){ MyFile myFile = new MyFile();
     myFile.setHeader(new MyFileHeader());    //以此实现多态,JPA支持吗?
    }以上方式能行吗?
      

  6.   

    以上方式是不行的 ,@Embeddable 不支持继承,多态,只能是类本身
    @Embeddable
    abstract class FileHeader{  // @Embeddable 能是Abstract吗?
    } 这种方式都无法 通过编译
    javax.persistence.PersistenceException: org.hibernate.InstantiationException: Cannot instantiate abstract class or interface: testjpa.FileHeader
            at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:637)
            at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:226)
            at testjpa.Main.persist(Main.java:55)
            at testjpa.Main.main(Main.java:36)
    Caused by: org.hibernate.InstantiationException: Cannot instantiate abstract class or interface: testjpa.FileHeader
      

  7.   


    楼上的,
    @Embeddable 是支持继承,多态的。
      

  8.   

    我在netbean下做的测试,不支持 ,用不用我把代码发上来
      

  9.   

    //我的例子如下,实体类是User,其中Man和Woman实体类继承自User
    //Embeddable类是BaseInfo,其中UserBaseInfo继承自BaseInfo
    @Entity
    @Table(name = "Users")
    @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name= "BBB",discriminatorType=DiscriminatorType.INTEGER)
    public class User implements Serializable {
    @Id
        @GeneratedValue(strategy = GenerationType.TABLE, generator = "customer_gen")
        @TableGenerator(name = "customer_gen",
        table = "tb_generator",
        pkColumnName = "gen_name",
        valueColumnName = "gen_value",
        pkColumnValue = "id",allocationSize = 1)
        private Long id;
        private String name;
    @Embedded
        private BaseInfo baseInfo;
    get/set......
    }@Embeddable
    public class BaseInfo implements java.io.Serializable {
        private String baseName;
    get/set......
        
    }
    //UserBaseInfo类继承BaseInfo类
    @Embeddable
    public class UserBaseInfo extends BaseInfo implements java.io.Serializable {
        private static final long serialVersionUID = 1L;
        private String address;
        private String email;
        private String telephone;
    get/set......
    }
    //Man类继承User类
    @Entity
    @DiscriminatorValue(value="2")
    public class Man extends User implements Serializable {
        private String manName;
    get/set......
    }
    //Woman类继承User类
    @Entity
    @DiscriminatorValue(value="1")
    public class Woman extends User implements Serializable {
        private String womainName;
    get/set......
    }
    //测试类如下
    public class Main extends User {
        /**
         * @param args the command line arguments
         */
        public static void main(String[] args) {
            Main m = new Main();
            UserBaseInfo userBaseInfo = new UserBaseInfo();
    userBaseInfo.setBaseName("haha112");
            userBaseInfo.setAddress("黑龙江");
            userBaseInfo.setEmail("[email protected]");
            Man man = new Man();
            man.setManName("男人aaaa");
            man.setBaseInfo(userBaseInfo);
    m.persist(man);
    } public void persist(Object object) {
            EntityManagerFactory emf = javax.persistence.Persistence.createEntityManagerFactory("TestjpaPU");
            EntityManager em = emf.createEntityManager();
            em.getTransaction().begin();
            try {
                em.persist(object);
                em.getTransaction().commit();
            } catch (Exception e) {
                e.printStackTrace();
                em.getTransaction().rollback();
            } finally {
                em.close();
            }
        }
    }
    persistence.xml如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <persistence version="1.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_1_0.xsd">
      <persistence-unit name="TestjpaPU" transaction-type="RESOURCE_LOCAL">
        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <class>testjpa.User</class>
        <class>testjpa.Man</class>
        <class>testjpa.Woman</class>
        <class>testjpa.MutiKeyTable</class>
        <class>testjpa.SinglePrimary</class>
        <properties>
          <property name="hibernate.connection.username" value="sa"/>
          <property name="hibernate.connection.driver_class" value="net.sourceforge.jtds.jdbc.Driver"/>
          <property name="hibernate.connection.password" value="123456"/>
          <property name="hibernate.connection.url" value="jdbc:jtds:sqlserver://localhost:1433/testjpa"/>
          <property name="hibernate.cache.provider_class" value="org.hibernate.cache.NoCacheProvider"/>
          <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
        </properties>
      </persistence-unit>
    </persistence>数据库字段如下
    BBB  id  baseName name   manName   womanName
    2 1 haha112   NULL 男人aaaa NULL可以说明继承类的字段没有被影射到数据库如果你在User类里面把BaseInfo 换成 UserBaseInfo的话,数据库字段如下BBB  id  address         email        telephone  name  manName   womanName
    2 1 哈尔滨333333333 [email protected]   NULL  NULL 男人aaaa NULL
    可以看出BaseInfo中的baseName没有被映射到数据库代码不全,可能有不对的地方,请指正