Можно ли заменить или изменить значения из проекций или анонимных классов? - PullRequest
0 голосов
/ 25 апреля 2020

В моем приложении я использую проекции для сопоставления *Entity объектов с упрощенными или измененными версиями фактической записи в базе данных.

Однако у меня есть конкретный случай использования, когда Я обязан заменить определенное значение из одного из вложенных прогнозов. Так как это интерфейсы и они также проксируются Spring, я не уверен, что то, что я хочу, действительно возможно, но я приведу это к одному очень простому примеру:

Предположим, у меня есть UserEntity и User проекция. Для моей User проекции я могу просто выполнить:

User user = this.userEntityRepository.findById(userId);

Однако, если я хочу что-то изменить, я не уверен, возможно ли это. А именно, я не могу сделать что-то вроде этого:

if (user.getAge() < 18) {
  user.setDisplayName(null);
}

Теперь я знаю, что мог бы создать анонимный класс new User() { .. } и просто передать требуемые значения, но в моем случае объекты вложены и следовательно, это не вариант.

Вопрос

Есть ли другой способ заменить значение, например, displayName, как указано выше, без использования анонимного класса?


Удачный пример

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

У нас есть простое UserEntity:

@Entity
@Table(name = "app_user")
public class UserEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @Column
  private String firstName;

  @Column 
  private String lastName;

  @Column 
  private Integer age;

  // Setter & Getter ..
}
@Entity
@Table(name = "event")
public class EventEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @OneToMany(mappedBy = "event")
  private List<EventAttendeeEntity> attendees;

  // ..
}

У нас есть таблица, которая отображает пользователей на события:

@Entity
@Table(name = "attendee")
public class AttendeeEntity {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;

  @ManyToOne
  private EventEntity event;

  @ManyToOne
  private UserEntity user;


  // ..
}

Кроме того, у нас есть прогнозы для этих сущности, которые мы готовим как представления для наших клиентов:

/*
 * Projection for User
 */
public interface User {
  // All the properties ..  
}
/*
 * Projection for AttendeeEntity
 */
public interface Attendee {

  Long getId();

  User getUser();

}
/*
 * Projection for EventEntity
 */
public interface Event {

  Long getId();

  String getName();

  List<Attendee> getAttendees();

}

В одной из служб, которые мы получаем UserEvent. Здесь, скажем, мы хотим удалить имена всех пользователей младше 18 и по-прежнему возвращать userEvent мы только что получили.

public Event getEvent(Long id, Boolean anonymize) {

  Event event = this.eventRepository.findById(id);

  // The "anonymize" is to highlight that I cannot 
  // simply solve this in a User-projection
  if (!anonymize) {
    return event;
  }

  event
    .getAttendees();
    .stream()
    .peek(attendee -> {

       User user = attendee.getUser();

       if(user.getAge() < 18) {

         // Here we create a new user object without a name

         User newUser = new User() {
            @Override
            String getDisplayName() { return null; }
            @Override
            Integer getAge() { return user.getAge(); }
         }

         // !! This is where we hit the problem since we cannot
         // !! replace the old user object like this
         attendee.setUser(newUser);
       }        
     });

  return event;
}

1 Ответ

0 голосов
/ 25 апреля 2020

Одним из решений является использование SPEL в вашем селекторе проекции. Пожалуйста, попробуйте

public interface Attendee {

  Long getId();

  @Value("#{target.user.age >= 18 ? target.user : new your.package.UserEntity()}")
  User getUser();

}

Замените you.package на пакет UserEntity. Обратите внимание, чтобы поставить новый UserEntity (), а не новый пользователь (). Таким образом, пустая модель будет проецироваться как пустой интерфейс пользователя.

...