具有 Mongodb 相同 table 的第二次查询结果取决于相同 table 的第一次查询的结果字段的 Hibernate OGM
Hibernate OGM with Mongodb Result of 2nd Query on same table dependent on Result fields of 1st query of same table
我正在使用 Hibernate OGM (5.2.0.Alpha1) 和 Mongodb (3.4)
@Entity
@Table(name = "service")
@JsonInclude(Include.NON_EMPTY)
public class Service {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "SERVICE_ID", unique = true, nullable = false)
@JsonSerialize(using = ToStringSerializer.class)
public ObjectId id;
private String name;
@ManyToOne
@JsonIgnore
public Lab lab;
getter....
setter....
}
@Entity
@Table(name = "lab")
@JsonInclude(Include.NON_EMPTY)
// @JsonFilter(value=SalesUtils.MY_CUSTOM_FILTER_FOR_LAB)
public class Lab {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonSerialize(using = ToStringSerializer.class)
@Column(name = "LAB_ID", unique = true, nullable = false)
public ObjectId id;
private String name;
@OneToMany(mappedBy = "lab")
public List<Service> listOfServices;
getter....
setter....
}
道层:
public <T> List<T> executeQuery(String query, Integer startPosition, Integer noOfRecords, T t) {
List<T> listOfT = new ArrayList<>();
if (SalesUtils.isObjectisNullOrEmpty(startPosition, noOfRecords)) {
listOfT = entityManager.createNativeQuery(query.toString(), t.getClass()).getResultList();
} else {
listOfT = entityManager.createNativeQuery(query.toString(), t.getClass()).setFirstResult(startPosition)
.setMaxResults(noOfRecords).getResultList();
}
return SalesUtils.isListIsNullOrEmpty(listOfT) ? new ArrayList<>() : listOfT;
}
服务层:(问题:实验室名称:空)
@Transaction
public void executeQuery(){
String query = "db.service.find({} , {"name":1})";
List<Service> listOfServices = myDao.executeQuery(query , null , null ,new Service());
String anotherQuery = " { $query : { name : "CDG Service"}}";
List<Service> listOfAnotherServices = myDao.executeQuery(query , null , null ,new Service());
if (!SalesUtils.isListIsNullOrEmpty(listOfAnotherServices )) {
System.out.println(listOfAnotherServices.get(0).getName());
System.out.println(listOfAnotherServices.get(0).getLab().getName()); //null
}
}
服务层:(临时解决方案)
@Transaction
public void executeQuery(){
//Temporary solution : added lab_LAB_ID field in below 1st query
String query = "db.service.find({} , {"name":1,"lab_LAB_ID":1})";
List<Service> listOfServices = myDao.executeQuery(query , null , null ,new Service());
String anotherQuery = " { $query : { name : "CDG Service"}}";
List<Service> listOfAnotherServices = myDao.executeQuery(query , null , null ,new Service());
if (!SalesUtils.isListIsNullOrEmpty(listOfAnotherServices )) {
System.out.println(listOfAnotherServices.get(0).getName());
System.out.println(listOfAnotherServices.get(0).getLab().getName()); //not null
}
}
详细说明:
- 服务层:(问题:实验室名称:空)
这里我只得到'name'服务领域table使用第一个查询执行(变量名=查询)然后执行第二个查询(变量名=另一个查询),但不能得到实验室对象.
- 服务层:(临时解决方案)
所以我使用第一次查询执行(变量名=查询)得到'name'和'lab_LAB_ID'两个字段然后我执行了第二次查询(变量名=另一个查询)所以我不能成功地得到实验室对象。
我不明白这个。
似乎第二个查询结果依赖于第一个查询结果字段,即使查询不同并且变量名称也不同。
我说的对吗?
编辑:
问题是第一个查询的结果被缓存(在会话级别),然后在第二个查询中重用。因为您 运行 的初始查询没有 return 所有字段,所以实体仅被部分初始化。当您想要重新创建实体时,请确保 return 所有字段。当用户尝试重新创建仅具有属性子集的实体时,Hibernate OGM 应该抛出异常。我将为此创建一个新的 JIRA。
当您指定 {name: 1}
时,您只要求 return 以下字段:_id
和 name
;
因为您请求服务,Hibernate OGM 会将这些值转换为服务 class。问题是结果不包含实验室,因此该字段为空(应该有一个例外)。
当您 运行 db.service.find({} , {"name":1,"lab_LAB_ID":1})
时,您还 return 使用实验室标识符,有了这些附加信息,OGM 也可以将实验室添加到服务中。
如果您需要整个服务,您应该使用的本机查询是:
String query = "db.service.find({})";
但我建议针对这种情况使用 HQL 查询:
String hqlQuery = "FROM Service";
List<Service> services = entityManager.createQuery(hqlQuery, Service.class)
.getResultList();
顺便说一句,你不需要每次运行查询时都创建一个新的Service(),你可以将参数定义为Class<T>
,然后传递Service.class
相反。
使用本机查询,如果您选择在根上应用投影 class 您必须删除 toEntity,因为不应允许提取部分实体。
很可能会在产品的下一个版本中引入异常抛出来阻止这种使用。
这也是 Hibernate ORM (5.2 | 5.3) 在 H2 方言上的当前行为。
我正在使用 Hibernate OGM (5.2.0.Alpha1) 和 Mongodb (3.4)
@Entity
@Table(name = "service")
@JsonInclude(Include.NON_EMPTY)
public class Service {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "SERVICE_ID", unique = true, nullable = false)
@JsonSerialize(using = ToStringSerializer.class)
public ObjectId id;
private String name;
@ManyToOne
@JsonIgnore
public Lab lab;
getter....
setter....
}
@Entity
@Table(name = "lab")
@JsonInclude(Include.NON_EMPTY)
// @JsonFilter(value=SalesUtils.MY_CUSTOM_FILTER_FOR_LAB)
public class Lab {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@JsonSerialize(using = ToStringSerializer.class)
@Column(name = "LAB_ID", unique = true, nullable = false)
public ObjectId id;
private String name;
@OneToMany(mappedBy = "lab")
public List<Service> listOfServices;
getter....
setter....
}
道层:
public <T> List<T> executeQuery(String query, Integer startPosition, Integer noOfRecords, T t) {
List<T> listOfT = new ArrayList<>();
if (SalesUtils.isObjectisNullOrEmpty(startPosition, noOfRecords)) {
listOfT = entityManager.createNativeQuery(query.toString(), t.getClass()).getResultList();
} else {
listOfT = entityManager.createNativeQuery(query.toString(), t.getClass()).setFirstResult(startPosition)
.setMaxResults(noOfRecords).getResultList();
}
return SalesUtils.isListIsNullOrEmpty(listOfT) ? new ArrayList<>() : listOfT;
}
服务层:(问题:实验室名称:空)
@Transaction
public void executeQuery(){
String query = "db.service.find({} , {"name":1})";
List<Service> listOfServices = myDao.executeQuery(query , null , null ,new Service());
String anotherQuery = " { $query : { name : "CDG Service"}}";
List<Service> listOfAnotherServices = myDao.executeQuery(query , null , null ,new Service());
if (!SalesUtils.isListIsNullOrEmpty(listOfAnotherServices )) {
System.out.println(listOfAnotherServices.get(0).getName());
System.out.println(listOfAnotherServices.get(0).getLab().getName()); //null
}
}
服务层:(临时解决方案)
@Transaction
public void executeQuery(){
//Temporary solution : added lab_LAB_ID field in below 1st query
String query = "db.service.find({} , {"name":1,"lab_LAB_ID":1})";
List<Service> listOfServices = myDao.executeQuery(query , null , null ,new Service());
String anotherQuery = " { $query : { name : "CDG Service"}}";
List<Service> listOfAnotherServices = myDao.executeQuery(query , null , null ,new Service());
if (!SalesUtils.isListIsNullOrEmpty(listOfAnotherServices )) {
System.out.println(listOfAnotherServices.get(0).getName());
System.out.println(listOfAnotherServices.get(0).getLab().getName()); //not null
}
}
详细说明:
- 服务层:(问题:实验室名称:空)
这里我只得到'name'服务领域table使用第一个查询执行(变量名=查询)然后执行第二个查询(变量名=另一个查询),但不能得到实验室对象.
- 服务层:(临时解决方案)
所以我使用第一次查询执行(变量名=查询)得到'name'和'lab_LAB_ID'两个字段然后我执行了第二次查询(变量名=另一个查询)所以我不能成功地得到实验室对象。
我不明白这个。 似乎第二个查询结果依赖于第一个查询结果字段,即使查询不同并且变量名称也不同。
我说的对吗?
编辑: 问题是第一个查询的结果被缓存(在会话级别),然后在第二个查询中重用。因为您 运行 的初始查询没有 return 所有字段,所以实体仅被部分初始化。当您想要重新创建实体时,请确保 return 所有字段。当用户尝试重新创建仅具有属性子集的实体时,Hibernate OGM 应该抛出异常。我将为此创建一个新的 JIRA。
当您指定 {name: 1}
时,您只要求 return 以下字段:_id
和 name
;
因为您请求服务,Hibernate OGM 会将这些值转换为服务 class。问题是结果不包含实验室,因此该字段为空(应该有一个例外)。
当您 运行 db.service.find({} , {"name":1,"lab_LAB_ID":1})
时,您还 return 使用实验室标识符,有了这些附加信息,OGM 也可以将实验室添加到服务中。
如果您需要整个服务,您应该使用的本机查询是:
String query = "db.service.find({})";
但我建议针对这种情况使用 HQL 查询:
String hqlQuery = "FROM Service";
List<Service> services = entityManager.createQuery(hqlQuery, Service.class)
.getResultList();
顺便说一句,你不需要每次运行查询时都创建一个新的Service(),你可以将参数定义为Class<T>
,然后传递Service.class
相反。
使用本机查询,如果您选择在根上应用投影 class 您必须删除 toEntity,因为不应允许提取部分实体。 很可能会在产品的下一个版本中引入异常抛出来阻止这种使用。 这也是 Hibernate ORM (5.2 | 5.3) 在 H2 方言上的当前行为。