【问题标题】:Hibernate update call generates new row in @OneToOne mappingHibernate 更新调用在 @OneToOne 映射中生成新行
【发布时间】:2021-08-05 18:25:36
【问题描述】:

所以我的包中有以下类

类存储数据:

@Data
@Entity
@ToString
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode
@Table(name = "data")
@Builder
public class StoredData {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id", unique = true, nullable = false, updatable = false)
private long id;

@Column(name = "data_id", nullable = false)
private String dataId;

@OneToOne(mappedBy = "data", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private StoredSource source;
}

类存储源:

@Data
@Entity
@EqualsAndHashCode(exclude = {"id","data"})
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "source_type")
@Table(name = "source")
public abstract class StoredSource {
 
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private long id;

@Enumerated(EnumType.STRING)
@Column(name = "source_type", insertable = false, updatable = false)
private SourceType sourceType;

@OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JoinColumn(name = "data_id", referencedColumnName = "id", nullable = false)
private StoredData data;

}

现在还有 2 个类扩展了 StoredSource 类:

@Data
@Entity
@ToString
@EqualsAndHashCode(callSuper = true)
@DiscriminatorValue(SourceType.ADS_TEXT)
public class StoredAdSource extends StoredSource {

@Column(name = "ad_id")
private String adId;
 
}

@Data
@Entity
@ToString
@EqualsAndHashCode(callSuper = true)
@DiscriminatorValue(SourceType.OFFERS_TEXT)
public class StoredOfferSource extends StoredSource {

@Column(name = "offer_id")
private String offerId;

}

所以现在我的数据库中的源表中已经有一个条目:

source_type id ad_id data_id
ADS 1 Ads12 1

但是当我尝试对 storedData 对象进行更新时:

StoredData storedData = getEntryFromDb();    
storedData.setSource(newData.getSource());
storedData.getSource().setData(storedData);
where newData is a StoredData type of object and only the ad_id of its source is changed to Ads1234.

Hibernate 生成新行如下

source_type id ad_id data_id
ADS 1 Ads12 1
ADS 2 Ads1234 1

我无法弄清楚为什么会这样。是因为 StoredSource 是一个抽象类吗?请帮帮我。

【问题讨论】:

  • 您是否需要StoredSource 中的StoredData 和StoredData 中的StoredSource 映射?你能删除其中一个吗?如果这不可能,请尝试从 StoredSource 的 StoredData 成员中删除 cascade = CascadeType.ALL。
  • 是的,我需要两个映射。我也尝试删除 cascade = CascadeType.ALL 但仍然是同样的问题。

标签: java hibernate jpa hibernate-mapping


【解决方案1】:

我不确定我是否完全理解了确切的问题,如果我有错误,请纠正我。


初始情况: Data 1 Ad 1

更新后的预期情况: Data 1 Ad 2(具有不同属性等的新 StoredAdSource)

在这种情况下,您需要确保旧的 Ad 1Data 1 实体断开连接(否则结果将是您上面显示的表格状态,有多个 StoredSource 引用到同一个data_id fk。

由于您不允许 StoredSource 实体没有关联的 Data(不可为空),因此您可以例如使用orphanRemoval=true 自动删除未连接StoredSource 的实体Data

    @OneToOne(mappedBy = "data", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
    private StoredSource source;

如果您只是想修改现有的 Ad 1(例如更改某些属性),请确保您正在修改 JPA 管理的实例,而不是意外地以某种方式创建一个新实例。

例如:

    var data1 = dataRepository.findById(1).get();
    if (data1.getSource() instanceof StoredAdSource) {
        ad1 = (StoredAdSource) data1.getSource(); // JPA instantiated the correct sub-class
        // ad1.setAdId(newAdIdValue); // ...
    }
    dataRepository.saveAndFlush(data1); // cascades save

(我希望这有助于避免您的问题,请随时查看the sample I tested with。)

【讨论】:

    猜你喜欢
    • 2020-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-26
    相关资源
    最近更新 更多