【问题标题】:Spring / JPA join on namespaced keySpring / JPA 加入命名空间键
【发布时间】:2018-06-28 15:04:09
【问题描述】:

我正在为现有数据库创建 Spring 4 / Spring Data 应用程序。数据库结构和数据由闭源软件定义。

现有系统的一个方面是您可以对系统中的任何项创建评论。这意味着,一篇文章、一个文档、一个媒体文件(系统中的所有实体)可以有任意数量的 cmets,并且每个评论恰好针对系统中的一个实体。所有 cmets 都在 相同 comment 表中。

实现的方式是表comment 有一个列comment_for,它包含对它作为注释的实际实体的连接/命名空间/前缀引用。当前系统似乎只是通过在主键前面加上表名来构建连接查询:

+----+--------------------------------+----------------+ |编号 | comment_for |评论 | +----+--------------------------------+----------------+ | 1|文章:12345 |这个不错...| | 2|文件:42 |酷博士! | +----+--------------------------------+----------------+

此示例显示了两个 cmets,一个用于 article.id 为 12345 的文章,一个用于document.id 为 42 的文档。我创建了 @Entities 匹配数据库表和相应的存储库接口与查询方法我需要。

我想利用 Spring Data Repositories / Entities 来用相应的 cmets 填充我的实体集合,就像实体文章的这个(伪代码)。

@OneToMany(mappedBy = "comment_for", prefix = "article:")
private List<Comment> comment = new ArrayList<>();

我只需要它单向。我的实体(目前ArticleDocumentMediafile)应该持有他们的 cmets 的集合。我不需要 cmets 来保留对实体的引用。

有没有办法做到这一点?生成的 SQL 查询应该类似于

SELECT * FROM .... WHERE comment.comment_for = concat('<entityname>:', <entity>.id); 

我查看了@JoinColumn,但无法修改连接的使用值,只能修改列名。我目前唯一的解决方案是 CommentRepository 接口上的手动 @Querys,它为我提供了某个实体/ID 组合的所有 cmets 的 ArrayList。但我想让 cmets 作为我的业务实体的一部分自动加入。

更新:看起来我可以将comment_for 中的命名空间和ID 拆分为两个新列,而不会中断现有软件。这两列现在是comment_for_idcomment_for_entityname

【问题讨论】:

  • comment_for中键值对的作用是什么?如果您的实体 id 与 comment_for 中的值完全匹配,它应该可以解决您的问题。可以修改表吗?您还可以拆分 comment_for 以仅包含像您的实体一样的 id。添加一个额外的列,如 entity_type 将允许您避免不同实体之间的重复 id 值。
  • 我没有编写创建表/插入数据的软件,但他们使用它来附加/连接 cmets 与任何其他实体。我喜欢 entity_type 的想法。 Spring 将如何解决。使用@JoinColumns?我必须看看我是否可以使用存储过程来拆分comment_for,因为写入数据的系统不在我的控制之下
  • 您可以在实体和评论之间关系的所有者方面使用@JoinCoumn。在您的情况下,它看起来像是 Comment 实体/表,因为每个实体都有许多 cmets。只要您能够使用一些 PL/SQL 创建一个新的修改结构,那应该可以工作。希望这会有所帮助!
  • 谢谢。如果你用对应的代码sn-ps写一个答案帖子,我可以接受它作为解决方案。

标签: java spring jpa spring-data-jpa spring-data


【解决方案1】:

您还可以拆分 comment_for 以仅包含您的实体的 id。添加一个额外的列,如 entity_type 可以让您避免不同实体之间的重复 id 值。

您也可以在实体和评论之间关系的所有者方面使用@JoinColumn。在您的情况下,它看起来像是 Comment 实体/表,因为每个实体有很多 cmets。

例子:

@Entity
@NamedQueries({ @NamedQuery(name = "Comments.findAll", query = "select o from Comments o") })
@IdClass(CommentsPK.class)
public class Comments implements Serializable {
    private static final long serialVersionUID = 4787438687752132432L;
    @Id
    @Column(name = "COMMENT_TEXT", nullable = false, length = 30)
    private String commentText;
    @Id
    @Column(name = "ENTITY_TYPE", nullable = false, length = 30)
    private String entityType;
    @ManyToOne
    @Id
    @JoinColumn(name = "COMMENT_FOR")
    private EntityDemo entityDemo;

请注意,我将所有三个字段的组合设置为主键,我不确定您当前设置中使用什么标准作为 PK。

这是一个实体的例子。属性是为了演示而制作的。

@Entity
@NamedQueries({ @NamedQuery(name = "EntityDemo.findAll", query = "select o from EntityDemo o") })
@Table(name = "ENTITY_DEMO")
public class EntityDemo implements Serializable {
    private static final long serialVersionUID = -8709368847389356776L;
    @Column(length = 1)
    private String data;
    @Id
    @Column(nullable = false)
    private BigDecimal id;
    @OneToMany(mappedBy = "entityDemo", cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    private List<Comments> commentsList;

【讨论】:

  • 谢谢。我不确定您的映射是如何工作的。 EntityDemo 需要对 Comments 的单向引用,因为有 14 个不同的 EntityDemo 实体(文章、文档、媒体...)。 Comment 不知道字段级别的 EntityDEmo,可能仅作为 String-Type。
  • 您是否将不同类型的实体捕获为 EntityDemo 对象的属性?还是通过继承实现的?关于评论有一个实体演示,也许我没有正确理解这个问题,但我的想法是如果你删除前缀并且只包含 id 它可能是一个 FK。该 FK 将指向与特定评论相关联的实体。我知道你提到这可能是不可能的,因为 db 结构是在其他地方管理的。
  • 我已经更新了我的问题。外键是一个组合,由 ID 和 ID 所在的实体组成。在数据库中创建内容的系统对任何其他实体上的所有 cmets 使用单个评论表。如果我对 ID 为 123 的实体文章发表评论,我的帖子将保存在表 comment 中,comment_for 设置为 article:123。如果我对媒体文件发表评论,则评论在同一个评论表中,但 comment_for 设置为 media_file:123(123 现在是媒体文件的 ID,而不是文章)。
猜你喜欢
  • 2021-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-18
  • 1970-01-01
  • 1970-01-01
  • 2020-05-31
相关资源
最近更新 更多