2017-11-16 11 views
0

私はthymeleafとSpringとHibernateを使ってMVCアプリケーションを構築しています。ここでの私の質問は、春より冬眠についてのことです。フォームのサブミットにないエンティティ属性をヌルに更新する

これは私がこれまで行ってきたことです。

A UI

<form role="form" th:action="@{/user/{userId}/official(userId=${userId})}" th:object="${user}" method="post"> 

      <!-- first form group --> 
      <div class="form-group"> 

       <label class="control-label col-xs-2">First Name</label> 
       <div class="col-xs-2"> 
        <input type="text" class="form-control" th:field="*{firstName}" placeholder="First Name" /> 
       </div> 

       <label class="control-label col-xs-2">Last Name</label> 
       <div class="col-xs-3"> 
        <input type="text" class="form-control" th:field="*{lastName}" placeholder="Last Name" /> 


      <!-- first form group end --> 
      </div> 
      <br/><br/> 

      <!-- third form group --> 
       <div class="form-group"> 
        <label class="control-label col-xs-2">Email Address</label> 
        <div class="col-xs-2"> 
         <input type="text" class="form-control" th:field="*{emailAddress}" placeholder="Email Address" /> 
        </div> 

      </div> 

      <div class="form-group"> 
            <div class="col-xs-2"> 
             <input type="submit" value="Update" class="btn btn-primary" /> 
    </form> 

コントローラー:

@Controller 
public class UserController { 

    @Autowired 
    private IUserService userServiceImpl; 

    @RequestMapping(value = "/user/{userId}/official", method = RequestMethod.GET) 
    public String getUserOfficialInfo(@PathVariable("userId") Integer userId, Model model) throws ServiceBusinessException { 

        UserBO userBO = userServiceImpl.findUserByUserId(userId); 
        model.addAttribute("user", userBO); 
        model.addAttribute("userId", userId); 
        model.addAttribute("genders", EnumSet.allOf(Gender.class)); 
        return "official"; 
    } 


    @RequestMapping(value = "/user/{userId}/official", method = RequestMethod.POST) 
    public String updateUserOfficialInfo(@PathVariable("userId") String userId, @ModelAttribute("user") UserBO user,BindingResult result, Model model) throws ServiceBusinessException { 

        userServiceImpl.updateUser(user); 
        UserBO userBO = userServiceImpl.findUserByUserId(Integer.parseInt(userId)); 
        model.addAttribute("user", userBO); 
        model.addAttribute("userId", userId); 
        model.addAttribute("genders", EnumSet.allOf(Gender.class)); 
        return "official"; 
    } 
} 

DAO:

@Override 
    public void updateUser(UserEntity user) throws DaoException { 
     entityManager.merge(user); 
    } 

コントローラでGETメソッドは、ビューにユーザーオブジェクトを取得します。しかし、私はちょうどフォームにユーザーオブジェクトのそれらの属性のいくつかを表示しています。

送信フォームでコントローラのPOSTメソッドが呼び出され、サービスレイヤが呼び出され、DAOのマージメソッドが実行されます。

ここで私が観察したことは、エンティティマネージャのこのマージメソッドが、フォームに存在しない属性をnullに更新していることです。

POSTメソッドから呼び出されたときにオブジェクトがデタッチされるため、これが期待される動作だと思います。したがって、ここで行うべきことは、まずデータベースからエンティティオブジェクトを取得し、そのオブジェクトにフォームで変更されたフィールドを設定してから、マージメソッドを呼び出します。

私が言った以上のことが正しいかどうか知る人もいますか?

もしそうなら、私の次の質問は、これは非常に面倒であり、少し努力するものではありません。つまり、オブジェクト全体をフォームに表示したくない場合があります。また、隠されたフィールドではありません。私はこれを処理する方法がないことは非常に驚いており、毎回上記の方法に従わなければなりません。

これを行うより良い方法はありますか?代わりにJDBCテンプレートを使用するだけでいいですか?そこにボイラープレートのコードを書いていることは分かっていますが、UIへの各回の旅行の際にゲッターとセッターも書いています。

+0

Hibernateはフォームについて何も知りません。私が見た典型的なパターンは、dbからエンティティをロードし、フォームのフィールドをエンティティにマップし、エンティティを永続化することです。私は、これを助けるためにどこかに春の配管があると信じていますが、私はそれを見つけるべき具体的なものを思い出すことはできません。 – Taylor

答えて

1

エンティティにorg.hibernate.annotations.Entityと注釈を付けることを検討してください。

@Entity 
@Table(name = "user") 
@org.hibernate.annotations.Entity(
     dynamicInsert = true, dynamicUpdate=true 
) 
public class User implements java.io.Serializable { 
// your properties 
} 

あなたが休止状態の4.xのバージョンを使用している場合は、@org.hibernate.annotations.Entityの使用は、最近廃止されましたので、代わりに@DynamicUpdateを使用することもできます。

参考文献:

https://www.mkyong.com/hibernate/hibernate-dynamic-update-attribute-example/ https://docs.jboss.org/hibernate/orm/4.2/javadocs/org/hibernate/annotations/Entity.html https://docs.jboss.org/hibernate/orm/4.2/javadocs/org/hibernate/annotations/DynamicInsert.html https://docs.jboss.org/hibernate/orm/4.2/javadocs/org/hibernate/annotations/DynamicUpdate.html

+0

これを試してみましょうこのような問題は、このように見えます。 – user641887

0

あなたはutilのクラスに次のコードを入れて、あなたは別の参照オブジェクトに基づいてオブジェクトを塗りつぶすしたいときにそれを呼び出すことができます。

public static <T> void fillNotNullFields(T reference, T source) { 
     try { 
      Arrays.asList(Introspector.getBeanInfo(reference.getClass(), Object.class) 
        .getPropertyDescriptors()) 
        .stream() 
        .filter(pd -> Objects.nonNull(pd.getReadMethod())) 
        .forEach(pd -> { 
         try { 
          Object value = pd.getReadMethod().invoke(source); 
          if (value != null) 
           pd.getWriteMethod().invoke(reference, value); 

         } catch (Exception e) { 
          e.printStackTrace(); 
         } 
        }); 
     } catch (IntrospectionException e) { 
      e.printStackTrace(); 
     } 
    } 

だから、あなたはサービスでこれを行うことができます。

public UserBO updateUser(String userId, UserBO user) { 
        UserBO reference = findOne(Integer.parseInt(userId)); 
        fillNotNullFields(reference, user); 
        return updateUser(reference); 
    } 

この回答の回答はhereです。それが役に立てば幸い。

+0

はい、それはポイントではありませんが、ポイントは、これが休止状態の予想される動作であれば、私は他の人々がこれをどのように処理しているか知りたいと思いますか?この場合に期待される動作ではない場合はどうすればよいでしょうか? – user641887

+0

@ user641887この場合、私は実際にはわかりません。私は、DTOデザインパターンを使用して穏やかなWebサービスでのみ休止状態での使用経験があり、この問題はrestアプローチとは関係ありません。実際には休息状態では、ビューレイヤーからオブジェクトを直接持続させることはできません。 –

0

フォームがコントローラに送信されたときに再マッピングされるように、非表示のフィールドに不要なBeanプロパティを格納する必要があります。たとえば、生年月日が既にユーザーの属性であると仮定して、ページに生年月日を表示したくない場合は、フォーム内に次のタグを追加するだけです。

<input type='hidden' th:field="*{dateOfBirth}" /> 
+0

私はそれを正確にやりたいとは思わないが、複数の属性を持っているユーザーのために、私がフォーム内に持っているものよりもはるかに多くのことがある。それは完全に冗長になるだろう。 – user641887

+0

これは、ほとんどのフレームワーク(Grailsなど)でよく使われる戦略です。複数の隠しフィールドを置くのを避けたいのであれば、動的な挿入物を調べたいかもしれません。 https://www.mkyong.com/hibernate/hibernate-dynamic-insert-attribute-example/ –

+0

ですが、私は既存のレコードの更新操作です。挿入しない – user641887

関連する問題