การตั้งค่าเริ่มต้นสำหรับคอลัมน์ใน JPA


245

เป็นไปได้หรือไม่ที่จะตั้งค่าเริ่มต้นสำหรับคอลัมน์ใน JPA และถ้าเป็นเช่นนั้นทำได้อย่างไรโดยใช้คำอธิบายประกอบ


มีในการแยก JPA ที่ฉันสามารถใส่ค่าเริ่มต้นสำหรับคอลัมน์เป็นค่าสำหรับคอลัมน์อื่นเพราะฉันต้องการที่จะซ่อนไว้
shareef

3
ที่เกี่ยวข้อง: Hibernate มี@ org.hibernate.annotations.ColumnDefault ("foo")
Ondra Žižka

คำตอบ:


230

จริงๆแล้วมันเป็นไปได้ใน JPA แม้ว่าจะมีการแฮ็คเล็กน้อยโดยใช้columnDefinitionคุณสมบัติของ@Columnคำอธิบายประกอบตัวอย่างเช่น:

@Column(name="Price", columnDefinition="Decimal(10,2) default '100.00'")

3
10 คือส่วนเลขจำนวนเต็มและ 2 คือส่วนทศนิยมของตัวเลขดังนั้น: 1234567890.12 จะเป็นหมายเลขที่รองรับ
นาธาน Feger

23
โปรดทราบว่าคอลัมน์นี้การกำหนดไม่จำเป็นต้องเป็นอิสระจากฐานข้อมูลและแน่นอนไม่ได้ผูกประเภทข้อมูลใน Java โดยอัตโนมัติ
นาธาน Feger

47
หลังจากสร้างเอนทิตีที่มีฟิลด์ว่างและคงอยู่คุณจะไม่ได้รับการตั้งค่า ไม่ใช่วิธีการแก้ปัญหา ...
Pascal Thivent

18
ไม่ @NathanFeger, 10 คือความยาวและ 2 ส่วนทศนิยม ดังนั้น 1234567890.12 จะไม่เป็นหมายเลขที่รองรับ แต่ 12345678.90 นั้นถูกต้อง
GPrimola

4
คุณจะต้องinsertable=falseถ้าคอลัมน์เป็นโมฆะ (และเพื่อหลีกเลี่ยงการโต้แย้งคอลัมน์ที่ไม่จำเป็น)
eckes

314

คุณสามารถทำสิ่งต่อไปนี้:

@Column(name="price")
private double price = 0.0;

มี! คุณเพิ่งใช้ศูนย์เป็นค่าเริ่มต้น

หมายเหตุสิ่งนี้จะให้บริการคุณหากคุณเข้าถึงฐานข้อมูลจากแอปพลิเคชันนี้เท่านั้น หากแอปพลิเคชันอื่นใช้ฐานข้อมูลด้วยคุณควรทำการตรวจสอบนี้จากฐานข้อมูลโดยใช้แอตทริบิวต์การเพิ่มความคิดเห็น columnDefinition ของ Cameron หรือวิธีอื่น


38
นี่เป็นวิธีที่ถูกต้องหากคุณต้องการให้เอนทิตีของคุณมีค่าที่ถูกต้องหลังจากใส่ +1
Pascal Thivent

16
การตั้งค่าเริ่มต้นของแอททริบิวต์ที่สามารถลบล้างได้ (แอปที่มีชนิดที่ไม่ใช่แบบดั้งเดิม) ในคลาสโมเดลจะแบ่งเคียวรีเกณฑ์ที่ใช้Exampleวัตถุเป็นต้นแบบสำหรับการค้นหา หลังจากตั้งค่าเริ่มต้นแล้วแบบสอบถามตัวอย่างไฮเบอร์เนตจะไม่เพิกเฉยคอลัมน์ที่เกี่ยวข้องอีกต่อไปซึ่งก่อนหน้านี้จะเพิกเฉยต่อเนื่องจากคอลัมน์นั้นว่างเปล่า วิธีที่ดีคือการตั้งค่าเริ่มต้นทั้งหมดเป็นเพียงแค่ก่อนที่จะตื่นตาตื่นใจ Hibernate หรือsave() update()สิ่งนี้จะเลียนแบบพฤติกรรมของฐานข้อมูลที่ดีกว่าซึ่งจะเป็นการตั้งค่าเริ่มต้นเมื่อบันทึกแถว
Derek Mahar

1
@Harry: นี่เป็นวิธีที่ถูกต้องในการตั้งค่าเริ่มต้นยกเว้นเมื่อคุณใช้การสืบค้นเกณฑ์ที่ใช้ตัวอย่างเป็นแบบตัวอย่างสำหรับการค้นหา
Derek Mahar

12
สิ่งนี้ไม่แน่ใจว่ามีการตั้งค่าเริ่มต้นสำหรับประเภทที่ไม่ใช่ดั้งเดิม ( nullตัวอย่างเช่นการตั้งค่า) การใช้@PrePersistและ@PreUpdateเป็นตัวเลือกที่ดีกว่า
Jasper

3
นี่เป็นวิธีที่ถูกต้องในการระบุค่าเริ่มต้นสำหรับคอลัมน์ columnDefinitionproperty ไม่เป็นอิสระจากฐานข้อมูลและ@PrePersistแทนที่การตั้งค่าของคุณก่อนที่จะแทรก "default value" เป็นอย่างอื่นค่าเริ่มต้นจะถูกใช้เมื่อค่าไม่ได้ตั้งค่าไว้อย่างชัดเจน
Utku Özdemir

110

วิธีอื่นคือการใช้ javax.persistence.PrePersist

@PrePersist
void preInsert() {
   if (this.createdTime == null)
       this.createdTime = new Date();
}

1
ฉันใช้วิธีการเช่นนี้เพื่อเพิ่มและอัปเดตการประทับเวลา มันทำงานได้ดีมาก
Spina

10
นี่ไม่ควรเป็นif (createdt != null) createdt = new Date();หรืออะไรนะ? ตอนนี้สิ่งนี้จะแทนที่ค่าที่ระบุไว้อย่างชัดเจนซึ่งดูเหมือนจะทำให้มันไม่ใช่ค่าเริ่มต้นจริง ๆ
Max Nanasy

16
@MaxNanasyif (createdt == null) createdt = new Date();
Shane

มันจะสำคัญไหมถ้าไคลเอนต์และฐานข้อมูลอยู่ในเขตเวลาที่แตกต่างกัน? ฉันคิดว่าการใช้บางอย่างเช่น "TIMESTAMP DEFAULT CURRENT_TIMESTAMP" จะได้รับเวลาปัจจุบันบนเซิร์ฟเวอร์ฐานข้อมูลและ "createdt = new Date ()" จะได้รับเวลาปัจจุบันในรหัส java แต่สองครั้งนี้อาจไม่เหมือนกันถ้า ไคลเอ็นต์กำลังเชื่อมต่อกับเซิร์ฟเวอร์ในเขตเวลาอื่น
FrustratedWithFormsDesigner

เพิ่มการnullตรวจสอบ
Ondra Žižka

49

ในปี 2560 JPA 2.1 ยังคงมีเพียง@Column(columnDefinition='...')คุณใส่นิยาม SQL ตามตัวอักษรของคอลัมน์ ซึ่งค่อนข้างไม่ยืดหยุ่นและบังคับให้คุณประกาศแง่มุมอื่น ๆ เช่นประเภททำให้เกิดมุมมองการใช้งาน JPA สั้นในเรื่องนั้น

แม้ว่าไฮเบอร์เนตมี:

@Column(length = 4096, nullable = false)
@org.hibernate.annotations.ColumnDefault("")
private String description;

ระบุค่าเริ่มต้นเพื่อนำไปใช้กับคอลัมน์ที่เกี่ยวข้องผ่าน DDL

หมายเหตุสองข้อต่อไปนี้:

1) อย่ากลัวที่จะไม่ได้มาตรฐาน ทำงานเป็นนักพัฒนา JBoss ฉันเห็นกระบวนการสเปคค่อนข้างมาก สเปคนั้นเป็นพื้นฐานที่ผู้เล่นรายใหญ่ในสาขานั้นยินดีที่จะให้การสนับสนุนในทศวรรษหน้าหรือมากกว่านั้น มันเป็นเรื่องจริงเพื่อความปลอดภัยสำหรับการส่งข้อความ ORM ไม่แตกต่างกัน (แม้ว่า JPA จะครอบคลุมค่อนข้างมาก) ประสบการณ์ของฉันในฐานะนักพัฒนาคือในแอปพลิเคชันที่ซับซ้อนไม่ช้าก็เร็วคุณจะต้องใช้ API ที่ไม่ได้มาตรฐาน และ@ColumnDefaultเป็นตัวอย่างเมื่อเปรียบเทียบกับข้อเสียของการใช้โซลูชันที่ไม่ได้มาตรฐาน

2) มันเป็นเรื่องดีที่ทุกคนส่งเสียง @PrePersist หรือการกำหนดค่าเริ่มต้นของสมาชิกคอนสตรัค แต่นั่นไม่เหมือนกัน ปรับปรุง SQL จำนวนมากได้อย่างไร วิธีการเกี่ยวกับงบที่ไม่ได้ตั้งค่าคอลัมน์? DEFAULTมีบทบาทและไม่สามารถทดแทนได้ด้วยการเริ่มต้นสมาชิกคลาส Java


ฉันสามารถใช้คำอธิบายประกอบจำศีลในเวอร์ชันใดสำหรับ Wildfly 12 ฉันพบข้อผิดพลาดกับเวอร์ชันนี้โดยเฉพาะ? ขอบคุณล่วงหน้า!
เฟอร์นันโดพาย

ขอบคุณ Ondra มีวิธีแก้ปัญหาอื่นอีกหรือไม่ในปี 2562?
อลัน

1
@Alan ไม่ได้อยู่ในสต็อก JPA น่าเศร้า
jwenting

13

JPA ไม่สนับสนุนสิ่งนั้นและมันจะมีประโยชน์ถ้ามันทำ การใช้ columnDefinition เป็นเฉพาะ DB และไม่สามารถยอมรับได้ในหลายกรณี การตั้งค่าเริ่มต้นในชั้นเรียนไม่เพียงพอเมื่อคุณเรียกข้อมูลระเบียนที่มีค่า Null (ซึ่งโดยทั่วไปจะเกิดขึ้นเมื่อคุณเรียกใช้การทดสอบ DBUnit เก่าอีกครั้ง) สิ่งที่ฉันทำคือ:

public class MyObject
{
    int attrib = 0;

    /** Default is 0 */
    @Column ( nullable = true )
    public int getAttrib()

    /** Falls to default = 0 when null */
    public void setAttrib ( Integer attrib ) {
       this.attrib = attrib == null ? 0 : attrib;
    }
}

ชวาอัตโนมัติชกมวยช่วยมากในที่


อย่าทำร้ายผู้ตั้งถิ่นฐาน! พวกเขาสำหรับการตั้งค่าพารามิเตอร์ในเขตข้อมูลวัตถุ ไม่มีอะไรเพิ่มเติม! ใช้ตัวสร้างเริ่มต้นที่ดีกว่าสำหรับค่าเริ่มต้น
Roland

@Roland ดีในทางทฤษฎี แต่จะไม่ทำงานเสมอเมื่อจัดการกับฐานข้อมูลที่มีอยู่แล้วที่มีค่า null ที่ใบสมัครของคุณไม่ต้องการให้พวกเขา คุณต้องทำการแปลงฐานข้อมูลก่อนที่คุณจะทำให้คอลัมน์ไม่เป็นโมฆะและตั้งค่าเริ่มต้นที่เหมาะสมในเวลาเดียวกันจากนั้นจัดการกับแบ็กสแลชจากแอปพลิเคชันอื่น ๆ ที่คิดว่ามันเป็นโมฆะจริง ยังสามารถปรับเปลี่ยนฐานข้อมูล)
jwenting

หากพูดถึง #JPA และ setters / getters พวกเขาจะต้องเป็น setter / getter บริสุทธิ์ทุกครั้งที่ใบสมัครของคุณเติบโตและโตขึ้นและกลายเป็นฝันร้ายในการบำรุงรักษา คำแนะนำที่ดีที่สุดคือ KISS ที่นี่ (ฉันไม่ใช่เกย์ LOL)
Roland

10

เมื่อฉันเห็นสิ่งนี้จาก Google ในขณะที่พยายามแก้ไขปัญหาเดียวกันฉันจะทิ้งวิธีแก้ปัญหาที่ฉันทำไว้ในกรณีที่มีคนพบว่ามีประโยชน์

จากมุมมองของฉันมีเพียง 1 ทางออกสำหรับปัญหานี้ - @PrePersist หากคุณทำใน @PrePersist คุณต้องตรวจสอบว่ามีการตั้งค่าไว้แล้ว


4
+1 - ฉันต้องการใช้@PrePersistUsecase ของ OP แน่นอน @Column(columnDefinition=...)ดูเหมือนจะไม่หรูหรามาก
Piotr Nowicki

@PrePersist จะไม่ช่วยคุณหากมีข้อมูลในร้านค้าที่มีค่า Null อยู่แล้ว มันจะไม่ทำการแปลงฐานข้อมูลอย่างน่าอัศจรรย์สำหรับคุณ
jwenting

10
@Column(columnDefinition="tinyint(1) default 1")

ฉันเพิ่งทดสอบปัญหา มันใช้งานได้ดี ขอบคุณสำหรับคำใบ้


เกี่ยวกับความคิดเห็น:

@Column(name="price") 
private double price = 0.0;

อันนี้ไม่ได้ตั้งค่าคอลัมน์เริ่มต้นในฐานข้อมูล (แน่นอน)


9
มันไม่ทำงานได้ดีในระดับวัตถุ (คุณจะไม่ได้รับค่าเริ่มต้นของฐานข้อมูลหลังจากการแทรกในเอนทิตีของคุณ) เริ่มต้นที่ระดับ Java
Pascal Thivent

มันทำงานได้ (โดยเฉพาะอย่างยิ่งถ้าคุณระบุ insertable = false ในฐานข้อมูล แต่น่าเสียดายที่เวอร์ชันแคชนั้นไม่รีเฟรช (ไม่ใช่แม้เมื่อ JPA เลือกตารางและคอลัมน์) อย่างน้อยก็ไม่จำศีลด้วย: - / แต่แม้ว่ามันจะทำงานเพิ่มเติม ไปกลับไม่ดี
eckes

9

คุณสามารถใช้ java reflect api:

    @PrePersist
    void preInsert() {
       PrePersistUtil.pre(this);
    }

นี่เป็นเรื่องปกติ:

    public class PrePersistUtil {

        private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");


        public static void pre(Object object){
            try {
                Field[] fields = object.getClass().getDeclaredFields();
                for(Field field : fields){
                    field.setAccessible(true);
                    if (field.getType().getName().equals("java.lang.Long")
                            && field.get(object) == null){
                        field.set(object,0L);
                    }else if    (field.getType().getName().equals("java.lang.String")
                            && field.get(object) == null){
                        field.set(object,"");
                    }else if (field.getType().getName().equals("java.util.Date")
                            && field.get(object) == null){
                        field.set(object,sdf.parse("1900-01-01"));
                    }else if (field.getType().getName().equals("java.lang.Double")
                            && field.get(object) == null){
                        field.set(object,0.0d);
                    }else if (field.getType().getName().equals("java.lang.Integer")
                            && field.get(object) == null){
                        field.set(object,0);
                    }else if (field.getType().getName().equals("java.lang.Float")
                            && field.get(object) == null){
                        field.set(object,0.0f);
                    }
                }
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }

2
ฉันชอบวิธีนี้ แต่มีจุดหนึ่งที่อ่อนแอฉันคิดว่ามันจะเป็นสิ่งสำคัญที่จะตรวจสอบว่าคอลัมน์เป็นโมฆะหรือไม่ก่อนที่จะตั้งค่าเริ่มต้น
Luis Carlos

หากคุณต้องการใส่รหัสจากField[] fields = object.getClass().getDeclaredFields();ลงในfor()อาจจะไม่เป็นเช่นกัน และเพิ่มfinalไปยังพารามิเตอร์ / ข้อยกเว้นที่ตรวจพบเนื่องจากคุณไม่ต้องการobjectแก้ไขโดยไม่ได้ตั้งใจ นอกจากนี้ยังเพิ่มการตรวจสอบใน:null if (null == object) { throw new NullPointerException("Parameter 'object' is null"); }ที่ทำให้แน่ใจว่ามีความปลอดภัยในการเรียกและไม่ได้เรียกobject.getClass() NPEเหตุผลคือเพื่อหลีกเลี่ยงข้อผิดพลาดโดยโปรแกรมเมอร์ขี้เกียจ ;-)
Roland

7

ฉันใช้columnDefinitionและมันใช้งานได้ดีมาก

@Column(columnDefinition="TIMESTAMP DEFAULT CURRENT_TIMESTAMP")

private Date createdDate;

6
ดูเหมือนว่าจะทำให้ผู้จำหน่ายระบบติดตั้งและวางระบบ jpa ของคุณเจาะจง
Udo Held

มันทำให้ผู้ขาย DDL เฉพาะเจาะจงเท่านั้น แต่คุณมีแฮ็ก DDL เฉพาะผู้ขายที่น่าจะเป็นไปได้มาก .. อย่างไรก็ตามดังที่ได้กล่าวไว้ข้างต้นค่า (แม้ว่า insertable = false) จะปรากฏในฐานข้อมูล แต่ไม่อยู่ในแคชเอนทิตีของเซสชัน
eckes

7

คุณทำสิ่งนี้ไม่ได้ด้วยคำอธิบายประกอบคอลัมน์ ฉันคิดว่าวิธีเดียวคือการตั้งค่าเริ่มต้นเมื่อวัตถุถูกสร้างขึ้น บางทีคอนสตรัคเตอร์เริ่มต้นอาจเป็นที่ที่เหมาะสมในการทำเช่นนั้น


ความคิดดี. น่าเศร้าที่ไม่มีคำอธิบายประกอบทั่วไปหรือคุณลักษณะสำหรับ@Columnประมาณ และฉันก็พลาดความเห็นที่ตั้งไว้ (นำมาจากหลักคำสอนของ Java)
Roland

5

ในกรณีของฉันฉันปรับเปลี่ยนซอร์สโค้ด hibernate-core เพื่อแนะนำหมายเหตุใหม่@DefaultValue:

commit 34199cba96b6b1dc42d0d19c066bd4d119b553d5
Author: Lenik <xjl at 99jsj.com>
Date:   Wed Dec 21 13:28:33 2011 +0800

    Add default-value ddl support with annotation @DefaultValue.

diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/DefaultValue.java b/hibernate-core/src/main/java/org/hibernate/annotations/DefaultValue.java
new file mode 100644
index 0000000..b3e605e
--- /dev/null
+++ b/hibernate-core/src/main/java/org/hibernate/annotations/DefaultValue.java
@@ -0,0 +1,35 @@
+package org.hibernate.annotations;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Specify a default value for the column.
+ *
+ * This is used to generate the auto DDL.
+ *
+ * WARNING: This is not part of JPA 2.0 specification.
+ *
+ * @author 谢继雷
+ */
+@java.lang.annotation.Target({ FIELD, METHOD })
+@Retention(RUNTIME)
+public @interface DefaultValue {
+
+    /**
+     * The default value sql fragment.
+     *
+     * For string values, you need to quote the value like 'foo'.
+     *
+     * Because different database implementation may use different 
+     * quoting format, so this is not portable. But for simple values
+     * like number and strings, this is generally enough for use.
+     */
+    String value();
+
+}
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java
index b289b1e..ac57f1a 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java
@@ -29,6 +29,7 @@ import org.hibernate.AnnotationException;
 import org.hibernate.AssertionFailure;
 import org.hibernate.annotations.ColumnTransformer;
 import org.hibernate.annotations.ColumnTransformers;
+import org.hibernate.annotations.DefaultValue;
 import org.hibernate.annotations.common.reflection.XProperty;
 import org.hibernate.cfg.annotations.Nullability;
 import org.hibernate.mapping.Column;
@@ -65,6 +66,7 @@ public class Ejb3Column {
    private String propertyName;
    private boolean unique;
    private boolean nullable = true;
+   private String defaultValue;
    private String formulaString;
    private Formula formula;
    private Table table;
@@ -175,7 +177,15 @@ public class Ejb3Column {
        return mappingColumn.isNullable();
    }

-   public Ejb3Column() {
+   public String getDefaultValue() {
+        return defaultValue;
+    }
+
+    public void setDefaultValue(String defaultValue) {
+        this.defaultValue = defaultValue;
+    }
+
+    public Ejb3Column() {
    }

    public void bind() {
@@ -186,7 +196,7 @@ public class Ejb3Column {
        }
        else {
            initMappingColumn(
-                   logicalColumnName, propertyName, length, precision, scale, nullable, sqlType, unique, true
+                   logicalColumnName, propertyName, length, precision, scale, nullable, sqlType, unique, defaultValue, true
            );
            log.debug( "Binding column: " + toString());
        }
@@ -201,6 +211,7 @@ public class Ejb3Column {
            boolean nullable,
            String sqlType,
            boolean unique,
+           String defaultValue,
            boolean applyNamingStrategy) {
        if ( StringHelper.isNotEmpty( formulaString ) ) {
            this.formula = new Formula();
@@ -217,6 +228,7 @@ public class Ejb3Column {
            this.mappingColumn.setNullable( nullable );
            this.mappingColumn.setSqlType( sqlType );
            this.mappingColumn.setUnique( unique );
+           this.mappingColumn.setDefaultValue(defaultValue);

            if(writeExpression != null && !writeExpression.matches("[^?]*\\?[^?]*")) {
                throw new AnnotationException(
@@ -454,6 +466,11 @@ public class Ejb3Column {
                    else {
                        column.setLogicalColumnName( columnName );
                    }
+                   DefaultValue _defaultValue = inferredData.getProperty().getAnnotation(DefaultValue.class);
+                   if (_defaultValue != null) {
+                       String defaultValue = _defaultValue.value();
+                       column.setDefaultValue(defaultValue);
+                   }

                    column.setPropertyName(
                            BinderHelper.getRelativePath( propertyHolder, inferredData.getPropertyName() )
diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
index e57636a..3d871f7 100644
--- a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
+++ b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java
@@ -423,6 +424,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
                getMappingColumn() != null ? getMappingColumn().isNullable() : false,
                referencedColumn.getSqlType(),
                getMappingColumn() != null ? getMappingColumn().isUnique() : false,
+               null, // default-value
                false
        );
        linkWithValue( value );
@@ -502,6 +504,7 @@ public class Ejb3JoinColumn extends Ejb3Column {
                getMappingColumn().isNullable(),
                column.getSqlType(),
                getMappingColumn().isUnique(),
+               null, // default-value
                false //We do copy no strategy here
        );
        linkWithValue( value );

นี่เป็นวิธีแก้ปัญหาจำศีลเท่านั้น


2
ในขณะที่ฉันรู้สึกซาบซึ้งในความพยายามของผู้คนที่มีส่วนร่วมในโครงการโอเพนซอร์ซฉันก็ลงคะแนนคำตอบนี้เพราะ JPA เป็นข้อกำหนดมาตรฐานของ Java ที่อยู่ด้านบนของ OR / M ใด ๆ OP ขอวิธี JPA เพื่อระบุค่าเริ่มต้น สำหรับไฮเบอร์เนตเท่านั้น ถ้านี้คือ NHibernate ซึ่งไม่มีซุปเปอร์ชิ้นส่วนข้อกำหนดสำหรับการติดตา (NPA ไม่สนับสนุนแม้โดย MS EF) ผมจะได้ upvoted เช่นชนิดของแพทช์ ความจริงก็คือ JPA นั้นค่อนข้าง จำกัด เมื่อเทียบกับข้อกำหนดของ ORM (ตัวอย่างหนึ่ง: ไม่มีดัชนีรอง) รุ่งโรจน์อย่างไรก็ตามความพยายาม
usr-local-ΕΨΗΕΛΩΝ

สิ่งนี้ไม่ได้สร้างปัญหาการบำรุงรักษาหรือไม่? จะต้องทำการเปลี่ยนแปลงเหล่านี้ซ้ำเมื่อใดก็ตามที่มีการอัพเกรดจำศีลหรือทุกครั้งที่ติดตั้งใหม่
user1242321

เนื่องจากคำถามเกี่ยวกับ JPA และไม่ได้กล่าวถึง Hibernate สิ่งนี้จึงไม่ตอบคำถาม
Neil Stockton

5
  1. @Column(columnDefinition='...') ไม่ทำงานเมื่อคุณตั้งค่าข้อ จำกัด เริ่มต้นในฐานข้อมูลในขณะที่แทรกข้อมูล
  2. คุณต้องสร้างinsertable = falseและลบออกcolumnDefinition='...'จากคำอธิบายประกอบจากนั้นฐานข้อมูลจะแทรกค่าเริ่มต้นจากฐานข้อมูลโดยอัตโนมัติ
  3. เช่นเมื่อคุณตั้งค่า varchar เพศชายโดยค่าเริ่มต้นในฐานข้อมูล
  4. คุณเพียงแค่ต้องเพิ่มinsertable = falseใน Hibernate / JPA มันจะทำงาน

คำตอบที่ดี. และนี่คือคำอธิบายเกี่ยวกับการ
แทรกได้

และไม่ใช่ตัวเลือกที่ดีถ้าคุณต้องการตั้งค่าเป็นบางครั้ง
Shihe Zhang

@ShiheZhang ใช้ false ไม่ให้ฉันตั้งค่าเหรอ?
fvildoso

3
@PrePersist
void preInsert() {
    if (this.dateOfConsent == null)
        this.dateOfConsent = LocalDateTime.now();
    if(this.consentExpiry==null)
        this.consentExpiry = this.dateOfConsent.plusMonths(3);
}

ในกรณีของฉันเนื่องจากฟิลด์เป็น LocalDateTime ฉันใช้สิ่งนี้ขอแนะนำเนื่องจากความเป็นอิสระของผู้ขาย


2

หมายเหตุประกอบ JPA หรือ Hibernate ไม่สนับสนุนแนวคิดของค่าคอลัมน์เริ่มต้น เพื่อเป็นการหลีกเลี่ยงข้อ จำกัด นี้ให้ตั้งค่าเริ่มต้นทั้งหมดก่อนที่คุณจะเรียกใช้ Hibernate save()หรือupdate()ในเซสชัน สิ่งนี้ใกล้เคียงที่สุด (สั้น ๆ ของไฮเบอร์เนตตั้งค่าเริ่มต้น) เลียนแบบพฤติกรรมของฐานข้อมูลที่ตั้งค่าเริ่มต้นเมื่อมันบันทึกแถวในตาราง

แตกต่างจากการตั้งค่าเริ่มต้นในคลาสรุ่นตามที่คำตอบอื่นแนะนำวิธีนี้ยังช่วยให้มั่นใจได้ว่าแบบสอบถามแบบใช้เกณฑ์ที่ใช้Exampleวัตถุเป็นแบบตัวอย่างสำหรับการค้นหาจะทำงานต่อไปเหมือนเดิม เมื่อคุณตั้งค่าเริ่มต้นของแอตทริบิวต์เป็นโมฆะ (หนึ่งที่มีชนิดที่ไม่ใช่แบบดั้งเดิม) ในรูปแบบคลาสแบบสอบถามไฮเบอร์เนตแบบสอบถามโดยตัวอย่างจะไม่สนใจคอลัมน์ที่เกี่ยวข้องที่ก่อนหน้านี้มันจะไม่สนใจเพราะมันเป็นโมฆะ


ในวิธีการแก้ปัญหาก่อนหน้าผู้เขียน menthioned ColumnDefault ("")
nikolai.serdiuk

@ nikolai.serdiuk ว่าคำอธิบายประกอบ ColumnDefault ถูกเพิ่มเข้ามาหลายปีหลังจากคำตอบนี้ถูกเขียนขึ้น ในปี 2010 มันถูกต้องไม่มีการเพิ่มความคิดเห็น (อันที่จริงแล้วไม่มีการเพิ่มความคิดเห็นเพียงการกำหนดค่า xml)
jwenting

1

ไม่สามารถทำได้ใน JPA

นี่คือสิ่งที่คุณสามารถทำได้กับหมายเหตุประกอบคอลัมน์: http://java.sun.com/javaee/5/docs/api/javax/persistence/Column.html


1
การไม่สามารถระบุค่าเริ่มต้นนั้นเป็นข้อบกพร่องร้ายแรงของคำอธิบายประกอบ JPA
Derek Mahar

2
JDO อนุญาตให้ใช้ในการกำหนด ORM ดังนั้น JPA ควรรวมสิ่งนี้ ... หนึ่งวัน
383680

คุณสามารถทำได้อย่างแน่นอนด้วยแอตทริบิวต์ ColumnDefinition ตามที่ Cameron Pope ตอบ
IntelliData

@DerekMahar ไม่ใช่เพียงข้อมูลจำเพาะใน JPA มันเป็นสเปคที่ดี แต่มันก็ไม่สมบูรณ์แบบ
jwenting

1

หากคุณใช้คู่คุณสามารถใช้สิ่งต่อไปนี้:

@Column(columnDefinition="double precision default '96'")

private Double grolsh;

ใช่มันเป็น db เฉพาะ


0

คุณสามารถกำหนดค่าเริ่มต้นในตัวออกแบบฐานข้อมูลหรือเมื่อคุณสร้างตาราง เช่นใน SQL Server คุณสามารถตั้งค่า vault เริ่มต้นของเขตข้อมูล Date เป็น ( getDate()) ใช้insertable=falseตามที่ระบุไว้ในคำจำกัดความคอลัมน์ของคุณ JPA จะไม่ระบุคอลัมน์นั้นในส่วนแทรกและฐานข้อมูลจะสร้างมูลค่าให้คุณ


-2

คุณจำเป็นต้องinsertable=falseในตัวคุณ@Columnคำอธิบายประกอบ JPA จะไม่สนใจคอลัมน์นั้นในขณะที่แทรกในฐานข้อมูลและจะใช้ค่าเริ่มต้น

ดูลิงค์นี้: http://mariemjabloun.blogspot.com/2014/03/resolved-set-database-default-value-in.html


2
แล้วคุณจะใส่ค่า @runtime ที่กำหนดอย่างไร?
Ashish Ratan

ใช่นั่นเป็นเรื่องจริง nullable=falseจะล้มเหลวด้วยSqlException: Caused by: java.sql.SQLException: Column 'opening_times_created' cannot be null. นี่ฉันลืมที่จะตั้ง "สร้าง" openingTime.setOpeningCreated(new Date())ประทับเวลาด้วย นี่เป็นวิธีที่ดีในการมีความมั่นคง แต่นั่นคือสิ่งที่ผู้ถามไม่ได้ถาม
Roland
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.