【发布时间】:2020-04-25 11:39:55
【问题描述】:
在我的应用程序中,我使用projections 将*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;
}
【问题讨论】:
-
我不认为这是可能的。如果可能,那么接口和实现类之间没有区别
-
@Eklavya 恐怕是这样。我真的开始后悔去预测了。它们适用于简单的东西,例如“按原样”获取实体,但当它变得更复杂时,它们就不是一种选择。例如。现在我有一个项目列表,我想确定用户喜欢哪些项目。我认为通过预测无法做到这一点。
标签: java spring-boot spring-data-jpa spring-data