如何在 Vaadin 8 中绑定外键
How to bind a foreign key in Vaadin 8
我无法解决问题。我有一个 window 和 TextField
,我想绑定一个外键,但不知道我做错了什么。我已经在这里阅读了答案:
我决定使用Converter
,但还是跌跌撞撞。
因此,有两个实体(简化):Client
和 Order
。现有或新客户可以有多个订单,意味着 Order.clientID 是外键
客户实体:
@Entity
@DynamicInsert
@DynamicUpdate
@Table(name = "Clients")
public class Client {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ClientID", updatable = false, nullable = false)
private Long clientID;
@Column(name = "Name", nullable = false, length = 20)
private String name;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "clientID")
private Set<Order> orders;
public Long getId() { return clientID; }
public void setId(Long clientID) { this.clientID = clientID; }
public String getName() { return firstName; }
public void setName(String name) { this.name = name; }
}
订单实体:
@Entity
@DynamicInsert
@DynamicUpdate
@Table(name = "Orders")
public class Order{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "OrderID", nullable = false)
private Long orderID;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "ClientID",
referencedColumnName = "ClientID",
updatable = false,
nullable = false)
private Client clientID;
@Column(name = "Description", nullable = false, length = 1000)
private String description;
public Long getOrderID() { return orderID; }
//public Long getClientID() { return clientID.getId(); }
public Client getClientID() { return clientID; }
public void setClientID(Client clientID) { this.clientID = clientID; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
}
并且我想将 Order.clientID 绑定到 TextField。但是 IDEA 将 setter setClientID
突出显示为 "Cannot resolve method 'setClientID'"
public class AddOrderModalView extends Window {
private OrderService orderService = new OrderService();
private Order order = new Order();
Binder<Order> binder = new Binder<>(Order.class);
private ChangeHandler changeHandler = new ChangeHandler() {
@Override
public void onChange() {
}
};
private FormLayout formLayout = new FormLayout();
private TextField clientId = new TextField("Client ID");
private TextField description = new TextField("Description");
private Button save = new Button("Save");
private Button cancel = new Button("Cancel");
public AddOrderModalView() {
super("Add a new order");
VerticalLayout subContent = new VerticalLayout();
subContent.setSizeFull();
HorizontalLayout actions = new HorizontalLayout();
actions.addComponents(save, cancel);
formLayout.addComponents(clientId, description);
subContent.addComponent(formLayout);
setContent(subContent);
save.addStyleNames(ValoTheme.BUTTON_SMALL, ValoTheme.BUTTON_PRIMARY);
cancel.addStyleName(ValoTheme.BUTTON_SMALL);
save.addClickListener(e -> save());
cancel.addClickListener(e -> close());
bindingFields();
setModal(true);
}
private void bindingFields() {
binder.forField(clientId)
.withConverter(Long::valueOf, String::valueOf)
.bind(Order::getClientID, Order::setClientID); //the error is here
binder.forField(this.description)
.withValidator(new StringLengthValidator(
"Please add description. The maximum length is 1000 characters", 1, 1000))
.bind(Order::getDescription, Order::setDescription);
binder.bindInstanceFields(this);
binder.setBean(order);
}
public interface ChangeHandler {
void onChange();
}
private void save() {
if (binder.validate().isOk()) {
orderService.persist(order);
close();
changeHandler.onChange();
}
}
}
ClientToClientIdConverter:
public class ClientToClientIdConverter implements Converter<String, Client> {
@Override
public Result<Client> convertToModel(String s, ValueContext valueContext) {
return Result.error("not supported");
}
@Override
public String convertToPresentation(Client client, ValueContext valueContext) {
return Objects.toString(client.getId(), "");
}
}
谁能帮我解决这个问题?
您的绑定不起作用,因为您的 setClient 方法需要一个 Client 类型的对象作为参数,而不是 Long。您应该将其更改为:
public void setClientID(Long clientID) { this.clientID = clientID; }
您也可以使用组合框来选择客户,在 Vaadin 网站上有一个如何将对象绑定到组合框的示例。
问题的答案:如何在文本字段中绑定外键(或任何其他嵌套 属性)(不是您需要的!)
您可以通过提供 lambda 表达式来获取和设置嵌套属性来实现。
TextField clientId = new TextField("Client ID");
binder.forField(clientId)
.withConverter(new StringToLongConverter("error message"))
.bind(item -> item.getClient().getId(), (item, value) -> item.getClient().setId(value));
如果此时订单没有客户端,则此代码可能会导致 NullPointerExceptions。如果可能,则改用它(添加了对空值的检查):
TextField clientId = new TextField("Client ID");
binder.forField(clientId)
.withConverter(new StringToLongConverter("error message"))
.bind(
item -> item.getClient() != null ? item.getClient.getId() : null,
(item, value) -> {
if(item.getClient() != null){
item.getClient().setId(value);
}
});
警告!请注意,手动更改此文本字段中的值将更改已分配给它的客户端的 ID,并且不是 select/assign 此订单的新客户。如果您想要后者,请改用 ComboBox!我不确定做第一个是否有意义,但我回答是因为你问了。我现在确定你想要后一种选择,所以请继续下一部分。
你问题的实际解决方案:看来你确实需要一个ComboBox,因为你想select/assign订单的客户。
所以你基本上需要的是:
ComboBox<Client> clientSelection = new ComboBox<Client>("client");
clientSelection.setItems(clientService.findAll()); // list/set of possible clients.
// Using clients name for item captions now, but you can also use id or both
clientSelection.setItemCaptionGenerator(Client::getName);
binder.forField(clientSelection)
.bind(Order::getClient, Order::setClient);
这样,您可以 select 一个客户端,然后将其设置为绑定订单客户端。
我无法解决问题。我有一个 window 和 TextField
,我想绑定一个外键,但不知道我做错了什么。我已经在这里阅读了答案:Converter
,但还是跌跌撞撞。
因此,有两个实体(简化):Client
和 Order
。现有或新客户可以有多个订单,意味着 Order.clientID 是外键
客户实体:
@Entity
@DynamicInsert
@DynamicUpdate
@Table(name = "Clients")
public class Client {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ClientID", updatable = false, nullable = false)
private Long clientID;
@Column(name = "Name", nullable = false, length = 20)
private String name;
@OneToMany(fetch = FetchType.LAZY, mappedBy = "clientID")
private Set<Order> orders;
public Long getId() { return clientID; }
public void setId(Long clientID) { this.clientID = clientID; }
public String getName() { return firstName; }
public void setName(String name) { this.name = name; }
}
订单实体:
@Entity
@DynamicInsert
@DynamicUpdate
@Table(name = "Orders")
public class Order{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "OrderID", nullable = false)
private Long orderID;
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "ClientID",
referencedColumnName = "ClientID",
updatable = false,
nullable = false)
private Client clientID;
@Column(name = "Description", nullable = false, length = 1000)
private String description;
public Long getOrderID() { return orderID; }
//public Long getClientID() { return clientID.getId(); }
public Client getClientID() { return clientID; }
public void setClientID(Client clientID) { this.clientID = clientID; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
}
并且我想将 Order.clientID 绑定到 TextField。但是 IDEA 将 setter setClientID
突出显示为 "Cannot resolve method 'setClientID'"
public class AddOrderModalView extends Window {
private OrderService orderService = new OrderService();
private Order order = new Order();
Binder<Order> binder = new Binder<>(Order.class);
private ChangeHandler changeHandler = new ChangeHandler() {
@Override
public void onChange() {
}
};
private FormLayout formLayout = new FormLayout();
private TextField clientId = new TextField("Client ID");
private TextField description = new TextField("Description");
private Button save = new Button("Save");
private Button cancel = new Button("Cancel");
public AddOrderModalView() {
super("Add a new order");
VerticalLayout subContent = new VerticalLayout();
subContent.setSizeFull();
HorizontalLayout actions = new HorizontalLayout();
actions.addComponents(save, cancel);
formLayout.addComponents(clientId, description);
subContent.addComponent(formLayout);
setContent(subContent);
save.addStyleNames(ValoTheme.BUTTON_SMALL, ValoTheme.BUTTON_PRIMARY);
cancel.addStyleName(ValoTheme.BUTTON_SMALL);
save.addClickListener(e -> save());
cancel.addClickListener(e -> close());
bindingFields();
setModal(true);
}
private void bindingFields() {
binder.forField(clientId)
.withConverter(Long::valueOf, String::valueOf)
.bind(Order::getClientID, Order::setClientID); //the error is here
binder.forField(this.description)
.withValidator(new StringLengthValidator(
"Please add description. The maximum length is 1000 characters", 1, 1000))
.bind(Order::getDescription, Order::setDescription);
binder.bindInstanceFields(this);
binder.setBean(order);
}
public interface ChangeHandler {
void onChange();
}
private void save() {
if (binder.validate().isOk()) {
orderService.persist(order);
close();
changeHandler.onChange();
}
}
}
ClientToClientIdConverter:
public class ClientToClientIdConverter implements Converter<String, Client> {
@Override
public Result<Client> convertToModel(String s, ValueContext valueContext) {
return Result.error("not supported");
}
@Override
public String convertToPresentation(Client client, ValueContext valueContext) {
return Objects.toString(client.getId(), "");
}
}
谁能帮我解决这个问题?
您的绑定不起作用,因为您的 setClient 方法需要一个 Client 类型的对象作为参数,而不是 Long。您应该将其更改为:
public void setClientID(Long clientID) { this.clientID = clientID; }
您也可以使用组合框来选择客户,在 Vaadin 网站上有一个如何将对象绑定到组合框的示例。
问题的答案:如何在文本字段中绑定外键(或任何其他嵌套 属性)(不是您需要的!)
您可以通过提供 lambda 表达式来获取和设置嵌套属性来实现。
TextField clientId = new TextField("Client ID");
binder.forField(clientId)
.withConverter(new StringToLongConverter("error message"))
.bind(item -> item.getClient().getId(), (item, value) -> item.getClient().setId(value));
如果此时订单没有客户端,则此代码可能会导致 NullPointerExceptions。如果可能,则改用它(添加了对空值的检查):
TextField clientId = new TextField("Client ID");
binder.forField(clientId)
.withConverter(new StringToLongConverter("error message"))
.bind(
item -> item.getClient() != null ? item.getClient.getId() : null,
(item, value) -> {
if(item.getClient() != null){
item.getClient().setId(value);
}
});
警告!请注意,手动更改此文本字段中的值将更改已分配给它的客户端的 ID,并且不是 select/assign 此订单的新客户。如果您想要后者,请改用 ComboBox!我不确定做第一个是否有意义,但我回答是因为你问了。我现在确定你想要后一种选择,所以请继续下一部分。
你问题的实际解决方案:看来你确实需要一个ComboBox,因为你想select/assign订单的客户。
所以你基本上需要的是:
ComboBox<Client> clientSelection = new ComboBox<Client>("client");
clientSelection.setItems(clientService.findAll()); // list/set of possible clients.
// Using clients name for item captions now, but you can also use id or both
clientSelection.setItemCaptionGenerator(Client::getName);
binder.forField(clientSelection)
.bind(Order::getClient, Order::setClient);
这样,您可以 select 一个客户端,然后将其设置为绑定订单客户端。