【问题标题】:self-reference field mapping in JPAJPA 中的自引用字段映射
【发布时间】:2011-12-19 19:28:19
【问题描述】:

假设我们有 User 实体类。用户可以与其他用户成为朋友。如何在不创建名为 Connection 的新实体或在数据库中创建多个条目的情况下映射此自引用集合字段?

@Entity
public class User {
...
@ManyToMany
private Collection<User> friends;
...
}

USER_ID-FRIEND_ID
1 - 2
2 - 1 (duplicate... I don't need it)

【问题讨论】:

  • 自引用多对多关系是有效的,可以使用 JPA 注释进行映射。像所有多对多关系一样,您必须定义一个桥表来存储关系的双方。实体将为关系的拥有方定义一个字段,并为关系的映射方定义另一个字段。

标签: java jpa eclipselink


【解决方案1】:

以下是我的 ElementEntity 代码的快照:

@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<ElementEntity> children;

@JoinColumn(name = "ParentId", referencedColumnName = "ElementId")
@ManyToOne(fetch = FetchType.LAZY)
private ElementEntity parent;

数据库中有字段的地方:

  • ElementId - 主键;
  • ParentId 与父母的关系

【讨论】:

  • 感谢您抽出宝贵时间。我不是在寻找亲子关系。
  • @HayatiGuvence 出了什么问题 - 只需将 ParentId 重命名为 USER_ID 并将 elementId 重命名为friend_Id
【解决方案2】:

您不能 - 您需要数据库中的两条记录。

实际上,对于友谊关系,我会说像 neo4j 这样的图形数据库是合适的选择。在那里你有两个用户,只需添加一个边缘“朋友”。

【讨论】:

  • 有趣...我认为可能有作弊或某事
  • 这个答案不正确。自引用多对多关系是有效的,并且可以在 JPA 中映射而无需定义任何新实体。该关系需要一个桥接表,就像所有多对多关系一样。
【解决方案3】:

至少你需要一个relational table

所以你有一个USER 表和一个FRIENDS

user_id friend_id
   1      2

但是@Bozho 的回答比我的好得多(neo4j)。

【讨论】:

  • :) 一个表中不能有两个相同的列名
【解决方案4】:

嗯,事实上你可以。

您可以使用@PreUpdate、@PrePersists、@PostUpdate 等注释手动转换集合的元素。这样,您的实体可以按照您想要的方式呈现它们,而在数据库中您只存储原始文本。

更合理的选择是使用自 jpa 2.1 起可用的 @Convert 注释(休眠中的 @UserType)。它告诉 jpa 每次在数据库中读取/保存时将该字段转换为另一种类型。 为此,您应该使用@Convert 注释,指定和 AttributeConverter 对象。

例如

    public class Parent {
      @Id
      private Integer id;

      @Convert(converter = FriendConverter.class)
      private Set<Parent>friends;
    }

转换器类如下:

    @Component
    public class FriendConverter implements AttributeConverter<List, String>{
      @Autowired
      private SomeRepository someRepository;

      @Override
      public String convertToDatabaseColumn(List attribute) {
        StringBuilder sb = new StringBuilder();
        for (Object object : attribute) {
          Parent parent = (parent) object;
          sb.append(parent.getId()).append(".");
        }
        return sb.toString();
      }

      @Override
      public List convertToEntityAttribute(String dbData) {
        String[] split = dbData.split(".");
        List<Parent>friends = new ArrayList<>();
        for (String string : split) {
          Parent parent = someRepository.findById(Integer.valueOf(string));
          friends.add(accion);
        }
        return friends;
      }
    }

这是一个虚拟的实现,但它给了你想法。

作为个人评论,我建议按应有的方式映射关系。将来它会避免你的问题。使用枚举时,AttributeConverter 会派上用场

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-19
    • 2010-10-24
    • 2023-03-15
    • 1970-01-01
    相关资源
    最近更新 更多