【问题标题】:How to delete Hibernate @Embeddables containing nullable fields?如何删除包含可为空字段的 Hibernate @Embeddables?
【发布时间】:2011-05-13 21:05:27
【问题描述】:

删除@Embeddable 对象时,我遇到了一些问题。

我有以下域类:SwitchVoipTrunkGroup 和 PrioritizedCodec。后者包含几个可以为空的字段。

class SwitchVoipTrunkGroup {

    //...

    @CollectionOfElements(fetch = FetchType.LAZY)
    @JoinTable(
            name = "SWITCH_VOIP_TKG_CODEC",
            joinColumns = @JoinColumn(name = "FK_SWITCH_VOIP_TKG_ID")
    )
    @ForeignKey(name = "FK_CODEC_SWITCH_VOIP_TKG")
    private Set<PrioritizedCodec> prioritizedCodecs = new HashSet<PrioritizedCodec>();

    //...
}

@Embeddable
public class PrioritizedCodec {

    @Column(name = "PRIORITY")
    private String priority;

    @Column(name = "FAX_MODE")
    private String faxMode;

    //... some more columns ...
}

当我编辑 SwitchVoipTrunkGroup 的 prioritydCodecs 字段(例如,通过删除条目)并保存实体时,我在 Hibernate 日志记录中看到以下内容:

13:54:31,919 INFO  [STDOUT] Hibernate: delete from T_SWITCH_VOIP_TKG_CODEC where 
fk_switch_voip_tkg_id=? and fax_mode=? and priority=?

来自this question 我明白为什么Hibernate 使用where 子句中的所有字段。但是,这会带来问题:如果其中一些字段为空,则查询将如下所示:

delete from T_SWITCH_VOIP_TKG_CODEC where fk_switch_voip_tkg_id=1 and fax_mode = '' 
and priority =''

然而,这不会删除任何记录,因为 Hibernate 真正需要的是检查空字符串的 NULL iso。例如:

delete from T_SWITCH_VOIP_TKG_CODEC where fk_switch_voip_tkg_id=1 and fax_mode
IS NULL and priority IS NULL

(请参阅here,了解为什么检查空字符串还不够)

关于如何解决这个问题的任何想法?非常感谢!

【问题讨论】:

  • 在执行删除操作之前,您是否有理由无法在您的实体中将这些属性的值设置为 null?
  • 它们为 null 的事实正是问题所在,因为这使得 Hibernate 在 where 子句中检查空字符串。
  • 事情是,@Embeddable 对象的概念是它们的生命周期与其父对象的生命周期相关联——删除它们而不删除它们的父对象似乎是错误的。

标签: java hibernate jpa


【解决方案1】:

我建议规范化你的数据库,让你的两个类都成为实体,然后设置 SwitchVoipTrunkGroup 和 PrioritizedCodec 之间的一对多关系,然后你可以设置级联规则,以便 Hibernate 自动更新 PrioritizedCodec 类型的元素集合,当你坚持 SwitchVoipTrungGroup 的实例。

@Entity
class SwitchVoipTrunkGroup {

    //...

    @OneToMany(cascade = {CascadeType.MERGE, CascadeType.PERSIST}, orphanRemoval = true)
    @JoinColumn(name = "switchVoipTrunkGroup_id")
    @ForeignKey(name = "FK_PrioritizedCodec_SwitchVoipTrunkGroup")
    private Set<PrioritizedCodec> prioritizedCodecs = new HashSet<PrioritizedCodec>();

    //...
}

@Entity
public class PrioritizedCodec {

        @Column(name = "PRIORITY")
        private String priority;

        @Column(name = "FAX_MODE")
        private String faxMode;

        //... some more columns ...
    }

@Serice("someService")
public class SomeService  {

     @Autowired 
     private SwitchVoipTrunkGroupDao trunkDao;

     public SwitchVoipTrunkGroup doOperation("criteria") {
         SwitchVoipTrunkGroup tg = trunkDao.find("criteroa");
         tg.getPrioritizedCodecs().[remove(2)]; //remove should be implemened, that is just lame statement
         tg.getPrioritizedCodecs().get(5).setFaxMod("ENABLED");
         return trunkDao.save(tg); //hibernate will remove missing elements from PrioritizedCodec table, and will update necessary entities.
    }
}

或者,您可以通过@Column 注释的属性为priority 和faxMode 字段指定默认值并强制为空约束

@Column(columnDefinition = "VARCHAR(20) default 'NONE'", nullable = false)
private String faxMode;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-16
    • 2011-07-12
    • 2014-10-06
    • 2021-03-31
    相关资源
    最近更新 更多