持続した後、春データ-JPAは、リンクされたエンティティのすべてのパラメータをクリア

geoffreydv:

私は2つの実体を保存する(Hibernateで)JPAを使用しようとしています。春のデータは、インタフェースを提供しているが、私はそれがここで問題ないと思います。

私は「モデル」と呼ばれる主なエンティティを持っています。このモデルは、多くの「パラメータ」のエンティティがリンクされています。私はモデルとそのパラメータを保存する方法を書いています。

これはメソッドです。

  private void cascadeSave(Model model) {

    modelRepository.save(model);

    for (ParameterValue value : model.getParameterValues()) {
        parameterValueRepository.save(value);
    }
}

これが問題です:

私はそのモデルをロードする前に既に存在し、それにいくつかの新しいパラメータを追加し、それらの両方を保存するには、このメソッドを呼び出して、奇妙な何かが起こります。

(modelRepository.save)を保存する前にまずこれをデバッグするときのようなものを、モデルのデータルックスです。

ここでは、画像の説明を入力します。

値(名称及びモデルが充填されている)に充填してモデルは、2つのパラメータを有しています。

さて、私の方法で保存した最初のモデルを保存した後、これが発生します。Hibernateは不思議な何かをやって、代わりに一人でそれらを残しての値を再作成しておく必要がありますので、オブジェクト参照が異なるものであることに注意してください:

ここでは、画像の説明を入力します。

何らかの理由で休止状態は、セット内のパラメータのすべての属性をクリア。

新しいパラメータの保存は、次のコードで発生したときに今では、などの理由NOT NULL制約の失敗します

私の質問:なぜ休止状態のすべてのフィールドをクリアしていますか?

ここでは、関連するマッピングは、次のとおりです。

ParameterValue

@Entity
@Table(name = "tbl_parameter_value")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "PARAMETER_TYPE")
public abstract class ParameterValue extends AbstractBaseObject {

    @Column(nullable = false)
    @NotBlank
    private String name;
    private String stringValue;
    private Double doubleValue;
    private Integer intValue;
    private Boolean booleanValue;
    @Enumerated(EnumType.STRING)
    private ModelType modelParameterType;
    @Column(precision = 7, scale = 6)
    private BigDecimal bigDecimalValue;
    @Lob
    private byte[] blobValue;

    ParameterValue() {
    }

    ParameterValue(String name) {
        this.name = name;
    }

モデルのパラメータ値

@Entity
@DiscriminatorValue(value = "MODEL")
public class ModelParameterValue extends ParameterValue {

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "model_id", foreignKey = @ForeignKey(name = "FK_VALUE_MODEL"))
    private Model model;

    ModelParameterValue() {
        super();
    }

    ModelParameterValue(String name) {
        super(name);
    }

モデル

@Entity
@Table(name = "tbl_model")
public class Model extends AbstractBaseObject implements Auditable {

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "model")
    private Set<ModelParameterValue> parameterValues = new HashSet<>();

EDIT

私は、最小限の例でこれを再現することができました。あなたはすべての春のデータを交換する場合、これは(EMはJPAのEntityManagerで)ボンネットの下に何が起こったのかですありません。

public Model simpleTest() {

    Model model = new Model("My Test Model");
    em.persist(model);

    model.addParameter(new Parameter("Param 1"));
    em.merge(model);

    for (Parameter child : model.getParameters()) {
        em.persist(child);
    }

    return model;
}

When the merge is executed, all of the attributes of the parameters are set to null. They are actually just replaced with completely new parameters.

Emil Hotkowski :

I guess you are using Spring Data Jpa as your modelRepository. This indicates following consequences.

Spring Repository Save

S save(S entity)

Saves a given entity. Use the returned instance for further operations as the save operation might have changed the entity instance completely.

So it is normal behaviour which you had encountered.

Code should be changed to :

model = modelRepository.save(model);

for (ParameterValue value : model.getParameterValues()) {
    parameterValueRepository.save(value);
}

EDIT:

I think that your saving function is broken in sense, that you do it backwards. Either you can use CascadeType on your relation or you have to save children first.

Cascade

Cascade works like that "If you save Parent, save Children, if you update Parent, update Children ..."

だから我々はそのようなあなたの関係にカスケードを置くことができます。

@Entity
@Table(name = "tbl_model")
public class Model extends AbstractBaseObject implements Auditable {

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "model", cascade = CascadeType.ALL)
    private Set<ModelParameterValue> parameterValues = new HashSet<>();

その後、これだけのように保存

  private void cascadeSave(Model model) {

    modelRepository.save(model);
    //ParamValues will be saved/updated automaticlly if your model has changed

}

ボトムアップのセーブ

2番目のオプションは、単に最初のparamsを保存し、それらをモデル化することです。

  private void cascadeSave(Model model) {

    model.setParameterValues(
      model.getParameterValues().stream()
       .map(param ->  parameterValueRepository.save(param))
       .collect(Collectors.toSet())
   );
    modelRepository.save(model);
}

私は自分のコンパイラで第二のコードをチェックしていませんが、考え方は、モデル保存しモデルにそれを入れて、子供(ParamValues)のセーブ最初に次のとおりです。)

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=203057&siteId=1