Jpa系统信息库和JsonIgnoreProperties在getOne()和findAll()方法中返回的对象不同,

时间:2018-10-29 13:50:32

标签: hibernate jpa spring-data-jpa

简要背景

我在Spring Boot上创建的API中有两种方法(通过Hibernate和JpaRepository)从mySQL数据库中检索数据。有一种方法可以返回名为 test 的表中的所有事件,而另一种方法可以返回与作为GET调用中的参数传递的id对应的 test 。两个API入口点(通过服务和存储库)最终都调用了两个JpaRepository方法(分别是 findAll() getOne())。

问题描述

我观察到的问题是,在 findAll()方法中,JpaRepository的行为与 getOne()不同,涉及到返回与之相对应的内部对象列表模型中的@ManyToMany关系。 test 类具有与模型的不同实体相对应的必要对象的列表。这两个类如下:

Pectest.java

@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="idtest")
public class Pectest {
@Id
@Column(name="idtest")
private long idtest;
private String testname;
private String testdescription;

[...]
// Other properties and fields
[...]

@ManyToMany(fetch = FetchType.LAZY
    )
@JoinTable(name = "test_checks_requisite",
        joinColumns = @JoinColumn(name = "test_idtest"),
        inverseJoinColumns = @JoinColumn(name = "requisite_idrequisite")
    )
@JsonProperty(access=Access.READ_ONLY)
private Set<Requisite> requisites = new HashSet<Requisite>();
[...]

requisite.java

@Entity
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
@JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="idrequisite")
public class Requisite {
@Id
@Column(name="idrequisite")
private long idrequisite;
private String Name;
private String Title;
private String Description;
@ManyToOne(cascade = {CascadeType.PERSIST}, fetch=FetchType.LAZY)
@JoinColumn(name="functionality_idfunctionality")
@JsonProperty(access=Access.WRITE_ONLY)
private Functionality functionality; 

@ManyToMany(mappedBy="requisites")
private Set<Pectest> tests = new HashSet<Pectest>();

这是由GET映射返回的JSON片段,该映射返回所有测试。可以看出,第一个 test 对象(具有 idtest 9的对象)在必要条件<下具有5个必要条件对象的集合。 / strong>属性。相反,第二个 test (ID为10)仅显示前一个对象中不存在的完整 Requirement 对象,仅显示ID的值在其他人中:

[
{
    "idtest": 9,
    "testtype": {
        "idTestType": 5,
        "testTypeName": "Manual"
    },
    "datatype": null,
    "requisites": [
        {
            "idrequisite": 7,
            "name": "REQ-0006",
            "description": "Campo para traducción de nombres, debe mostrar el nombre en el idioma seleccionado por el cliente.",
            "title": "DisplayName"
        },
        {
            "idrequisite": 4,
            "name": "REQ-0003",
            "description": "Se ofrece acceso a parámetros a través de este tipo de nodo",
            "title": "Parameter Type"
        },
        {
            "idrequisite": 5,
            "name": "REQ-0004",
            "description": "El BrowseName de las variables debe ser sólo el último campo de las variables exportadas por FW de BR (ItemName)",
            "title": "BrowseName"
        },
        {
            "idrequisite": 3,
            "name": "REQ-0002",
            "description": "Se ofrece acceso a variables analógicas a través de este tipo de nodo",
            "title": "Analog Type"
        },
        {
            "idrequisite": 2,
            "name": "REQ-0001",
            "description": "Se ofrece acceso a variables digitales a través de este tipo de nodo",
            "title": "Digital Type"
        }
    ],
    "testDescription": "El servidor es capaz de devolver correctamente todos los tipos de dato.",
    "lastUpdated": null,
    "testName": "Lectura de DataTypes",
    "dateCreated": null,
    "testURL": ""
},
{
    "idtest": 10,
    "testtype": {
        "idTestType": 5,
        "testTypeName": "Manual"
    },
    "datatype": {
        "idDataType": 2,
        "dataTypeName": "Boolean"
    },
    "requisites": [
        7,
        5,
        {
            "idrequisite": 10,
            "name": "REQ-0009",
            "description": "Se generan a partir de los niveles de acceso de la variable. Se deben escalar los valores, de 256 a 1000.",
            "title": "AccessLevel & UserAccessLevel"
        },
        2
    ],
    "testDescription": "El servidor es capaz de admitir escrituras correctamente de todos los tipos de dato.",
    "lastUpdated": null,
    "testName": "Escritura de DataTypes",
    "dateCreated": null,
    "testURL": ""
}
...
]

下面是通过其ID调用单个对象的GET方法的结果(在本例中是ID为10的对象,在先前的JSON中不正确):

{
"idtest": 10,
"testtype": {
    "idTestType": 5,
    "testTypeName": "Manual"
},
"datatype": {
    "idDataType": 2,
    "dataTypeName": "Boolean"
},
"requisites": [
    {
        "idrequisite": 7,
        "name": "REQ-0006",
        "description": "Campo para traducción de nombres, debe mostrar el nombre en el idioma seleccionado por el cliente.",
        "title": "DisplayName"
    },
    {
        "idrequisite": 2,
        "name": "REQ-0001",
        "description": "Se ofrece acceso a variables digitales a través de este tipo de nodo",
        "title": "Digital Type"
    },
    {
        "idrequisite": 5,
        "name": "REQ-0004",
        "description": "El BrowseName de las variables debe ser sólo el último campo de las variables exportadas por FW de BR (ItemName)",
        "title": "BrowseName"
    },
    {
        "idrequisite": 10,
        "name": "REQ-0009",
        "description": "Se generan a partir de los niveles de acceso de la variable. Se deben escalar los valores, de 256 a 1000.",
        "title": "AccessLevel & UserAccessLevel"
    }
],
"testDescription": "El servidor es capaz de admitir escrituras correctamente de todos los tipos de dato.",
"lastUpdated": null,
"testName": "Escritura de DataTypes",
"dateCreated": null,
"testURL": ""

}

其他信息

我观察到以下行为:

  • 如果我仅将一项必备条件与单个测试相关联,它将按预期工作。
  • 如果我将一个条件与两个或多个测试相关联,它将仅在第一个测试中返回该对象,而在随后的一个中仅返回其索引值。

由于这两点,我认为这似乎是一些缓存问题(我没有启用二级缓存或查询级缓存)。我的意思是,hibernate似乎仅是第一次从数据库中检索给定的条件,而其余的则检测到已请求了具有该ID的条件,并且没有启动查询。当然,这很好,但是如何在随后具有必要条件关联的 test 对象中将缓存的对象包含在结果中?

编辑:好的,我将其发布为答案,因为我在原始帖子中描述的问题似乎消失了。就像我在原始帖子的评论中说的那样,我删除了Requisite类上的@JsonIdentityInfo批注。我使用它来避免由于模型类之间的@ManyToMany关系而导致的无限递归。

但是,我不认为这是一种解决方案,并且绝对不了解@JsonIdentityInfo的工作原理。我会阅读该文档,但是如果有人可以提供一个解释,我将不胜感激。

0 个答案:

没有答案