2017-02-12 16 views
1

Spring Data JPAに多対一フィールドを保存する際に問題があります。 は、まもなく以下に説明するようにエンティティのユーザーとグループを考えてみましょう:発生したSpringデータUpdate Many To Oneプロパティ

@Entity 
    @Table(name = "Users") 
    public class User { 
     @Basic(optional = false) 
     @Column(name = "username") 
     private String username; 

     @JoinColumn(name = "group_id", referencedColumnName = "id") 
     @ManyToOne 
     private Group group; 
    } 

    @Entity 
    @Table(name = "groups") 
    public class Group { 
     @Basic(optional = false) 
     @Column(name = "name") 
     private String name; 

     @OneToMany(mappedBy = "group",cascade=CascadeType.PERSIST) 
     private Collection<User> userCollection; 
    } 

私は、ユーザーエンティティを更新し、例外以下の方法を保存CrudRepositoryとそのグループを変更したいとき: org.hibernate.HibernateException:のインスタンスの識別子をグループは2から1に変更されました。は、春のデータがグループのidフィールドを編集したいときに表示されます。idの参照を変更したいと思います。更新のための

私はDTO形式で表示データを取得し、後述するように、その後、私はドーザーマッパーを使用してエンティティオブジェクトへのDTOオブジェクトを変換:

DozerBeanMapper mapper = new DozerBeanMapper(); 
// get user by id from database for editing 
User user = this.userService.findByIdAndDeletedFalse(form.getId()); 
// merge view data and entity data using Dozer 
mapper.map(form, user); 
// save User entity 
this.userService.save(user); 

UserServiceのが唯一の方法を保存crudRepositoryを呼び出すBeanです。

解決策はありますか?あなたはJPAで許可されていない追跡エンティティのidを変更しようとしているため

おかげ

+0

ユーザーとグループが同じテーブルを共有するのは正しいですか? – al27091

+0

更新コードを含めてください。 – Naros

+0

親愛なるal27091間違いだった – Farid327

答えて

0

エラーが発生します。新しいGroupへの参照を取得し、それをUser.groupに割り当てる必要があります。これに代え要するに

、:私はあなたが次のXMLを使用してgroupフィールドを除外するDozerを伝えるべきだと思い

user.setGroup(entityManager.getReference(Group.class, newId)); 
+0

ありがとう敬具@crizizis私はそのソリューションの仕事を知っていますが、私はcontorllerでグループをフェッチしたいと思うし、そのビューのデータがマップされ、ユーザーグループの関係を編集する原因を保存するために渡されます。この文章によればあなたには何か提案はありますか? – Farid327

+0

...新しいグループを実際にロードしていない場合、そのようなID(まだ)のグループがどのように分かっていますか? JPAはどのように知っているはずですか?とにかくデータベースとの検証が必要になるでしょう。私は回避策はないと思う。 'EntityManager。getReference'は 'Group'エンティティのすべてのフィールドをロードしません**。それはidだけをロードします(これは 'find'と' getReference'の違いです)。 – crizzis

+0

また、コントローラに 'Group'をロードしてはいけません。あなたは、トランザクションのコンテキスト内で、あなたのサービスメソッドでそれをロードする必要があります – crizzis

0

user.getGroup().setId(newId); 

はこれを試してみてください。

<field-exclude> 
    <a>group</a> 
</field-exclude> 

そして、手動でgroupを設定します。

mapper.map(form, user); 
user.setGroup(this.groupService.finfById(form.group.getId())); 
// save User entity 
this.userService.save(user); 

コントローラでグループをマッピングしたくない場合は、 groupオブジェクトをフェッチしてそこに設定することができるDozerConverterクラスを使用できます。

<mapping> 
    <class-a>org.mypackage.Form</class-a> 
    <class-b>org.mypackage.User</class-b>  
    <field custom-converter-id="org.mypackage.UserGroupCustomConverter"> 
    <a>groupId</a> 
    <b>group</b> 
    </field> 
</mapping> 

public class UserGroupCustomConverter extends DozerConverter<Form, User> { 

    public NewDozerConverter() { 
    super(Form.class, User.class); 
    } 

    public Boolean convertTo(Form form, User user) { 
    user.setGroup(this.groupService.finfById(form.group.getId())); 
    } 
} 
+0

ありがとうMr @alayor私はcontorllerでグループをフェッチしたいと思います。そのビューのデータがマップされ、ユーザーグループの関係を編集する原因を保存する必要があります。この文章によればあなたには何か提案はありますか? – Farid327