【问题标题】:Spring Data REST Joined Inheritance IssueSpring Data REST 加入继承问题
【发布时间】:2014-10-16 13:50:56
【问题描述】:

我在单个 JPA 实体上有一个 Spring Data Repository。该实体通过联合继承继承。

Spring Data REST 似乎在解释这种结构时存在问题,至少是自动解释。或者我可能误解了Inheritance.JOINED的用法

对带有Event 的任何实体的任何请求都会返回以下内容:

{
    cause: null,
    message: "Cannot create self link for class com.foo.event.SubEvent! No persistent entity found!"
}

也许我要求这个项目知道如何处理这个问题太多了,但是有没有一种解决方法可以将我的所有Events 分组到同一个/events 下?也许甚至允许我过滤类型?

我在下面留下了应用程序结构的基础知识。

Event.java

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@JsonTypeInfo(use = Id.NAME, include = As.PROPERTY, property = "type")
@JsonSubTypes({
  @Type(value = SubEvent.class), 
  ...
})
...
public class Event {
    @Id
    private long id;
    ...
}

SubEvent.java

@Entity
public class SubEvent extends Event {
    private String code;
    ...
}

EventRepository.java

@RepositoryRestResource(path = "events")
public interface EventRepository extends PagingAndSortingRepository<Event, Long> {
    ...    
}

【问题讨论】:

  • 问题不仅在于JOINED 继承类型。使用SINGLE_TABLE时发现同样的问题。

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


【解决方案1】:

我认为这个问题与 JPA 无关,而是一个循环序列化问题。由于您没有显示您的实体,我只能假设 Subevent 实体与另一个 (Sub)Event 有关系,并且一个 Subevent 引用自身,这会导致问题。当然也有可能不是直接的关系,而是通过其他一些实体类,比如 SubEvent -> EntityG -> Event。

要解决这个问题,只需使用DTO,在其中您只映射子事件的所有字段,产生循环依赖的字段除外。

【讨论】:

  • 嘿安德烈。对于这个练习,这些实体的命名可能很糟糕,因为我只是为了这个问题而擦洗了它们。实际上这个模型中没有循环引用:-/
  • 为了找到原因并最终确保没有循环引用,开始一一注释掉 JPA 映射的属性,直到找到导致问题的原因。
【解决方案2】:

我认为您缺少使用 Discriminator 让 JPA 了解用于给定对象的子类(它如何知道其他情况?)。

我倾向于对每个子类的表使用抽象类,所以这里有一个适合你的示例:

Event.java

@Entity
@DiscriminatorColumn(name = "type")
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class Event {
    @Id
    @GeneratedValue
    public Long id;

    public String type;
}

SubEvent.java

@Entity
@DiscriminatorValue("subevent")
@PrimaryKeyJoinColumn(name = "event_id")
public class PeeringService extends Service {
    private String code;
}

使用上面的代码,您会注意到一些奇怪的东西 - 在为这些对象之一生成资源路径时,它假定您为每个子类都有一个 Repository,并生成如下内容:

{
  "type" : "subevent",
  "code" : "bacon",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8081/subEvents/1"
    },
    "peeringService" : {
      "href" : "http://localhost:8081/subEvents/1"
    }
  }
}

这很容易解决,您只需在基类中添加以下注释:

@RestResource(path = "events")

它会生成你期望的资源路径!

希望这会有所帮助:)

【讨论】:

  • 这个带有 spring-data-rest 2.5.1 的解决方案不起作用
  • 感谢提醒,我正在运行2.4.4.RELEASE(当前spring-boot 推荐的版本)。下周我会在新版本上试一试:)
  • 在我的情况下,似乎只有一个(非确定性的)存储库(具有相同的路径)处理了请求,这导致休息控制器只提供部分行(只有那些存储库负责)。告诉我你的测试进展如何,我很想知道解决方案。
【解决方案3】:

我在一个简单的 Spring Boot 项目中尝试了你的课程,他们没有给我任何问题,我无法重现你遇到的问题。但是,搜索您描述的错误消息会给出一些帖子,这些帖子建议您需要创建一个 SubEvent 存储库,即使您不使用它,并且问题出现在更复杂的项目中,例如使用 REST。

参考:Cannot create self link for class X. No persistent entity found

How to choose MappingContext in spring-data-jpa (2x) + spring-rest-webmvc?

所以,尝试添加一个 SubEvent 存储库:

interface SubEventRepository extends CrudRepository<SubEvent, Long> {
}

【讨论】:

    【解决方案4】:

    我尝试了很多选项,但都没有按预期工作,并且总是在某一点上遇到问题(链接生成、存储库映射、url 映射等)。

    即使对于单独的存储库(每个子类型一个)我也没有成功。我的“肮脏但有效”的解决方案是使用ResourceProcessor 的实现对所有子类型的链接进行后处理。这个实现基本上用资源上每个链接上的类型名称替换了子类型名称。

    另外引入了RelProvider 来处理不同类型的属性名称。

    【讨论】:

      猜你喜欢
      • 2012-09-09
      • 1970-01-01
      • 2019-12-08
      • 1970-01-01
      • 2020-01-15
      • 1970-01-01
      • 2019-07-16
      • 2016-02-01
      • 2020-09-22
      相关资源
      最近更新 更多