假设我有一个简单的应用程序,其中包含这样的实体:
Dog.java:
@Entity(name = "dogs")
public class Dog {
@Id
@SequenceGenerator(name = "dog_sequence",
sequenceName = "dog_sequence",
allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "dog_sequence")
private Long id;
@Column(unique = true)
private String name;
// getters, setters, constructors
}
Command.java:
@Entity(name = "commands")
public class Command {
@Id
@SequenceGenerator(name = "command_sequence",
sequenceName = "command_sequence",
allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE,
generator = "command_sequence")
private Long id;
@Column(unique = true)
private String name;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "dog_id", nullable = false)
private Dog dog;
// getters, setters, constructors
}
所以一只狗可以知道几个命令,每个命令对一只狗来说都是唯一的(只属于一只狗)。
我有一个视图(网站页面),允许管理员添加新的命令,每只狗,也改变狗的名字。
完成后,视图将发送一个POST
请求到/api/dog/edit
,JSON如下所示:
{
"commands": ["some command name", "another command name"],
"id": 1,
"name": "Updated Dog Name"
}
现在,由于Dog
实体不包含List<Command>
字段,控制器无法将所有JSONMap到Dog
实体,因此我创建了一个DogDto
:
DogDto.java:
public class DogDto {
private Long id;
private String name;
private List<CommandDto> commands;
// getters, setters, constructors
}
CommandDto
:
CommandDto.java:
public class CommandDto {
private Long id;
private String name;
private DogDto dog;
// getters, setters, constructors
}
现在我的控制器可以将从视图传递的JSONMap到DogDto
:
@RestController
@RequestMapping(path = "api/dog")
public class DogController {
...
@PostMapping("edit")
@CrossOrigin
public ResponseEntity<DogDto> editDog(@RequestBody DogDto dogDto) {
...
Dog dog = mapper.map(dogDto, Dog.class);
List<Command> commands = new ArrayList<>();
for (CommandDto commandDto: dogDto.getCommands()) {
Command command = mapper.map(commandDto, Command.class);
commands.add(command);
}
...
}
}
现在我可以将DogDto
Map到Dog
和Command
实体。但是什么才是坚持下去的最好方法呢?目前我的DogService
有
public boolean editDog(Dog dog) {...}
方法接受一个狗,尝试通过ID查找它:
Dog foundDog = this.dogRepository.findById(dog.getId());
如果找到了狗,则更新其名称字段并执行this.dogRepository.save(foundDog);
。
但是我也需要保存命令。Dog
实体不包含命令列表。因此,我需要将editDog
方法签名更改为boolean editDog(DogDto dog)
,或者在控制器中这样做:
for (Command command: commands) {
command.setDog(dogFoundById);
this.commandService.createCommand(command);
}
我不知道该怎么办。
我也一直在想,如果我有一个更复杂的结构,有更多的嵌套实体:
public class C {
...
@ManyToOne
private B b;
}
最佳设计决策是否会有所不同?
1条答案
按热度按时间fruv7luv1#
一种方法是使用业务对象。
我们总是希望能够自由地更改域对象,而不会影响视图对象。这意味着域实体可以随着业务需求开始而发展,而不会改变API的使用者。
这里的约束是控制器总是与API的客户端交换DTO,并且存储库调用总是处理域对象。当在对象上执行业务逻辑时,您通常不希望选择其中一个。两种选择都不合适。