<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      只為成功找方向,不為失敗找借口

      每天都不能停止前進的腳步
        博客園  :: 首頁  :: 新隨筆  :: 聯系 :: 訂閱 訂閱  :: 管理

      JPA 不生成外鍵

      Posted on 2018-08-20 17:38  冰碟  閱讀(8683)  評論(0)    收藏  舉報

      在用jpa這種orm框架時,有時我們實體對象存在關聯關系,但實際的業務場景可能不需要用jpa來控制數據庫創建數據表之間的關聯約束,這時我們就需要消除掉數據庫表與表之間的外鍵關聯。
      但jpa在處理建立外鍵時存在一些問題,在stackoverflow上搜索了相關的jpa創建實體對象關聯關系但不建立外鍵這一系列問題后,發現這個是jpa在處理外鍵時存在一定的bug,官方給出的答復是在hibernate 5.x會解決掉這個問題,但是經驗證5.x的版本這個問題依舊存在。下面給出這個問題的解釋以及這個問題如何解決。

      下面會以techer和student對象來舉例,teacher和student存在一對多關系,一個teacher關聯多個student。

      1.teacher與student設置外鍵關系

      teacher和student之間通過@OneToMany和@ManyToOne建立外鍵關聯關系
      teacher:

      @Entity
      @Table(name = "TEACHER")
      public class Teacher extends BaseDomain {
          @Id()
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          @Column(name = "ID")
          private Long id;
      
          @Column
          private String name;
      
          @OneToMany(mappedBy = "teacher")
          private List<Student> students;
          
          //getter&setter...
      }

       


      student: 

      @Entity
      @Table(name = "STUDENT")
      public class Student extends BaseDomain {
      
          @Id()
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          @Column(name = "ID")
          private Long id;
      
          @Column
          private String name;
      
          @ManyToOne
          @JoinColumn(name = "tid")
          private Teacher teacher;
      
          //getter&setter...
      }

       


      數據庫生成表結果: 

      CREATE TABLEpublic”.”student” (
      “id” int8 DEFAULT nextval(‘student_id_seq’::regclass) NOT NULL,
      “name” varchar(255) COLLATE “default”,
      “teacher_id” int8,
      CONSTRAINT “student_pkey” PRIMARY KEY (“id”),
      CONSTRAINT “fk3y5qg5r9ewc48x7ek8lx5ua8h” FOREIGN KEY (“teacher_id”) REFERENCESpublic”.”teacher” > (“id”) ON DELETE NO ACTION ON UPDATE NO ACTION
      )
      WITH (OIDS=FALSE)
      ;
      ALTER TABLEpublic”.”student” OWNER TO “postgres”;

       

      可以看到設置了外鍵”fk3y5qg5r9ewc48x7ek8lx5ua8h” FOREIGN KEY (“teacher_id”)

      2.只在student端加上@ForeignKey

      student

      @Entity
      @Table(name = "STUDENT")
      public class Student extends BaseDomain {
      
          @Id()
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          @Column(name = "ID")
          private Long id;
      
          @Column
          private String name;
      
          @ManyToOne
          @JoinColumn(name = "tid",foreignKey = @ForeignKey(name = "none",value = ConstraintMode.NO_CONSTRAINT))
          private Teacher teacher;
      
          //setter&getter
      }

       


      加上該注解之后,根據這個注解說明是可以去掉外鍵關聯關系,但發現加上后然并卵,外鍵還是沒有去掉。這里需要說明其中@ForeignKey的value值由如下代碼所示幾種情況: 

       

      /**
       * Used to control the application of a constraint.
       *
       * @since JPA 2.1
       */
      public enum ConstraintMode {
          /**
           * Apply the constraint.
           */
          CONSTRAINT,
          /**
           * Do not apply the constraint.
           */
          NO_CONSTRAINT,
          /**
           * Use the provider-defined default behavior.
           */
          PROVIDER_DEFAULT
      }

       

       

      3.在teacher端加入@org.hibernate.annotations.ForeignKey(name = “none”)

      在一的這端加上@org.hibernate.annotations.ForeignKey(name = “none”)這個被jpa廢棄的注解。加上之前在student中設置的@ForeignKey(注意這個是javax.persistence包下的),可以去掉外鍵關聯
      teacher:

      @Entity
      @Table(name = "TEACHER")
      public class Teacher extends BaseDomain {
          @Id()
          @GeneratedValue(strategy = GenerationType.IDENTITY)
          @Column(name = "ID")
          private Long id;
      
          @Column
          private String name;
      
          @OneToMany(mappedBy = "teacher")
          @org.hibernate.annotations.ForeignKey(name = "none")
          private List<Student> students;
          
          //getter&setter...
      }

       


      結果: 

      CREATE TABLEpublic”.”student” (
      “id” int8 DEFAULT nextval(‘student_id_seq’::regclass) NOT NULL,
      “createdtime” timestamp(6),
      “name” varchar(255) COLLATE “default”,
      “version” int4,
      “tid” int8,
      CONSTRAINT “student_pkey” PRIMARY KEY (“id”)
      )
      WITH (OIDS=FALSE)
      ;
      ALTER TABLEpublic”.”student” OWNER TO “postgres”;

       

      可以看到student表中原來關聯teacher的外鍵沒了,說明該注解起作用。

      4.需要注意的坑

      1.如果teacher(1的這端)有student列表(多的這端),像這樣:

      @OneToMany(mappedBy = "teacher")
      @org.hibernate.annotations.ForeignKey(name = "none")
      private List<Student> students;

       


      如果要去掉外鍵關聯關系,student端也需要像在2小結提到樣需要加上@JoinColumn(name = “tid”,foreignKey = @ForeignKey(name = “none”,value = ConstraintMode.NO_CONSTRAINT)),但此時你會發現其中@ForeignKey中value的值不管你設置為ConstraintMode.NO_CONSTRAINT還是ConstraintMode.CONSTRAINT,數據庫都不會設置外鍵(這個是特么的真奇怪)。但是就是不管怎樣,你就是不能不設置@ForeignKey,并且你還必須要設置其中的值不能為默認值,不然就是要生成外鍵。這里貼下@ForeignKey的源碼: 

       

      @Target({})
      @Retention(RUNTIME)
      public @interface ForeignKey {
          /**
           * (Optional) The name of the foreign key constraint.  Defaults to a provider-generated name.
           *
           * @return The foreign key name
           */
          String name() default "";
      
          /**
           * (Optional) The foreign key constraint definition.  Default is provider defined.  If the value of
           * disableForeignKey is true, the provider must not generate a foreign key constraint.
           *
           * @return The foreign key definition
           */
          String foreignKeyDefinition() default "";
      
          /**
           * (Optional) Used to specify whether a foreign key constraint should be generated when schema generation is in effect.
           */
          ConstraintMode value() default ConstraintMode.CONSTRAINT;
      }

       

      真的是X了狗了。。。我表示久久不能理解。。。 

      2.teacher(1這端)沒有student列表或者student列表被@Transient所修飾,像這樣:

       

      @OneToMany(mappedBy = "teacher")
      @Transient
      private List<Student> students;

       

      那么也是無論你在student端設置ConstraintMode的值,都不會設置外鍵.but!!!你就是不能不在student端(多的這端)設置@JoinColumn(name=”tid”,foreignKey=@ForeignKey(name=”none”,value=ConstraintMode.NO_CONSTRAINT)),否則也是會生成外鍵 

      總結

      所以要使數據表中沒有外鍵關聯關系。
      1.當兩邊都有關聯關系字段,1的這端利用@org.hibernate.annotations.ForeignKey(name = “none”),多的那端在JoinColumn中加上foreignKey = @ForeignKey(name = “none”,value = ConstraintMode.NO_CONSTRAINT)

      2.當只有多的那端有關聯字段,一的那段沒有關聯字段或者關聯字段被@Transient所修飾,請在多的那端在JoinColumn中加上foreignKey = @ForeignKey(name = “none”,value = ConstraintMode.NO_CONSTRAINT)

      最后需要說明的是@org.hibernate.annotations.ForeignKey(name = “none”)這個注解之后可能會在之后的版本會被直接移除掉,所以更新jar包的時候需要注意下。

      參考資料:
      ①.https://hibernate.atlassian.net/browse/HHH-8805
      ②.https://hibernate.atlassian.net/browse/HHH-8862

       

       

      親測可用;

       

      第二種辦法:

       

       

        關于如何禁用Hibernate生成外鍵,網上有使用設置ForeignKey(name="null")方式,使Hibernate不生成外鍵關聯,但是需要在每個關聯關系上設置,比較繁瑣,很難統一控制保證數據庫中不存在外鍵關聯。而且經測試在@JoinColumn設置foreignkey=@ForeignKey(name="null")不會生成外鍵,在@JoinTable中此種設置方式還是可以生成外鍵。 

             下面提供一種禁用Hibernate外鍵的方式,在創建數據庫表時不生成外鍵關聯,但是個人感覺還不是最好的解決方案,希望多多指教。

             思路:因為Hibernate為了處理不同數據庫SQL的差異,為每個數據庫定義了dialect,在執行SQL時會由dialect類的方法中獲取相應的SQL,所以可以通過重寫dialect類中生成外鍵SQL的方法不生成數據庫外鍵關聯。分別重寫的Postgresql數據庫和Oracle數據庫的Dialect類如下:

      Java代碼  收藏代碼
      import org.hibernate.dialect.PostgreSQL9Dialect;  
      /** 
       * 不生成外鍵,通過類似于SQL注入的方法,為每個數據庫修改創建外鍵的SQL 
       */  
      public class PostgreSQL9DialectWithoutFK extends PostgreSQL9Dialect {  
          @Override  
          public String getAddForeignKeyConstraintString(  
                  String constraintName,  
                  String[] foreignKey,  
                  String referencedTable,  
                  String[] primaryKey,  
                  boolean referencesPrimaryKey) {  
      //      設置foreignkey對應的列值可以為空  
              return " alter "+ foreignKey[0] +" set default null " ;  
          }  
      }  

       

      Java代碼  
      import org.hibernate.dialect.Oracle10gDialect;  
      /** 
       * 不生成外鍵,通過類似于SQL注入的方法,為每個數據庫修改創建外鍵的SQL 
       */  
      public class Oracle10gDialectWithoutFK extends Oracle10gDialect {  
          @Override  
          public String getAddForeignKeyConstraintString(  
                  String constraintName,  
                  String[] foreignKey,  
                  String referencedTable,  
                  String[] primaryKey,  
                  boolean referencesPrimaryKey) {  
      //      通過修改外鍵列的默認值,而不是添加外鍵,避免生成外鍵  
              return " modify "+ foreignKey[0] +" default null " ;  
          }  
      }  

       

             在重寫生成外鍵SQL時考慮過使用SQL注入的方式在創建完外鍵后,再刪除外鍵,但是這種方式比較復雜,做了一點后就放棄了。

       

             創建了重寫的Dialect類,通過hibernate.dialect=Oracle10gDialectWithoutFK配置后,在生成數據庫表時外鍵策略就會生效。

            另:

      • 關于是否在數據庫中生成外鍵的討論如下圖,具體的討論內容可以按關鍵字搜索相關內容。

        • JPA中@JoinColumn不生成外鍵的配置
        • postgresql中alter語法如下
      主站蜘蛛池模板: 久久精品手机观看| 人妻少妇久久中文字幕| 国产精品人成视频免| 欧美人伦禁忌dvd放荡欲情| 熟妇的味道hd中文字幕| 无码人妻精品一区二区三| 日韩午夜福利视频在线观看| 免费无码高潮流白浆视频| 亚洲精品一区二区三区大| 亚洲中文字幕无码中字| 桃花岛亚洲成在人线AV| 欧洲码亚洲码的区别入口| 日韩在线视频观看免费网站| 乱人伦人妻精品一区二区| 久久午夜无码鲁丝片午夜精品| 国产二区三区不卡免费| 蜜桃麻豆www久久囤产精品| 国产精品一二区在线观看| 四虎永久精品在线视频| av在线播放观看国产| 日日摸夜夜添夜夜添国产三级| 亚洲精品理论电影在线观看| 欧美成人精品| 爽爽精品dvd蜜桃成熟时电影院| 麻豆精产国品一二三区区| 樱花草视频www日本韩国| 精品无码国产污污污免费| 最新中文字幕av无码专区不| 国产亚洲av嫩草久久| 精品国产成人国产在线视| 中文字幕乱码无码人妻系列蜜桃| 一区二区三区四区自拍偷拍| bt天堂新版中文在线| 国产999久久高清免费观看| 久久精品国产一区二区三| 亚洲日产韩国一二三四区| 99精品国产在热久久婷婷| 欧美视频网站www色| 精品久久一线二线三线区| 宾馆人妻4P互换视频| 亚洲性色AV一区二区三区|