我希望您能协助翻译编程相关内容,从Play Framework转向Spring Boot时遇到了一些难以理解的问题。
考虑以下简单实体:
当在控制器中调用getSystems()方法时,我希望得到一个填充了基本字段的所有系统列表,因为其他所有内容都是懒加载的。这也确实发生了,我还检查了Hibernate查询,唯一被查询的表确实是System表。到目前为止一切正常。
但我的第一个问题是,我也希望system.systemtype.systemtypeid被填充,因为这是系统表中的外键,但这始终为空。如果我使用EclipseLink,我相信这将是预期的行为,但在Hibernate中不应该是这样的。 我添加了一个System对象的虚拟列(systemtypeid)以进行验证,这确实得到了填充。所以: system.systemtypeid = "Something" system.systemtype.systemtypeid = null
我认为这两个都应该是"Something",那么我错过了什么吗?
我在此期间找到了解决方法,只有在注释使用属性级别访问时,Hibernate 才会获取外键 ID。这里有说明: https://developer.jboss.org/wiki/HibernateFAQ-TipsAndTricks#jive_content_id_How_can_I_retrieve_the_identifier_of_an_associated_object_without_fetching_the_association 当使用 Play 时,我没有遇到这种行为,我现在猜测 Play 可能会在幕后执行一些操作来生成它们。
第二个问题开始于将数据序列化为 JSON 以便发送到客户端。
首先我希望能够得到惰性初始化异常,因为转换是在控制器内完成的,而事务注释方法在服务上。令人惊讶的是,这并没有发生,项目集被惰性加载,并且所有项都可以很好地序列化为 JSON。 再次无法理解这种行为,为什么惰性加载在控制器内部进行时仍然有效?Spring Boot 是否在控制器方法开始时打开会话?
我已经理解了这个问题(感谢Nico指导),Spring Boot默认启用OpenSessionInView(非常糟糕的想法),因此我必须在我的applications.properties中添加spring.jpa.open-in-view=false。
更令人惊讶的是,即使这样,system.systemtype仍将为空,也不会进行懒加载。唯一能够加载system.systemtype的方法是将其声明为急切加载。
也许我错过了一些明显的东西,但我很难理解这种行为,这与我使用Play时所经历的完全不同,我认为这种行为应该是完全相同的。
在所有编辑之后,唯一剩下的问题是为什么system.systemtype永远不会进行懒加载。我进行了一些测试,只有当我为Systemtype实体的所有字段添加getter/setter时,它才会进行懒加载。这正常吗?
查看Hibernate文档,现在似乎是这样: https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html "默认情况下,Hibernate3对于集合使用延迟选择获取,对于单值关联使用延迟代理获取。这些默认设置对于大多数应用程序中的大多数关联关系是有意义的。"
"代理获取:当调用与关联对象相关联的除标识符getter之外的方法时,将获取单值关联。"
这是否意味着所有用于单值关联的实体都需要定义其所有字段的getter和setter才能进行延迟加载?这听起来非常令人困惑,因为它在所有其他场景中的工作方式都不同。
在Play中,我从未需要使用getter/setter,所以也许Play改变了单值关联的默认获取策略?甚至有没有一种方法可以做到这一点?"
考虑以下简单实体:
@Entity
@Table(name = "system")
public class System {
@Id
@Column(name = "systemid", unique = true, nullable = false, length = 36)
public String systemid;
@ManyToOne(fetch = FetchType.LAZY, optional=false)
@JoinColumn(name = "systemtypeid", nullable = false)
public Systemtype systemtype;
//This column is added just for testing purposes, see comments below
@Column(name = "systemtypeid", insertable=false, updatable=false)
public String systemtypeid;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "system")
public Set<SystemItem> items = new HashSet<SystemItem>(0);
}
@Entity
@Table(name = "systemtype")
public class Systemtype {
@Id
@Column(name = "systemtypeid", unique = true, nullable = false, length = 36)
@Access(AccessType.PROPERTY)
public String systemtypeid;
public String getSystemtypeid() {
return systemtypeid;
}
public void setSystemtypeid(String systemtypeid) {
this.systemtypeid = systemtypeid;
}
@Column(name = "name", length = 60)
public String name;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "systemtype")
public Set<System> systems = new HashSet<System>(0);
}
@Entity
@Table(name = "systemitem")
public class SystemItem {
@Id
@Column(name = "systemitemid", unique = true, nullable = false, length = 36)
public String systemitemid;
@Column(name = "name", length = 60)
public String name;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "systemid", nullable = false)
public System system;
}
控制器:
@RestController
@RequestMapping(value = ApiController.SYSTEM_URL)
public class SystemController extends ApiController {
private static final Logger log = LoggerFactory.getLogger(SystemController.class);
@Autowired
private SystemService systemService;
@RequestMapping(method = RequestMethod.GET)
public Collection<System> getSystems() throws Exception {
List<System> systems = systemService.getSystems();
return systems;
}
}
最后,服务部分:
@Service
@Transactional(readOnly = true, value = "tmPrimary")
public class SystemService {
private static final Logger log = LoggerFactory.getLogger(SystemService.class);
@Autowired
SystemRepository systemRepository; //Spring-Data's PagingAndSortingRepository
public List<System> getSystems() {
return Lists.newArrayList(systemRepository.findAll());
}
}
当在控制器中调用getSystems()方法时,我希望得到一个填充了基本字段的所有系统列表,因为其他所有内容都是懒加载的。这也确实发生了,我还检查了Hibernate查询,唯一被查询的表确实是System表。到目前为止一切正常。
但我的第一个问题是,我也希望system.systemtype.systemtypeid被填充,因为这是系统表中的外键,但这始终为空。如果我使用EclipseLink,我相信这将是预期的行为,但在Hibernate中不应该是这样的。 我添加了一个System对象的虚拟列(systemtypeid)以进行验证,这确实得到了填充。所以: system.systemtypeid = "Something" system.systemtype.systemtypeid = null
我认为这两个都应该是"Something",那么我错过了什么吗?
我在此期间找到了解决方法,只有在注释使用属性级别访问时,Hibernate 才会获取外键 ID。这里有说明: https://developer.jboss.org/wiki/HibernateFAQ-TipsAndTricks#jive_content_id_How_can_I_retrieve_the_identifier_of_an_associated_object_without_fetching_the_association 当使用 Play 时,我没有遇到这种行为,我现在猜测 Play 可能会在幕后执行一些操作来生成它们。
第二个问题开始于将数据序列化为 JSON 以便发送到客户端。
首先我希望能够得到惰性初始化异常,因为转换是在控制器内完成的,而事务注释方法在服务上。令人惊讶的是,这并没有发生,项目集被惰性加载,并且所有项都可以很好地序列化为 JSON。 再次无法理解这种行为,为什么惰性加载在控制器内部进行时仍然有效?Spring Boot 是否在控制器方法开始时打开会话?
我已经理解了这个问题(感谢Nico指导),Spring Boot默认启用OpenSessionInView(非常糟糕的想法),因此我必须在我的applications.properties中添加spring.jpa.open-in-view=false。
更令人惊讶的是,即使这样,system.systemtype仍将为空,也不会进行懒加载。唯一能够加载system.systemtype的方法是将其声明为急切加载。
也许我错过了一些明显的东西,但我很难理解这种行为,这与我使用Play时所经历的完全不同,我认为这种行为应该是完全相同的。
在所有编辑之后,唯一剩下的问题是为什么system.systemtype永远不会进行懒加载。我进行了一些测试,只有当我为Systemtype实体的所有字段添加getter/setter时,它才会进行懒加载。这正常吗?
查看Hibernate文档,现在似乎是这样: https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html "默认情况下,Hibernate3对于集合使用延迟选择获取,对于单值关联使用延迟代理获取。这些默认设置对于大多数应用程序中的大多数关联关系是有意义的。"
"代理获取:当调用与关联对象相关联的除标识符getter之外的方法时,将获取单值关联。"
这是否意味着所有用于单值关联的实体都需要定义其所有字段的getter和setter才能进行延迟加载?这听起来非常令人困惑,因为它在所有其他场景中的工作方式都不同。
在Play中,我从未需要使用getter/setter,所以也许Play改变了单值关联的默认获取策略?甚至有没有一种方法可以做到这一点?"
fetch = FetchType.LAZY
,所以它是 null。你能发布一下你的 Hibernate 配置吗? - Rafik BELDI