LoginSignup
2
2

More than 5 years have passed since last update.

Ebeanで特定項目をnullに更新

Last updated at Posted at 2015-06-26

Ebeanのデフォルトの動きでは、nullがセットされている値はupdateの対象にはならないです。
通常はそれを踏まえて、主キーと更新したいプロパティの値をセットしてsaveメソッドするという使い方です。

場合によっては、DBの値をnullにセットしたいこともあります。
Ebean#updateメソッドには、第二引数にSetをとるものがあります。これはSetにあるプロパティのみ更新の対象とし、nullへの上書きもできます。

あらかじめ、nullに更新したいプロパティのSetを作成し、それとBeanでnon-nullの値をもつプロパティのSetを合わせたものを渡すことで、特定項目はnullにできる更新になります。

それの結果が下記です。

     try {
            Ebean.update(bean, getUpdateProperties(bean));
            Ebean.refresh(bean)
        } catch (Exception e) {
            logger.error("update failed.", e);
        }

        logger.debug("END update");
    }

    /**
     * null更新可能なプロパティ名のセット.
     */
    private final static HashSet<String> NULLABLE_PROPERTIES =
            Sets.newHashSet(
                    "passwordExpirationDate",
                    "tokenExpirationDate"   
                    );

    /**
     * 値を持つか、null更新可能なプロパティ名のセットを取得.
     * @param bean
     * @return
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     * @throws NoSuchMethodException
     */
    private Set<String> getUpdateProperties(Object bean) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        Map<String,String> beanMap = BeanUtils.describe(bean);

        Predicate<Map.Entry<String,String>> hasNotNullValueOrIsNullableKey = new Predicate<Map.Entry<String,String>>(){
            public boolean apply(Map.Entry<String, String> entry) {
                return (entry.getValue() != null) || NULLABLE_PROPERTIES.contains(entry.getKey());
            }
        };
        Map<String,String> filteredMap = Maps.filterEntries(beanMap, hasNotNullValueOrIsNullableKey);

        return filteredMap.keySet();
    }

non-nullなプロパティを求めるのに、commons-beanのBeanUtils#describeを使ってみました。MapのフィルタリングはGuavaを利用しています。

問題点

Ebean#updateのあとにEbean#refreshをしています。refreshはselect文を発行してbeanの値を再度詰め直すものです。

これをやらないと、@Entityと紐付けているテーブルとは対応していないプロパティを参照するとnullpoが発生しました・・・ 更新するプロパティを制限しているせいで、オブジェクトの状態がうまくいってないのか。

6.x 系でのやり方

6.xではEbean#update(Object bean, Set<String> properties) がなくなっているので、別のやり方が必要。

検証中だが、次でいけそう。

  • BeanPersistAdapterを継承し、preUpdateのみをoverride
  • BeanPersistRequest#getUpdatedValues()を使って、nullに更新したいkeyのValuePairを取得
  • ValuePairは更新前後の値を持つ、setNewValue(null)で更新後の値をnullに指定

あるいは、

ServerConfig.setUpdateChangesOnly(false) として、毎回全項目を更新することで、nullへの変更をできるようにするか。(もはや項目を限定しないやり方...)

参考サイト

2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2