我有一个Spring4应用程序,试图从数据库中删除实体的实例。我拥有以下实体:
@实体
公共类令牌实现可序列化{
@身份证
@SequenceGenerator(name=“seqToken”,sequenceName=“SEQ_TOKEN”,initialValue=500,allocationSize=1)
@GeneratedValue(策略=GenerationType.SEQUENCE,generator=“seqToken”)
@列(name=“TOKEN\u ID”,null=false,精度=19,刻度=0)
私人长id;
@NotNull
@列(name=“VALUE”,unique=true)
私有字符串值;
@manytone(fetch=FetchType.EAGER)
@JoinColumn(name=“USER\u ACCOUNT\u ID”,null=false)
私人用户帐户;
@时态(TemporalType.TIMESTAMP)
@列(name=“EXPIRES”,长度=11)
非公开日期到期;
...
//getter和setter省略以保持简单
}
我定义了一个JpaRepository接口:
公共接口令牌存储库扩展了JpaRepository<;令牌,长>;{
令牌findByValue(@Param(“value”)字符串值);
}
我有一个与内存数据库(H2)一起工作的单元测试设置,我正在用两个令牌预填充数据库:
@测试
public void testDeleteToken(){
资产(tokenRepository.findAll().size(),为(2));
Token deleted=tokenRepository.findOne(1L);
tokenRepository.delete(已删除);
tokenRepository.flush();
断言(tokenRepository.findAll().size()为(1));
}
第一个断言通过,第二个断言失败。我尝试了另一个测试,更改令牌值并将其保存到数据库中,它确实起作用,所以我不确定为什么delete不起作用。它也不会抛出任何异常,只是不会将其持久化到数据库中。它对我的oracle数据库也不起作用
编辑
还有这个问题。通过将以下内容添加到我的TokenRepository界面,我能够将删除持久化到数据库:
修改
@查询(“从令牌t中删除,其中t.id=?1”)
作废删除(长entityId);
然而,这不是一个理想的解决方案。如果没有这个额外的方法,我需要做些什么来让它工作呢
这种行为最有可能发生在您具有双向关系,并且在保持父级和子级(连接到当前会话)的同时没有同步双方的情况下
这很棘手,我将用下面的例子来解释
@实体
公共类父类{
@身份证
@生成值(策略=标识)
@列(name=“id”,unique=true,nullable=false)
私人长id;
@OneToMany(cascade=CascadeType.PERSIST,mappedBy=“parent”)
私有集<;Child>;children=新哈希集<;>;(0);
公共无效集合子对象(集合子对象){
这个。孩子=孩子;
this.children.forEach(child->;child.setParent(this));
}
}
@实体
公营儿童{
@身份证
@生成值(策略=标识)
@列(name=“id”,unique=true,nullable=false)
私人长id;
@许多酮
@JoinColumn(name=“parent\u id”)
私人家长;
公共void setParent(父级){
this.parent=parent;
}
}
让我们编写一个测试(一个事务测试)
公共类ParentTest扩展了IntegrationTestSpec{
@自动连线
私有父存储库父存储库;
@自动连线
私人儿童知识库;
@自动连线
私人亲子关系;
@试验
公开无效测试(){
父项=新父项();
子项=新子项();
父集合子集合(子集合);
parentRepository.save(父级);
Child fetchedChild=childRepository.findAll().get(0);
childRepository.delete(fetchedChild);
assertEquals(1,parentRepository.count());
assertEquals(0,childRepository.count());//失败!!!childRepository.counts()返回1
}
}
非常简单的测试,对吗?我们正在创建父级和子级,将其保存到数据库中,然后从数据库中获取一个子级,将其删除,最后确保一切正常工作。事实并非如此
此处的删除不起作用,因为我们没有同步关系的另一部分,该部分在当前会话中保持不变。如果家长未与当前会话关联,我们的测试将通过,即
@组件
公共类亲子关系{
...
@事务性(传播=传播。需要\u新建)
public void theresparenttwithchildren(){
父项=新父项();
子项=新子项();
父集合子集合(子集合);
parentRepository.save(父级);
}
}
及
@测试
公开无效测试(){
parentFixture.TheResparentWithChildren();//我们正在单独的事务中保存子级和父级
Child fetchedChild=childRepository.findAll().get(0);
childRepository.delete(fetchedChild);
assertEquals(1,parentRepository.count());
assertEquals(0,childRepository.count());//有效!
}
当然,OP只是解释了我的行为。正确的方法显然是保持关系的两部分同步,这意味着:
类父类{
...
公共无效解除子对象(子对象){
这个。儿童。移除(儿童);
}
公屋子女{
this.children.forEach(child->;child.dismissParent());//同步关系的另一端
这个.children.clear();
}
}
班童{
...
public void dismissParent(){
this.parent.dismissChild(this);//同步关系的另一端
this.parent=null;
}
}
显然这里可以使用@PreRemove