2010-07-14 26 views
9

Tôi có các loại lớp sau đây để phân cấp thực thể ngủ đông. Tôi đang cố gắng có hai lớp phụ cụ thể Sub1ClassSub2Class. Chúng được phân tách bằng một cột phân biệt đối xử (field) được xác định trong MappedSuperClass. Có một lớp thực thể trừu tượng EntitySuperClass được tham chiếu bởi các thực thể khác. Các thực thể khác không nên quan tâm nếu chúng thực sự tham chiếu Sub1Class hoặc Sub2Class.Hibernate, thừa kế bảng đơn và trường sử dụng từ siêu lớp làm cột phân biệt đối tượng

Điều này thực sự có thể? Hiện nay tôi nhận được lỗi này (vì định nghĩa cột được thừa hưởng hai lần trong Sub1Class và trong EntitySuperClass):

Repeated column in mapping for entity: my.package.Sub1Class column: field (should be mapped with insert="false" update="false") 

Nếu tôi thêm @MappedSuperClass để EntitySuperClass, sau đó tôi nhận được lỗi khẳng định từ hiberante: nó không giống như nếu một lớp là cả Thực thể và một lớp siêu ánh xạ. Nếu tôi xóa @Entity khỏi EntitySuperClass, lớp đó không còn là thực thể và không thể được tham chiếu từ các thực thể khác:

MappedSuperClass là một phần của gói bên ngoài, vì vậy nếu có thể, không nên thay đổi.

lớp của tôi:

@MappedSuperclass 
public class MappedSuperClass { 
    private static final String ID_SEQ = "dummy_id_seq"; 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = ID_SEQ) 
    @GenericGenerator(name=ID_SEQ, strategy="sequence") 

    @Column(name = "id", unique = true, nullable = false, insertable = true, updatable = false) 
    private Integer id; 

    @Column(name="field", nullable=false, length=8) 
    private String field; 

    public Integer getId() { 
     return id; 
    } 
    public void setId(Integer id) { 
     this.id = id; 
    } 
    public String getField() { 
     return field; 
    } 
    public void setField(String field) { 
     this.field = field; 
    } 
} 


@Entity 
@Table(name = "ACTOR") 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="field", discriminatorType=DiscriminatorType.STRING) 
abstract public class EntitySuperClass extends MappedSuperClass { 


    @Column(name="description", nullable=false, length=8) 
    private String description; 

    public String getDescription() { 
     return description; 
    } 

    public void setDescription(String description) { 
     this.description = description; 
    } 
} 

@Entity 
@DiscriminatorValue("sub1") 
public class Sub1Class extends EntitySuperClass { 

} 


@Entity 
@DiscriminatorValue("sub2") 
public class Sub2Class extends EntitySuperClass { 

} 


@Entity 
public class ReferencingEntity { 
    @Id 
    @GeneratedValue(strategy = GenerationType.SEQUENCE) 
    private Integer id; 

    @Column 
    private Integer value; 

    @ManyToOne 
    private EntitySuperClass entitySuperClass; 


    public Integer getId() { 
     return id; 
    } 

    public void setId(Integer id) { 
     this.id = id; 
    } 

    public Integer getValue() { 
     return value; 
    } 

    public void setValue(Integer value) { 
     this.value = value; 
    } 

    public EntitySuperClass getEntitySuperClass() { 
     return entitySuperClass; 
    } 

    public void setEntitySuperClass(EntitySuperClass entitySuperClass) { 
     this.entitySuperClass = entitySuperClass; 
    } 

} 
+0

Nhưng tại sao bạn muốn để lộ bộ phân biệt cột? Cột này thường là chi tiết triển khai "ẩn" mà bạn không muốn hiển thị. –

+0

Cột phân biệt đối xử đã được hiển thị trong MappedSuperClass là một phần của gói bên ngoài. Một gói tôi muốn tránh sửa đổi, nếu có thể. –

Trả lời

14

Trong dự án của tôi nó được thực hiện theo cách này:

@Entity 
@Inheritance(strategy = InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name = "field", discriminatorType = DiscriminatorType.STRING) 
@DiscriminatorValue("dummy") 
public class EntitySuperClass { 
    // here definitions go 
    // but don't define discriminator column here 
} 

@Entity 
@DiscriminatorValue(value="sub1") 
public class Sub1Class extends EntitySuperClass { 
    // here definitions go 
} 

Và nó hoạt động. Tôi nghĩ rằng vấn đề của bạn là bạn không cần thiết xác định trường phân biệt đối xử trong định nghĩa lớp cha của bạn. Loại bỏ nó và nó sẽ hoạt động.

12

Để sử dụng cột phân biệt đối xử làm thuộc tính bình thường, bạn nên đặt thuộc tính này là chỉ đọc với insertable = false, updatable = false. Vì bạn không thể thay đổi MappedSuperClass, bạn cần phải sử dụng @AttributeOverride:

@Entity 
@Table(name = "ACTOR") 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) 
@DiscriminatorColumn(name="field", discriminatorType=DiscriminatorType.STRING) 

@AttributeOverride(name = "field", 
    column = @Column(name="field", nullable=false, length=8, 
     insertable = false, updatable = false)) 

abstract public class EntitySuperClass extends MappedSuperClass { 
    ... 
} 
2

Bạn có thể ánh xạ một cột cơ sở dữ liệu một lần duy nhất là lĩnh vực đọc-ghi (một trường có insertable=true và/hoặc updatable=true) và bất kỳ thời điểm số như trường chỉ đọc (insertable=falseupdatable=false). Sử dụng một cột là @DiscriminatorColumn được tính là ánh xạ đọc-ghi, do đó bạn không thể có ánh xạ đọc-ghi bổ sung.

Hibernate sẽ đặt giá trị được chỉ định trong @DiscriminatorColumn đằng sau hậu trường dựa trên phiên bản lớp cụ thể. Nếu bạn có thể thay đổi trường đó, nó sẽ cho phép sửa đổi trường @DiscriminatorColumn để lớp con và giá trị của bạn trong trường có thể không khớp.

0

Một điều cơ bản: Bạn không cần truy xuất cột phân biệt đối xử của mình từ DB. Bạn đã có thông tin đó trong mã, trong đó bạn sử dụng các thẻ @DiscriminatorValue của mình. Nếu bạn cần đọc từ DB, xem xét cẩn thận cách bạn chỉ định các nhà phân biệt đối xử.

Nếu bạn cần nó trong đối tượng thực thể cuối cùng, một thực hành tốt có thể để thực hiện một Enum từ giá trị phân biệt và trở về cửa hàng nó trong một lĩnh vực @Transient:

@Entity 
@Table(name="tablename") 
@DiscriminatorValue(Discriminators.SubOne.getDisc()) 
public class SubClassOneEntity extends SuperClassEntity { 

    ... 

    @Transient 
    private Discriminators discriminator; 

    // Setter and Getter 
    ... 
} 

public enum Discriminators { 
    SubOne ("Sub1"), 
    SubOne ("Sub2"); 

    private String disc; 
    private Discriminators(String disc) { this.disc = disc; } 
    public String getDisc() { return this.disc; } 
} 
Các vấn đề liên quan