Spring Data REST 继承关系中的连接问题

10

我有一个Spring Data仓储库,涉及单个JPA实体。该实体通过联接继承进行子类化。

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

任何使用Event的实体的请求都会返回以下内容:

{
    cause: null,
    message: "Cannot create self link for class com.foo.event.SubEvent! No persistent entity found!"
}
也许对于这个项目来说,我期望过高了,希望它知道如何处理这个问题,但是是否有一种解决方法可以将我所有的事件分组到同一个/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 时也会出现相同的问题。 - Francisco Spaeth
4个回答

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的解决方案不起作用。 - Francisco Spaeth
谢谢提醒,我正在使用2.4.4.RELEASE(当前spring-boot推荐的版本)。下周我会尝试在更新的版本上操作 :) - bly
在我的情况下,似乎只有一个(非确定性的)存储库(具有相同路径)处理了请求,这导致REST控制器仅提供部分行(仅由存储库负责的行)。让我知道你的测试结果如何,我很想知道解决方案。 - Francisco Spaeth

1
我在一个简单的Spring Boot项目中测试了您的类,没有出现任何问题,我无法重现您遇到的问题。然而,根据您描述的错误消息进行搜索,有几篇文章建议即使您不使用它,也需要创建一个SubEvent存储库,并且这个问题在更复杂的项目中会出现,例如使用REST。

参考文献: 无法为类X创建自链接。找不到持久实体

如何在spring-data-jpa(2x)+ spring-rest-webmvc中选择MappingContext?

因此,请尝试添加一个SubEvent存储库:

interface SubEventRepository extends CrudRepository<SubEvent, Long> {
}

0

我尝试了很多选项,但没有一个按预期工作,总是在某一点上出现问题(如链接生成、仓库映射、URL 映射等)。

即使对于分离的仓库(每个子类型一个),我也没有成功。我的“非常不优雅但可行”的解决方案是使用 ResourceProcessor 实现对所有子类型的链接进行后处理。该实现基本上是在资源中替换每个链接上的子类型名称为类型名称。

此外,还引入了一个 RelProvider 来处理不同类型的属性名称。


0

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

要解决这个问题,只需使用DTO,其中映射SubEvent的所有字段,除了那些产生循环依赖的字段。


嘿,Andrei。这些实体可能只是为了这个练习而命名不当,因为我只是为了问题而清理了它们。实际上,在这个模型中没有循环引用 :-/ - bvulaj
为了找出原因并最终确保没有循环引用,请逐个注释掉JPA映射的属性,直到找到问题所在。 - V G

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接