Обновите постоянный объект временным объектом, используя Hibernate - PullRequest
7 голосов
/ 24 января 2011

Ежедневно данные импортируются через веб-сервис.

  1. Я создаю новый (временный) экземпляр приложения, которое я отобразил в спящем режиме с помощью аннотаций JPA.
  2. Я заполняю данные из веб-сервиса во временный экземпляр
  3. Я загружаю постоянный объект из базы данных, которую я хочу обновить, используя данные в моем временном экземпляре.
  4. Я как-то объединяю этот временный экземпляр с постоянным. Если постоянный объект имеет ненулевое значение в одном из своих полей, он не будет перезаписан потенциально нулевым значением для временного объекта. По сути, я не хочу потерять какие-либо данные, просто обновите информацию об изменениях.

Я знаю, что мог бы пройтись по всем полям в pojos, проверить на нулевые значения и обновить, где это необходимо, но я бы предпочел, чтобы это сделал hibernate, если это возможно, так как это уменьшило бы шансы на мое добавление поле и забыть добавить его в этот процесс слияния вручную.

Может ли Hibernate выполнить шаг № 4 выше?

Ответы [ 2 ]

11 голосов
/ 24 января 2011

Нет, Hibernate (или JPA) не предоставляет такую ​​функциональность "из коробки", но нетрудно достичь с помощью механизма JavaBeans (или одной из многих библиотек, которые предоставляют над этим уровень абстракции).

Использование простого самоанализа Javabeans

Вот метод, который копирует все свойства из beanA в beanB, если они равны нулю в beanB, с использованием стандартного механизма JavaBeans Introspector:

public static void copyBeanProperties(
    final Object beanA, final Object beanB){

    if(beanA.getClass() != beanB.getClass()){
        // actually, this may be a problem, because beanB may be a
        // cglib-created subclass
        throw new IllegalArgumentException();
    }
    try{
        for( final PropertyDescriptor pd :
            Introspector
              .getBeanInfo(beanB.getClass(), Object.class)
              .getPropertyDescriptors()){
            if(pd.getReadMethod().invoke(beanB)==null){
                pd.getWriteMethod().invoke(beanB,
                    pd.getReadMethod().invoke(beanA)
                );
            }
        }
    } catch(IntrospectionException e){
        throw new IllegalStateException(e);
    } catch(IllegalAccessException e){
        throw new IllegalStateException(e);
    } catch(InvocationTargetException e){
        throw new IllegalStateException(e);
    }
}

Конечно, это просто быстрая и грязная реализация, но она должна помочь вам начать работу.

Использование Apache Commons / BeanUtils

Вот немногоболее элегантная версия с использованием Commons / BeanUtils .Он скрывает ваше отражение и предоставляет доступ к свойствам на основе карты:

public static void copyBeanProperties(final Object beanA, final Object beanB){
    try{
        @SuppressWarnings("unchecked") // this should be safe
        final Map<String, Object> beanAProps = PropertyUtils.describe(beanA);
        @SuppressWarnings("unchecked") // this should be safe
        final Map<String, Object> beanBProps = PropertyUtils.describe(beanB);

        if(!beanAProps.keySet().containsAll(beanBProps.keySet())){
            throw new IllegalArgumentException("Incompatible types: "
                + beanA + ", " + beanB);
        }
        for(final Entry<String, Object> entryA : beanAProps.entrySet()){
            if(beanBProps.get(entryA.getKey()) == null){
                PropertyUtils.setMappedProperty(beanB, entryA.getKey(),
                    entryA.getValue());
            }
        }
    } catch(final IllegalAccessException e){
        throw new IllegalStateException(e);
    } catch(final InvocationTargetException e){
        throw new IllegalStateException(e);
    } catch(final NoSuchMethodException e){
        throw new IllegalStateException(e);
    }
}

Использование Spring BeanWrapper

А вот еще одна версия, использующая интерфейс Spring BeanWrapper (этонаименее многословный, потому что Spring предоставляет абстракцию выше всего отражения и выполняет собственную обработку исключений), но, к сожалению, технология BeanWrapper доступна только с контейнером Spring IOC (что, конечно, прискорбно, если вы не используетеконтейнер):

public static void copyBeanProperties(final Object beanA, final Object beanB){

    final BeanWrapper wrapperA = new BeanWrapperImpl(beanA);
    final BeanWrapper wrapperB = new BeanWrapperImpl(beanB);

    try{
        for(final PropertyDescriptor descriptor : wrapperB
            .getPropertyDescriptors()){

            final String propertyName = descriptor.getName();
            if(wrapperB.getPropertyValue(propertyName) == null){
                wrapperB.setPropertyValue(propertyName,
                    wrapperA.getPropertyValue(propertyName));
            }
        }
    } catch(final /* unchecked */ InvalidPropertyException e){
        throw new IllegalArgumentException("Incompatible types: " + beanA
            + ", " + beanB, e);
    }
}
0 голосов
/ 24 января 2011

Hibernate не сделает это для вас.Вы можете изменить свои setter s, чтобы иметь эту функцию.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...