如何在Vaadin 8中绑定外键

时间:2018-12-07 23:17:27

标签: java hibernate binding vaadin vaadin8

我无法解决问题。我有一个带有TextField的窗口,我想绑定一个外键,但是不知道我在做什么错。我已经在这里阅读答案:Binding foreign key in Vaadin (EclipseLink) 我决定使用Converter,但仍然遇到问题。 因此,有两个实体(简化):ClientOrder。一个现有的或新的客户可以有多个订单,这意味着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将设置程序setClientID突出显示为“无法解析方法'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(), "");
    }
}

有人可以帮助我解决问题吗?

2 个答案:

答案 0 :(得分:2)

答案:如何在文本字段中绑定外键(或任何其他嵌套属性)(不是您所需要的!)

您可以通过提供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));

如果订单目前没有客户端,则此代码可能是NullPointerException的原因。如果可能的话,请改用此方法(添加了对空值的检查):

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 ,而 为此订单选择/分配新客户。如果您要使用后者,请改用ComboBox!我不确定第一次做是否有意义,但我回答了,因为你问过。我现在确定您要使用后一种方法,所以请继续下一部分。


问题的实际解决方案:似乎确实需要一个ComboBox,因为您想选择/分配该订单的客户。

所以您基本上需要的是这样:

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);

这样,您可以选择一个客户端,然后将其设置为绑定订单客户端。

答案 1 :(得分:1)

您的绑定不起作用,因为您的setClient方法希望将Client类型的Object作为参数而不是Long。您应该将其更改为:

{
  "parcelles" : {
    "mappings" : {
      "parcelle" : {
        "properties" : {
          "geometry" : {
            "properties" : {
              "coordinates" : {
                "type" : "float"
              },
              "type" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              }
            }
          },
          "id" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "properties" : {
            "properties" : {
              "commune" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              },
              "contenance" : {
                "type" : "long"
              },
              "created" : {
                "type" : "date"
              },
              "id" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              },
              "numero" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              },
              "prefixe" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              },
              "section" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              },
              "updated" : {
                "type" : "date"
              }
            }
          },
          "type" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          }
        }
      }
    }
  }
}

您还可以使用组合框来选择客户,在Vaadin网站上有一个示例如何将对象绑定到组合框。