Hibernate复合外键共享列

时间:2014-02-02 14:37:05

标签: java hibernate jpa orm jpa-2.0

我正在研究一个我无法改变的遗留数据库。此数据库定期与辅助实例同步,辅助实例创建新条目。要使实体的主键对所有实例都是唯一的,所有实体都有复合主键,包括由其原始数据库生成的代理键和标识原始实例的服务器ID。

复合主键对于Hibernate / JPA来说不是问题,它看起来像这样:

@Embeddable
public class ID implements Serializable {
    private Long autoin;      // Surrogate key
    private Integer serverId; // instance identifier

    @Column(name = "autoin_fix")
    public Long getAutoin() {
        return this.autoin;
    }
    @Column(name = "servdat_fk")
    public Integer getServerId() {
        return this.serverId;
    }

    // ... setter, equals, hashCode ...
}

现在考虑以下实体:

@Entity
@Table(name = "LEADS")
public class Request {
    private Long id;

    private Article article;
    private Location location;

    @Id
    @Column(name = "autoin_fix")
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "auto-increment")
    @GenericGenerator(name = "auto-increment", strategy = "sequence",
            parameters = @org.hibernate.annotations.Parameter(name = "sequence", value = "AUTOINCREMENT"))
    public Long getId() {
        return this.id;
    }

    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "artikel_fk", referencedColumnName = "autoin_fix", 
                    insertable = false, updatable = false), // Here is the problem!
        @JoinColumn(name = "servdat_fk", referencedColumnName = "servdat_fk", 
                    insertable = false, updatable = false)
    })
    public Article getArticle() {
        return this.article;
    }

    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = "standort_fk", referencedColumnName = "autoin_fix"),
        @JoinColumn(name = "servdat_fk", referencedColumnName = "servdat_fk")
    })
    public Location getLocation() {
        return this.location;
    }

    // Setters omitted
}

Request实体引用了两个其他实体,它们都使用复合主键来标识自己。但是从业务逻辑的角度来看,这两个实体(文章和位置)的serverId必须始终相同,数据库中只有一列serverId:

TABLE leads
-------------
autoin_fix
artikel_fk
standort_fk
servdat_fk  // This only exists once, but is part of the association to both Article and Location!

要使应用程序启动,我必须向Article关联添加insertable = false,updatable = false,这是我想要的。如果我尝试持久化一个Request对象,则不会写入“artikel_fk”字段,在数据库中留下null,因为我告诉hibernate它是只读的。并且不允许在其中一个连接列上使用insertable = false,updatable = false。

// This is illegal and the application won't start
@JoinColumns({
        @JoinColumn(name = "artikel_fk", referencedColumnName = "autoin_fix"),
        @JoinColumn(name = "servdat_fk", referencedColumnName = "servdat_fk", insertable = false, updatable = false)
    })

有谁知道这个问题的解决方案?或者使用Hibernate / JPA无法映射?

编辑:文章和位置的(简化)定义(真的不那么有趣,重要的是它们使用复合主键):

@Entity
@Table(name = "ARTIKEL")
public class Article {
    private ID id;
    private String headline;
    private String description;

    @EmbeddedId
    public ID getId() {
        return this.id;
    }

    @Column(name = "artbesch")
    public String getDescription() {
        return this.description;
    }

    @Column(name = "artueschr")
    public String getHeadline() {
        return this.headline;
    }

    // Setters omitted
}

@Entity
@Table(name = "STANDORT")
public class Location {
    private ID id;
    private GeoCoordinates geoCoordinates;
    private Name name;

    @EmbeddedId
    public ID getId() {
        return this.id;
    }

    @Embedded
    public GeoCoordinates getGeoCoordinates() {
        return this.geoCoordinates;
    }

    @Embedded
    public Name getName() {
        return this.name;
    }

    // Setters omitted
}

1 个答案:

答案 0 :(得分:0)

我认为如果从属实体的派生标识符是嵌入式id类的形式,那么表示关系的该id类的每个属性应该由对应关系属性上的@MapsId注释引用。

例如:

@Entity
public class Request {
    // ...
    @Id
    int id;

    @MapsId
    @ManyToOne
    private Article article;
    // ...
}

我希望这样有效,因为我现在无法尝试。