web-dev-qa-db-ja.com

JPA多対1関係-IDのみを保存する必要がある

ドライバーと車の2つのクラスがあります。車のテーブルは別のプロセスで更新されます。必要なのは、ドライバーのプロパティを使用して、完全な車の説明を読み取り、既存の車を指すIDのみを書き込むことです。次に例を示します。

@Entity(name = "DRIVER")
public class Driver {
... ID and other properties for Driver goes here .....

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name = "CAR_ID")
    private Car car;

    @JsonView({Views.Full.class})
    public Car getCar() {
      return car;
    }
    @JsonView({Views.Short.class})
    public long getCarId() {
      return car.getId();
    }
    public void setCarId(long carId) {
      this.car = new Car (carId);
    }

}

Carオブジェクトは、Driverへの後方参照のない、単なる典型的なJPAオブジェクトです。

つまり、これによって達成しようとしていたことは、1)詳細なJSONビューを使用して完全な車の説明を読み取ることができる2)または、短いJsonViewで車のIDのみを読み取ることができる3)最も重要なのは、新しいドライバーを作成するときに車のJSON IDを渡します。この方法では、永続化中にCarの不要な読み取りを行う必要はなく、IDを更新するだけです。

次のエラーが発生しました:「オブジェクトは保存されていない一時インスタンスを参照しています-フラッシュする前に一時インスタンスを保存してください:com.Driver.car-> com.Car」

私はDBで車のインスタンスを更新したくありませんが、ドライバーから参照するだけです。私が望むものを達成する方法はありますか?

ありがとうございました。

更新:ドライバーの作成中に渡す車のIDが、DB内の既存の車の有効なIDであることを言及するのを忘れていました。

21
Andrei V

そのエラーメッセージは、明示的に永続化されていない一時的なインスタンスがオブジェクトグラフにあることを意味します。 JPAでオブジェクトが持つことができるステータスの簡単な要約:

  • 一時的:データベースにまだ格納されていない(したがって、entitymanagerには認識されていない)新しいオブジェクトIDが設定されていません。
  • Managed:entitymanagerが追跡するオブジェクト。管理対象オブジェクトは、トランザクションのスコープ内で操作するものであり、管理対象オブジェクトに対して行われたすべての変更は、トランザクションがコミットされると自動的に保存されます。
  • Detached:トランザクションのコミット後も到達可能な以前に管理されていたオブジェクト。 (トランザクション外の管理対象オブジェクト。)IDが設定されています。

エラーメッセージが伝えているのは、操作している(管理/切り離された)Driver-objectが、Hibernateにとって不明な(一時的な)Carオブジェクトへの参照を保持しているということです。保存しようとしているドライバーから参照されている保存されていないCarのインスタンスも保存する必要があることをHibernateに理解させるには、EntityManagerのpersist-methodを呼び出すことができます。

別の方法として、持続をカスケードに追加することもできます(私は、頭の真上から、テストしていないと思います)。ドライバーを持続する前に、自動車で持続を実行します。

@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.PERSIST)
@JoinColumn(name = "CAR_ID")
private Car car;

Entitymanagerのmergeメソッドを使用してドライバーを格納する場合は、代わりにCascadeType.MERGEを追加するか、またはその両方を行う必要があります。

@ManyToOne(fetch=FetchType.LAZY, cascade={ CascadeType.PERSIST, CascadeType.MERGE })
@JoinColumn(name = "CAR_ID")
private Car car;
6
Tobb

これは、getReferenceEntityManager呼び出しを介して実行できます。

EntityManager em = ...;
Car car = em.getReference(Car.class, carId);

Driver driver = ...;
driver.setCar(car);
em.persist(driver);

これはデータベースからSELECTステートメントを実行しません。

17
scetix

Okutaneへの回答として、スニペットを参照してください。

@JoinColumn(name = "car_id", insertable = false, updatable = false)
@ManyToOne(targetEntity = Car, fetch = FetchType.EAGER)
private Car car;

@Column(name = "car_id")
private Long carId;

したがって、ここで何が発生するかというと、挿入/更新を行う場合、carIdフィールドに値を入力して挿入/更新を実行するだけです。 carフィールドは挿入不可で更新不可なので、Hibernateはこれについて文句を言わず、データベースモデルでは外部キーとしてcar_idのみを設定するので、この時点でこれで十分です(データベース上の外部キーの関係はデータの整合性を確保してください)。エンティティをフェッチすると、carフィールドがHibernateによって入力され、必要なときに親だけがフェッチされる柔軟性が得られます。

8

次のようにcar IDでのみ作業できます。

@JoinColumn(name = "car")
@ManyToOne(targetEntity = Car.class, fetch = FetchType.LAZY)
@NotNull(message = "Car not set")
@JsonIgnore
private Car car;

@Column(name = "car", insertable = false, updatable = false)
private Long carId;
5
Radu Gancea
public void setCarId(long carId) {
      this.car = new Car (carId);
    }

実際にはcarの保存バージョンではありません。つまり、idがないため、これは一時オブジェクトです。 JPAは、関係に注意する必要があると要求しています。エンティティが新しい(コンテキストで管理されていない)場合は、他の管理対象オブジェクトまたはデタッチされたオブジェクトと関連付ける前に保存する必要があります(実際には、MASTERエンティティはカスケードを使用してその子を維持できます)。

2つの方法cascadesまたはsave&retrievalfromデシベル。

また、エンティティID手動の設定は避けてください。 車を更新/永続化しない場合 MASTERエンティティの場合、データベースからCARを取得し、driverそれはインスタンスです。したがって、これを行うと、Carは永続化コンテキストから切り離されますが、IDがあり、影響を受けることなく任意のエンティティに関連付けることができます。

3
00Enthusiast

次のようにオプションのフィールドをfalseに追加します

@ManyToOne(optional = false) // Telling hibernate trust me (As a trusted developer in this project) when building the query that the id provided to this entity is exists in database thus build the insert/update query right away without pre-checks
private Car car; 

そうすれば、車のIDを次のように設定できます

driver.setCar(new Car(1));

そして、通常のドライバを永続化します

driverRepo.save(driver);

ID 1の車がデータベースのドライバーに完全に割り当てられていることがわかります

説明:

それで、この小さなoptional=falseこれはより役立つかもしれません https://stackoverflow.com/a/17987718

0
Youans