jpa/hibernate中的对称复合键

发布于 2024-12-17 22:38:08 字数 2067 浏览 4 评论 0原文

我试图确保模型不会在数据库中保存两次并且其 id 是对称的。在对称复合 id 下,我的意思如下:

@Entity
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "item_id", unique = true, nullable = false)
    public Long id;

    // other properties ...
}

@Entity
public class Pair {
    @EmbeddedId
    public PairId id;   

    // other properties...

    @Embeddable
    public static class PairId implements Serializable {

        @ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
        @JoinColumn(name="source_item_id")
        public Item source;

        @ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
        @JoinColumn(name="target_item_id")
        public Item target;

        @Override
        public boolean equals(Object o) {
             if(this == o){
               return true;
             }
             if (o instanceof PairId == false){
               return false;
             }

             PairId other = (PairId) o;
             return (this.source.equals(other.source) && this.target.equals(other.target)) ||
                    (this.source.equals(other.target) && this.target.equals(other.source));
    }

        @Override
        public int hashCode() { //probably not the best approach
             return source.hashCode() + target.hashCode();
        }
    }
}

示例:

Item i1 = new Item();
Item i2 = new Item();
//persist items into the database ...
PairId pId1 = new PairId(i1, i2);
PairId pId2 = new PairId(i2, i1);
Pair p1 = new Pair(pId1);
//persist p1 into the database
Pair p2 = new Pair(pId2);
//calling persist should not add new entry to the database, since p2 is symmetrical to p1 and already exists in the database
Pair p3 = findById(pId2); 
//p3 should now contain p1 also

您知道我如何实现这种行为吗?提前致谢!

编辑: 添加了对这两个类的注释,以表明这些类可以具有(并且它们具有)除上面列出的 id 之外的其他属性。但为了简单起见,我只是将他们的 ID 保留为单独的常设财产。

I'm trying to make sure that a model is not persisted twice in the database and its id is symmetrical. Under symmetrical composite id I mean the following:

@Entity
public class Item {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "item_id", unique = true, nullable = false)
    public Long id;

    // other properties ...
}

@Entity
public class Pair {
    @EmbeddedId
    public PairId id;   

    // other properties...

    @Embeddable
    public static class PairId implements Serializable {

        @ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
        @JoinColumn(name="source_item_id")
        public Item source;

        @ManyToOne(cascade={CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH})
        @JoinColumn(name="target_item_id")
        public Item target;

        @Override
        public boolean equals(Object o) {
             if(this == o){
               return true;
             }
             if (o instanceof PairId == false){
               return false;
             }

             PairId other = (PairId) o;
             return (this.source.equals(other.source) && this.target.equals(other.target)) ||
                    (this.source.equals(other.target) && this.target.equals(other.source));
    }

        @Override
        public int hashCode() { //probably not the best approach
             return source.hashCode() + target.hashCode();
        }
    }
}

Example:

Item i1 = new Item();
Item i2 = new Item();
//persist items into the database ...
PairId pId1 = new PairId(i1, i2);
PairId pId2 = new PairId(i2, i1);
Pair p1 = new Pair(pId1);
//persist p1 into the database
Pair p2 = new Pair(pId2);
//calling persist should not add new entry to the database, since p2 is symmetrical to p1 and already exists in the database
Pair p3 = findById(pId2); 
//p3 should now contain p1 also

Do you have any idea how I could implement such a behaviour? Thanks in advance!

Edit:
Added comments on both classes in order to show that those classes could have(and they have) other properties except of the listed ids above. But for the sake of simplicity I just left their ids as alone standing property.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

难以启齿的温柔 2024-12-24 22:38:09

也许,只是也许您可以放弃 Pair 想法并在 Item 中使用自引用。这样您就可以拥有更少的表、更清晰的代码并且没有复合键。

代码:

@Entity
public class Item
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @OneToOne
    @JoinColumn(name = "source_id", referencedColumnName = "id")
    private Item source;

    @OneToOne(mappedBy = "source")
    private Item target;
}

Maybe, just maybe you could drop the Pair idea and use a self reference in Item. This way you have less tables, cleaner code and no composite keys.

Code:

@Entity
public class Item
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @OneToOne
    @JoinColumn(name = "source_id", referencedColumnName = "id")
    private Item source;

    @OneToOne(mappedBy = "source")
    private Item target;
}
醉城メ夜风 2024-12-24 22:38:08

首先,我不会使用复合 ID。使用自动生成的代理键,并将这两项存储为常规属性。

然后,当成对存储物品时,我会确保始终以相同的顺序存储它们。例如,源 ID 应始终小于目标 ID。这可以通过封装来确保:

public void setItems(Item i1, Item i2) {
    if (i1.getId().compareTo(i2.getId()) < 0) {
        this.source = i1;
        this.target = i2;
    }
    else {
        this.source = i2;
        this.target = i1;
    }
}

First of all, I would not use a composite ID. Use an autogenerated surrogate key, and store both items as regular properties.

Then, when storing the items in a pair, I would just make sure to always store them in the same order. For example, the source ID should always be smaler than the target ID. This can be ensured using encapsulation:

public void setItems(Item i1, Item i2) {
    if (i1.getId().compareTo(i2.getId()) < 0) {
        this.source = i1;
        this.target = i2;
    }
    else {
        this.source = i2;
        this.target = i1;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文