web-dev-qa-db-ja.com

JPA Hibernateを使用して子オブジェクトを自動的に保存する

親テーブルと子テーブルの間には1対多の関係があります。親オブジェクトには、

List<Child> setChildren(List<Child> childs)

Childテーブルにも外部キーがあります。この外部キーは、データベースの親行を参照するIDです。したがって、私のデータベース構成では、この外部キーをNULLにすることはできません。また、この外部キーは親テーブルの主キーです。

だから私の質問は、次のようなことをして子供のオブジェクトを自動的に保存する方法です:

session.save(parent);

上記を試しましたが、Childテーブルの外部キーフィールドをNULLにすることはできないという文句をデータベースエラーが表示されます。 JPAにこの外部キーを自動的にChildオブジェクトに設定して、子オブジェクトを自動的に保存できるようにする方法はありますか?

前もって感謝します。

62
Marquinio

上記を試しましたが、Childテーブルの外部キーフィールドをNULLにすることはできないという文句をデータベースエラーが表示されます。 JPAにこの外部キーを自動的にChildオブジェクトに設定して、子オブジェクトを自動的に保存できるようにする方法はありますか?

さて、ここには2つのことがあります。

最初に、保存操作をカスケードする必要があります(ただし、これを行っているか、「子」テーブルへの挿入中にFK制約違反が発生しないことを理解しています)

第二に、おそらく双方向の関連付けがあり、「リンクの両側」を正しく設定していないと思います。あなたはこのようなことをすることになっています:

Parent parent = new Parent();
...
Child c1 = new Child();
...
c1.setParent(parent);

List<Child> children = new ArrayList<Child>();
children.add(c1);
parent.setChildren(children);

session.save(parent);

一般的なパターンは、リンク管理方法を使用することです。

@Entity
public class Parent {
    @Id private Long id;

    @OneToMany(mappedBy="parent")
    private List<Child> children = new ArrayList<Child>();

    ...

    protected void setChildren(List<Child> children) {
        this.children = children;
    }

    public void addToChildren(Child child) {
        child.setParent(this);
        this.children.add(child);
    }
}

そして、コードは次のようになります。

Parent parent = new Parent();
...
Child c1 = new Child();
...

parent.addToChild(c1);

session.save(parent);

参照資料

64
Pascal Thivent

Xml/annotationを使用してマッピングのカスケードオプションを設定する必要があると思います。 Hibernateの参照例はこちら を参照してください。

アノテーションを使用している場合は、次のようにする必要があります。

@OneToMany(cascade = CascadeType.PERSIST) // Other options are CascadeType.ALL, CascadeType.UPDATE etc..
27
Adeel Ansari

双方向リレーションの子オブジェクトに親オブジェクトを割り当てる方法は?

1対多というリレーションがあり、親オブジェクトごとに子オブジェクトのセットが存在するとします。双方向の関係では、各子オブジェクトはその親への参照を持ちます。

eg : Each Department will have list of Employees and each Employee is part of some department.This is called Bi directional relations.

これを達成するために、one wayは、親オブジェクトを永続化しながら子オブジェクトに親を割り当てることです

Parent parent = new Parent();
...
Child c1 = new Child();
...
c1.setParent(parent);

List<Child> children = new ArrayList<Child>();
children.add(c1);
parent.setChilds(children);

session.save(parent);

その他の方法は、hibernate Intercepterを使用して実行できます。この方法は、すべてのモデルに対して上記のコードを記述しないようにするのに役立ちます。

Hibernateインターセプターは、DB操作を実行する前に独自の作業を行うためのAPIを提供します。オブジェクトのonSaveと同様に、リフレクションを使用して子オブジェクトに親オブジェクトを割り当てることができます。

public class CustomEntityInterceptor extends EmptyInterceptor {

    @Override
    public boolean onSave(
            final Object entity, final Serializable id, final Object[] state, final String[] propertyNames,
            final Type[] types) {
        if (types != null) {
            for (int i = 0; i < types.length; i++) {
                if (types[i].isCollectionType()) {
                    String propertyName = propertyNames[i];
                    propertyName = propertyName.substring(0, 1).toUpperCase() + propertyName.substring(1);
                    try {
                        Method method = entity.getClass().getMethod("get" + propertyName);
                        List<Object> objectList = (List<Object>) method.invoke(entity);

                        if (objectList != null) {
                            for (Object object : objectList) {
                                String entityName = entity.getClass().getSimpleName();
                                Method eachMethod = object.getClass().getMethod("set" + entityName, entity.getClass());
                                eachMethod.invoke(object, entity);
                            }
                        }

                    } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
        return true;
    }

}

そして、インターセプターを次のように構成に登録できます。

new Configuration().setInterceptor( new CustomEntityInterceptor() );
2
Sunil Kumar

つかいます org.hibernate.annotationsCascadehibernateJPAを一緒に使用すると、子オブジェクトの保存に何らかの不満が生じます。

1
sandhya nayak

次のプログラムは、双方向リレーションが休止状態でどのように機能するかを説明しています。親が子オブジェクトのリストを保存すると、自動保存されます。

      @Entity
      @Table(name="clients")
     public class Clients implements Serializable  {
     @Id
     @GeneratedValue(strategy = GenerationType.IDENTITY)     
     @OneToMany(mappedBy="clients", cascade=CascadeType.ALL)
      List<SmsNumbers> smsNumbers;

    on the parent side
     and put the following annotation on the child side




 @Entity
  @Table(name="smsnumbers")
 public class SmsNumbers implements Serializable {
   @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
   int id;
   String number;
   String status;
 Date reg_date;
 @ManyToOne
 @JoinColumn(name = "client_id")
 private Clients clients;
  and getter setter.





    public static void main(String arr[])
   {
       Session session = HibernateUtil.openSession();
     //getting transaction object from session object
       session.beginTransaction();

        Clients cl=new Clients("Murali", "1010101010");
          SmsNumbers sms1=new SmsNumbers("99999", "Active", cl);
          SmsNumbers sms2=new SmsNumbers("88888", "InActive", cl);
          SmsNumbers sms3=new SmsNumbers("77777", "Active", cl);
          List<SmsNumbers> lstSmsNumbers=new ArrayList<SmsNumbers>();
          lstSmsNumbers.add(sms1);
          lstSmsNumbers.add(sms2);
          lstSmsNumbers.add(sms3);
          cl.setSmsNumbers(lstSmsNumbers);
     session.saveOrUpdate(cl);
     session.getTransaction().commit(); 
    session.close();    
1
shriram

setChildsで、リストをループして、次のようなことを試してみてください。

child.parent = this;

また、親のカスケードを適切な値に設定する必要があります。

0
hvgotcodes

カスケードタイプをallに設定すると、ジョブが実行されます。モデルの例について。このようなコードを追加します。 @OneToMany(mappedBy = "receipt"、cascade = CascadeType.ALL)プライベートリストsaleSet;

0
Dila Gurung