我正在将Spring Boot 1.5.21项目(Java 8U221)升级到Spring Boot 2.1.9(Java 11.0.2-Open)。在这两种情况下,我们都使用带有Spring Boot启动程序和依赖关系解析器的gradle构建,因此底层spring、JPA和Hibernate库的版本都是spring管理的。
该项目有一个可选的一对一映射,其中子实体从父实体生成的ID获取其ID。在项目的Spring Boot1版本中,关系配置如下:
@Entity
@Table(name = "PARENT_OBJECT", schema = "MYSCHEMA")
public class ParentObject implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "PARENT_OBJECT_ID_SEQ")
@SequenceGenerator(name = "PARENT_OBJECT_ID_SEQ", sequenceName = "MYSCHEMA.PARENT_OBJECT_ID_SEQ")
protected Long id;
@OneToOne(optional = true, mappedBy = "parentObject", cascade = CascadeType.ALL, orphanRemoval = true)
@Valid
protected ChildObject childObject;
// Other fields and methods
}
@Entity
@Table(name = "CHILD_OBJECT", schema = "MYSCHEMA")
public class ChildObject implements Serializable {
@Id
@Column(name = "parent_object_id", unique = true, nullable = false, insertable = true, updatable = false)
private Long parentObjectId;
@OneToOne
@MapsId
@PrimaryKeyJoinColumn
@JsonIgnore
private ParentObject parentObject;
// Other fields and methods
}
当我更新到Spring Boot2时,我必须更新很多JPA设置,特别是有一点被抱怨的是,生成的查询正在查找'parentobject_id'而不是'parent_object_id',所以我对其进行了一些研究,找到了一篇解释如何用@joincolumn
修复一对一映射的列名的文章,并将子html" target="_blank">对象的parentObject字段的注释更新为:
@OneToOne
@MapsId
@JoinColumn(name = "parent_object_id")
@JsonIgnore
private ParentObject parentObject;
我完全删除了@primarykeyjoincolumn
,因为文档似乎建议,如果您希望Hibernate处理ID的分配,并且如果您要自己管理这些ID,那么就应该使用@primarykeyjoincolumn
。
这个配置在我的所有测试中都运行良好,除了2:控制器的更新集成测试(当ParentObject首次与相关联的ChildObject一起创建时,POST测试也运行良好)。对于这两个测试,我得到的错误是:
JPasystemException:试图从null一对一属性[org.MyCompany.MyProject.MyModule.MySubModule.ChildObject.ParentObject]中分配id;嵌套异常为org.hibernate.id.IdentifierGenerationException:尝试从null一对一属性[org.MyCompany.MyProject.MyModule.MySubModule.ChildObject.ParentObject]分配id
奇怪的是,这些实体及其关联的所有存储库集成测试都通过了,所有其他控制器集成测试也都通过了,包括一个新的ParentObject
与它的新的ChildObject
一起发布的测试。我到处寻找一个可能的解决方案,但我读到的每一篇文章似乎都暗示我使用的配置应该可以工作。我还尝试了其他配置,这些配置建议使用@PrimaryKeyJoinColumn
和自己设置ID字段,在ChildObject
的ID上使用ID生成器(尽管@MapSID
的目的是告诉系统使用ParentObject
的ID),但通常我最终得到的结果是更多的测试失败,出现以下错误:
JPasystemException:在调用save()之前必须手动分配该类的ID:org.myCompany.myProject.myModule.mySubModule.ChildObject;嵌套异常为org.hibernate.id.IdentifierGenerationException:调用save()之前必须手动分配该类的ID:org.myCompany.myProject.myModule.mySubModule.ChildObject
虽然有时我会得到最初的错误,即不能‘从null分配id’。在这一点上,我不知道这是如何配置不正确的,或者是什么其他因素在搅乱事情。在这一点上,我愿意尝试任何和所有的建议。
为了完整起见,下面是应用程序中的一些代码片段。堆栈跟踪中的相关行号会被注释。我省略了控制器代码,因为它没有什么特别之处;POST和PUT方法都调用相同的服务方法;它们只是在不同的endpoint上,PUT首先检查对象是否存在于DB中,然后调用service save方法。下面是为ParentObject
调用JPA repo的服务方法:
@Service
@Transactional(readOnly = true)
public class ParentObjectServiceImpl implements ParentObjectService {
// other fields and other methods
@Autowired
private ParentObjectRepository parentObjectRepository;
@Transactional(readOnly = false)
@Override
public ParentObject saveParentObject(final ParentObject parentObject) {
parentObject.prepForPersistence();
return parentObjectRepository.save(parentObject); //Line 93
}
}
下面是我的JPA存储库:
public interface ParentObjectRepository extends CrudRepository<ParentObject, Long> {
// custom methods, no override for save though
}
public void prepForPersistence() {
if(childObject != null) {
childObject.setParentObject(this);
// In some iterations of the code in trying to solve this, I also had the following line
//childObject.setParentObjectId(this.id);
}
}
@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApplication.class)
@WebAppConfiguration
// This profile disabled csrf for testing, and sets some env variables
@ActiveProfiles("integration-test")
@Transactional
public class ParentObjectControllerTest {
@Autowired
private WebApplicationContext context;
private MockMvc mockMvc;
@Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.apply(springSecurity())
.build();
}
// This test PASSES
@Test
@WithMockUser(roles = {"MY_APP_ADMIN"}, username = TEST_USER)
@Sql(scripts = "/db-scripts/bootstrap.sql")
public void testPostParentObjectWithChildObject() {
final ChildObject childObject = new ChildObject();
// set some properties on childObject that don't relate to ParentObject
final ParentObject parentObject = new ParentObject();
// set some properties on parentObject that don't relate to ChildObject
parentObject.setChildObject(childObject);
final ParentObject result = given().mockMvc(mockMvc).contentType(ContentType.JSON)
.and().body(item).log().all()
.when().post("/parent-objects")
.then().log().all().statusCode(201).contentType(ContentType.JSON)
.and().body(matchesJsonSchemaInClasspath("json-schemas/parent-object.json"))
.and().body("username", equalTo(TEST_USER))
.extract().as(ParentObject.class);
assertThat(result.getId(), is(notNullValue()));
assertThat(result.getChildObject().getParentObjectId(), is(result.getId()));
}
// This test FAILS with the 'attempted to assign id from null one-to-one property' error
@Test
@WithMockUser(roles = {"MY_APP_ADMIN"}, username = TEST_USER)
// Inserts a ParentObject record with ID -1
@Sql(scripts = "/db-scripts/bootstrap.sql")
public void testPutParentObjectWithChildObject() {
final ChildObject childObject = new ChildObject();
// set some properties on childObject that don't relate to ParentObject
final Long EXISTING_ID = -1L;
final ParentObject parentObject = new ParentObject();
parentObject.setId(EXISTING_ID);
parentObject.setChildObject(childObject);
final ParentObject result = given().mockMvc(mockMvc).contentType(ContentType.JSON)
.and().body(item).log().all()
.when().put("/parent-objects/{parentObjectId}", parentObject.getId()) //line 260
.then().log().all().statusCode(200)
.extract().as(ParentObject.class);
assertThat(result.getId(), is(EXISTING_ID));
assertThat(result.getChildObject().getParentObjectId(), is(EXISTING_ID));
}
提前感谢大家的建议和帮助!
我认为这是一个bug,但我仍然感兴趣的变通办法,如果有人有他们。我最初在hibernate上发现了一个似乎与问题相符的bug,但它被注册为只影响5.2系列,并被标记为“已修复”,由于我们的项目使用的是5.3系列,所以我继续了。但是,从spring方面深入研究提交的bug,一条面包屑的线索将我引向了这个5.3系列的bug:https://hibernate.atlassian.net/browse/hhh-13413,它链接回了我最初发现的5.2系列bug,与5.3的文章相反,它似乎暗示了这从5.2系列开始就一直存在问题,并且在5.3系列中从来不应该起作用,因为不仅5.3系列的bug被标记为5.2系列bug的重复,当我仔细查看5.2 bug时,它声明它的修复版本直到5.4:https://hibernate.atlassian.net/browse/hhh-12436
所以我会试着降级到上一个5.2系列,然后升级到5.4系列...我只是不确定这两种方法将如何使用spring data jpa的其余功能,这本身可能是一个大问题。
更新:除了因为我们使用Java11(https://hibernate.atlassian.net/browse/hhh-12924->I had to use javassist:3.23.0-ga to get hibernate-core:5.2.13.final to work)而遇到问题之外,降级成功地使一对一映射再次工作。所有其他测试也都通过了。但是,我还没有对这个解决方案进行过广泛的测试,因为我更喜欢基于升级的解决方案。
更新2:能够升级到Spring Boot2.2.0(它使用Hibernate5.4,这是一对一映射的特殊bug被修复的地方)!它需要对我的序列进行一些更改,但升级并不是太痛苦;甚至不需要使用降级标志!如果您的映射问题没有得到解决,那么就会有一个“使用5.2行为”标志,因为他们仍然在解决各种映射场景的矛盾。有关5.4迁移笔记的详细信息,请访问:https://github.com/hibernate/hibernate-orm/blob/61cddad76d5bba951805fa7ed90cc149d404841c/migration-guide.adoc
去年我在做一个项目,导出和导入都很好,但最近我决定导入我的sql文件,由于每个表中都有很多错误,我无法导入。 一旦我停止工作,我就删除了xampp,现在决定再次下载它,但我被困在导入上,这是我的完整文件: http://pastebin.com/mddVUU1i 我的错误如下: 创建表(int(11)Not NULL, varchar(50)Not NULL,datetime Not NULL D
输出给我抛出了这个错误: 我已经尝试按照OWL API示例中的说明进行保存,所以我不知道我的错误在哪里。 这是我用来保存本体的代码: 和getPatient的代码
我正在做一个简单的部分更新场景,它适用于Solr的6.x和7.x版本。将Solr和Solrj升级到8.8后,我遇到以下异常: 注意,这与前面关于stackoverflow的问题不同,因为我传递的是简单的整数字段,而在Solr/Lucene端,它被替换。
运行Firebase upgrade命令后,我尝试在模拟器中运行我的应用程序,出现了以下错误消息: 在调试模式下在 sdk gphone64 x86 64 上启动 lib\main.dart...运行 Gradle 任务 'assembleDebug'... /C:/src/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_core-1.24.
我们正试图在MVC4控制器中的一种操作方法中防止跨站点请求伪造攻击。下面是我们所做的代码更改,它在VS 2013中运行良好,但在VS 2012中抛出错误,与我们在Windows Server 2012-IIS 8中部署时遇到的错误相同。 View.cshtml Controller.cs VS2013-以上代码运行良好 VS2012-引发以下错误 http://schemas.xmlsoap.or
我们正在应用程序中进行更改,将文件扩展名从xls转换为xlsx格式(2007及以上),同时从应用程序中导出文件。 通过升级到POI3.9JAR,我添加了HSSF的XSSF intead,从而进行了必要的代码更改。我们使用的Jar文件的前一个版本是POI3.0。 以下是我在库文件夹中添加的JAR: