简体   繁体   中英

Using composite key with JPA

Learning on the go with Spring and all it's tools. Not sure how to use the PK instead of the String. tickets = repository.findOne(tk.getSerial()); Wants Primary key but unable to find the correct way?

Main UI:

package com.boot;

import com.boot.model.Tickets;
import com.boot.repository.TicketsRepository;
import com.boot.service.TicketsEditor;
import com.vaadin.annotations.Theme;
import com.vaadin.data.util.BeanContainer;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.sass.internal.util.StringUtil;
import com.vaadin.server.FontAwesome;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.StringUtils;

/**
 * Created by Ryan on 7/28/2016.
 */

@SpringUI
@Theme("valo")
public class TicketsUI extends UI {
    private final TicketsRepository repository;
    private final TicketsEditor editor;
    private final Grid grid;
    private final TextField filter;
    private final TextField invoiceFilter;
    private final Button addNewBtn;

    @Autowired
    public TicketsUI(TicketsRepository tkRepo, TicketsEditor tkEditor) {
        this.repository = tkRepo;
        this.editor = tkEditor;
        this.grid = new Grid();
        this.filter = new TextField();
        this.invoiceFilter = new TextField();
        this.addNewBtn = new Button("New game", FontAwesome.PLUS);

    }

    @Override
    protected void init(VaadinRequest request) {


    // build layout
    HorizontalLayout actions = new HorizontalLayout(filter, invoiceFilter, addNewBtn);
    VerticalLayout mainLayout = new VerticalLayout(actions, grid, editor);

    setContent(mainLayout);

    // Configure layouts and components
    actions.setSpacing(true);
    mainLayout.setMargin(true);
    mainLayout.setSpacing(true);

    grid.setHeight(500,Unit.PIXELS);
        grid.setWidth(1800,Unit.PIXELS);
        grid.setColumns("serial", "datePlaced", "dateRemoved","unsoldAmt", "actualGross","actualPrizes",
                "actualNet", "bin", "inplay", "closed", "unsoldTickets", "lastSaleRem", "prizeRem1", "prizeRem2",
                "prizeRem3", "prizeRem4", "prizeRem5","prizeRem6", "prizeRem7", "prizeRem8","prizeRem9", "prizeRem10", "prizeRem11", "prizeRem12", "prizeRem13", "prizeRem14", "prizeRem15",
                "gameTemplatesPartNum", "datePurch", "invoiceNum", "type");
        filter.setInputPrompt("Filter by serial");
        filter.addTextChangeListener(e -> listTickets(e.getText()));

      //  invoiceFilter.setInputPrompt("Filter by invoice");
      //  invoiceFilter.addTextChangeListener(e -> listTickets(e.getText()));
        //grid.setContainerDataSource(new BeanItemContainer(Tickets.class, repository.findByInvoiceNum()));
        // Connect selected Customer to editor or hide if none is selected
        grid.addSelectionListener(e -> {
            if (e.getSelected().isEmpty()) {
                editor.setVisible(false);
            }
            else {
                editor.editTicket((Tickets) grid.getSelectedRow());
            }
        });

        // Instantiate and edit new Customer the new button is clicked
        addNewBtn.addClickListener(e -> editor.editTicket(new Tickets()));

        // Listen changes made by the editor, refresh data from backend
        editor.setChangeHandler(() -> {
            editor.setVisible(false);
            listTickets(filter.getValue());
        });

        // Initialize listing
        listTickets(null);
}
    private void listTickets(String text){
        if (StringUtils.isEmpty(text)) {
            grid.setContainerDataSource(
                    new BeanItemContainer(Tickets.class, repository.findAll()));
        }else
        {
            grid.setContainerDataSource(new BeanItemContainer(Tickets.class, repository.findBySerial(text)));


        }
    }
}

Ticket

    package com.boot.model;

import javax.persistence.*;
import java.sql.Date;

/**
 * Created by Ryan on 7/26/2016.
 */
@Entity
@IdClass(TicketsPK.class)
public class Tickets {
    private String serial;
    private Date datePlaced;
    private Date dateRemoved;
    private Integer unsoldAmt;
    private Integer actualGross;
    private Integer actualPrizes;
    private Integer actualNet;
    private Integer bin;
    private Byte inplay;
    private Integer closed;
    private Integer unsoldTickets;
    private Byte lastSaleRem;
    private Integer prizeRem1;
    private Integer prizeRem2;
    private Integer prizeRem3;
    private Integer prizeRem4;
    private Integer prizeRem5;
    private Integer prizeRem6;
    private Integer prizeRem7;
    private Integer prizeRem8;
    private Integer prizeRem9;
    private Integer prizeRem10;
    private Integer prizeRem11;
    private Integer prizeRem12;
    private Integer prizeRem13;
    private Integer prizeRem14;
    private Integer prizeRem15;
    private String gameTemplatesPartNum;
    private Date datePurch;
    private String invoiceNum;
    private Integer type;

    @Id
    @Column(name = "Serial")
    public String getSerial() {
        return serial;
    }

    public void setSerial(String serial) {
        this.serial = serial;
    }

    @Basic
    @Column(name = "Date_placed")
    public Date getDatePlaced() {
        return datePlaced;
    }

    public void setDatePlaced(Date datePlaced) {
        this.datePlaced = datePlaced;
    }

    @Basic
    @Column(name = "Date_removed")
    public Date getDateRemoved() {
        return dateRemoved;
    }

    public void setDateRemoved(Date dateRemoved) {
        this.dateRemoved = dateRemoved;
    }

    @Basic
    @Column(name = "Unsold_amt")
    public Integer getUnsoldAmt() {
        return unsoldAmt;
    }

    public void setUnsoldAmt(Integer unsoldAmt) {
        this.unsoldAmt = unsoldAmt;
    }

    @Basic
    @Column(name = "Actual_gross")
    public Integer getActualGross() {
        return actualGross;
    }

    public void setActualGross(Integer actualGross) {
        this.actualGross = actualGross;
    }

    @Basic
    @Column(name = "Actual_prizes")
    public Integer getActualPrizes() {
        return actualPrizes;
    }

    public void setActualPrizes(Integer actualPrizes) {
        this.actualPrizes = actualPrizes;
    }

    @Basic
    @Column(name = "Actual_net")
    public Integer getActualNet() {
        return actualNet;
    }

    public void setActualNet(Integer actualNet) {
        this.actualNet = actualNet;
    }

    @Basic
    @Column(name = "Bin")
    public Integer getBin() {
        return bin;
    }

    public void setBin(Integer bin) {
        this.bin = bin;
    }

    @Basic
    @Column(name = "Inplay")
    public Byte getInplay() {
        return inplay;
    }

    public void setInplay(Byte inplay) {
        this.inplay = inplay;
    }

    @Basic
    @Column(name = "Closed")
    public Integer getClosed() {
        return closed;
    }

    public void setClosed(Integer closed) {
        this.closed = closed;
    }

    @Basic
    @Column(name = "Unsold_tickets")
    public Integer getUnsoldTickets() {
        return unsoldTickets;
    }

    public void setUnsoldTickets(Integer unsoldTickets) {
        this.unsoldTickets = unsoldTickets;
    }

    @Basic
    @Column(name = "Last_sale_rem")
    public Byte getLastSaleRem() {
        return lastSaleRem;
    }

    public void setLastSaleRem(Byte lastSaleRem) {
        this.lastSaleRem = lastSaleRem;
    }

    @Basic
    @Column(name = "Prize_rem1")
    public Integer getPrizeRem1() {
        return prizeRem1;
    }

    public void setPrizeRem1(Integer prizeRem1) {
        this.prizeRem1 = prizeRem1;
    }

    @Basic
    @Column(name = "Prize_rem2")
    public Integer getPrizeRem2() {
        return prizeRem2;
    }

    public void setPrizeRem2(Integer prizeRem2) {
        this.prizeRem2 = prizeRem2;
    }

    @Basic
    @Column(name = "Prize_rem3")
    public Integer getPrizeRem3() {
        return prizeRem3;
    }

    public void setPrizeRem3(Integer prizeRem3) {
        this.prizeRem3 = prizeRem3;
    }

    @Basic
    @Column(name = "Prize_rem4")
    public Integer getPrizeRem4() {
        return prizeRem4;
    }

    public void setPrizeRem4(Integer prizeRem4) {
        this.prizeRem4 = prizeRem4;
    }

    @Basic
    @Column(name = "Prize_rem5")
    public Integer getPrizeRem5() {
        return prizeRem5;
    }

    public void setPrizeRem5(Integer prizeRem5) {
        this.prizeRem5 = prizeRem5;
    }

    @Basic
    @Column(name = "Prize_rem6")
    public Integer getPrizeRem6() {
        return prizeRem6;
    }

    public void setPrizeRem6(Integer prizeRem6) {
        this.prizeRem6 = prizeRem6;
    }

    @Basic
    @Column(name = "Prize_rem7")
    public Integer getPrizeRem7() {
        return prizeRem7;
    }

    public void setPrizeRem7(Integer prizeRem7) {
        this.prizeRem7 = prizeRem7;
    }

    @Basic
    @Column(name = "Prize_rem8")
    public Integer getPrizeRem8() {
        return prizeRem8;
    }

    public void setPrizeRem8(Integer prizeRem8) {
        this.prizeRem8 = prizeRem8;
    }

    @Basic
    @Column(name = "Prize_rem9")
    public Integer getPrizeRem9() {
        return prizeRem9;
    }

    public void setPrizeRem9(Integer prizeRem9) {
        this.prizeRem9 = prizeRem9;
    }

    @Basic
    @Column(name = "Prize_rem10")
    public Integer getPrizeRem10() {
        return prizeRem10;
    }

    public void setPrizeRem10(Integer prizeRem10) {
        this.prizeRem10 = prizeRem10;
    }

    @Basic
    @Column(name = "Prize_rem11")
    public Integer getPrizeRem11() {
        return prizeRem11;
    }

    public void setPrizeRem11(Integer prizeRem11) {
        this.prizeRem11 = prizeRem11;
    }

    @Basic
    @Column(name = "Prize_rem12")
    public Integer getPrizeRem12() {
        return prizeRem12;
    }

    public void setPrizeRem12(Integer prizeRem12) {
        this.prizeRem12 = prizeRem12;
    }

    @Basic
    @Column(name = "Prize_rem13")
    public Integer getPrizeRem13() {
        return prizeRem13;
    }

    public void setPrizeRem13(Integer prizeRem13) {
        this.prizeRem13 = prizeRem13;
    }

    @Basic
    @Column(name = "Prize_rem14")
    public Integer getPrizeRem14() {
        return prizeRem14;
    }

    public void setPrizeRem14(Integer prizeRem14) {
        this.prizeRem14 = prizeRem14;
    }

    @Basic
    @Column(name = "Prize_rem15")
    public Integer getPrizeRem15() {
        return prizeRem15;
    }

    public void setPrizeRem15(Integer prizeRem15) {
        this.prizeRem15 = prizeRem15;
    }

    @Id
    @Column(name = "game_templates_part_num")
    public String getGameTemplatesPartNum() {
        return gameTemplatesPartNum;
    }

    public void setGameTemplatesPartNum(String gameTemplatesPartNum) {
        this.gameTemplatesPartNum = gameTemplatesPartNum;
    }

    @Basic
    @Column(name = "date_purch")
    public Date getDatePurch() {
        return datePurch;
    }

    public void setDatePurch(Date datePurch) {
        this.datePurch = datePurch;
    }

    @Basic
    @Column(name = "invoice_num")
    public String getInvoiceNum() {
        return invoiceNum;
    }

    public void setInvoiceNum(String invoiceNum) {
        this.invoiceNum = invoiceNum;
    }

    @Basic
    @Column(name = "type")
    public Integer getType() {
        return type;
    }

    public void setType(Integer type) {
        this.type = type;
    }


}

TicketsPK

package com.boot.model;

import javax.persistence.Column;
import javax.persistence.Id;
import java.io.Serializable;

/**
 * Created by Ryan on 7/26/2016.
 */
public class TicketsPK implements Serializable {
    private String serial;
    private String gameTemplatesPartNum;

    @Column(name = "Serial")
    @Id
    public String getSerial() {
        return serial;
    }

    public void setSerial(String serial) {
        this.serial = serial;
    }

    @Column(name = "game_templates_part_num")
    @Id
    public String getGameTemplatesPartNum() {
        return gameTemplatesPartNum;
    }

    public void setGameTemplatesPartNum(String gameTemplatesPartNum) {
        this.gameTemplatesPartNum = gameTemplatesPartNum;
    }

}

Repo

package com.boot.repository;

import com.boot.model.Tickets;
import com.boot.model.TicketsPK;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.List;

/**
 * Created by Ryan on 7/28/2016.
 */
public interface TicketsRepository extends JpaRepository<Tickets, String>{

    List<Tickets> findBySerial (String serial);

}

Pruned stacktrace:

org.springframework.dao.InvalidDataAccessApiUsageException: Provided id of the wrong type for class com.boot.model.Tickets. Expected: class com.boot.model.TicketsPK, got class java.lang.String; nested exception is java.lang.IllegalArgumentException: Provided id of the wrong type for class com.boot.model.Tickets. Expected: class com.boot.model.TicketsPK, got class java.lang.String
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:384) ~[spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:227) ~[spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:417) ~[spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59) ~[spring-tx-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213) ~[spring-tx-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147) ~[spring-tx-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:131) ~[spring-data-jpa-1.9.2.RELEASE.jar:na]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:208) ~[spring-aop-4.2.4.RELEASE.jar:4.2.4.RELEASE]
    at com.sun.proxy.$Proxy80.findOne(Unknown Source) ~[na:na]
    at com.boot.service.TicketsEditor.editTicket(TicketsEditor.java:88) ~[classes/:na]
    at com.boot.TicketsUI.lambda$init$ca60a5c0$1(TicketsUI.java:75) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]
at com.boot.TicketsUI.lambda$init$ca60a5c0$1(TicketsUI.java:75) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_91]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_91]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_91]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_91]

TicketEditor

package com.boot.service;

import com.boot.model.Tickets;
import com.boot.model.TicketsPK;
import com.boot.repository.TicketsRepository;
import com.vaadin.data.fieldgroup.BeanFieldGroup;
import com.vaadin.event.ShortcutAction;
import com.vaadin.server.FontAwesome;
import com.vaadin.spring.annotation.SpringComponent;
import com.vaadin.spring.annotation.UIScope;
import com.vaadin.ui.*;
import com.vaadin.ui.components.calendar.CalendarComponentEvents;
import com.vaadin.ui.themes.ValoTheme;
import org.springframework.beans.factory.annotation.Autowired;

/**
 * Created by Ryan on 7/28/2016.
 */
@SpringComponent
@UIScope
public class TicketsEditor extends VerticalLayout{

    private final TicketsRepository repository;
    private Tickets tickets;

    //TextField gameName = new TextField("Game Name");
    TextField serial = new TextField("Serial");
    DateField datePlaced = new DateField("Date placed");
    DateField dateRemoved = new DateField("Date Removed");
    TextField unsoldAmt = new TextField("Unsold Amount");
    TextField actualGross = new TextField("Actual Gross");
    TextField actualPrizes = new TextField("Actual Prizes");
    TextField actualNet = new TextField("Actual Net");
    TextField bin = new TextField("Bin");
    TextField inplay = new TextField("Inplay");
    TextField closed = new TextField("Closed");
    TextField unsoldTickets = new TextField("Unsold Tickets");
    TextField lastSaleRem = new TextField("Last Sale Remaining");
    TextField prizeRem1 = new TextField("Prize Remaining 1");
    TextField prizeRem2 = new TextField("Prize Remaining 2");
    TextField prizeRem3 = new TextField("Prize Remaining 3");
    TextField prizeRem4 = new TextField("Prize Remaining 4");
    TextField prizeRem5 = new TextField("Prize Remaining 5");
    TextField prizeRem6 = new TextField("Prize Remaining 6");
    TextField prizeRem7 = new TextField("Prize Remaining 7");
    TextField prizeRem8 = new TextField("Prize Remaining 8");
    TextField prizeRem9 = new TextField("Prize Remaining 9");
    TextField prizeRem10 = new TextField("Prize Remaining 10");
    TextField prizeRem11 = new TextField("Prize Remaining 11");
    TextField prizeRem12 = new TextField("Prize Remaining 12");
    TextField prizeRem13 = new TextField("Prize Remaining 13");
    TextField prizeRem14 = new TextField("Prize Remaining 14");
    TextField prizeRem15 = new TextField("Prize Remaining 15");
    TextField gameTemplatesPartNum = new TextField("Part Number");
    DateField datePurchased = new DateField("Date Purchased");
    TextField invoice = new TextField("Invoice");
    TextField type = new TextField("Type");

    /* Action buttons */
    Button save = new Button("Save", FontAwesome.SAVE);
    Button cancel = new Button("Cancel");
    Button delete = new Button("Delete", FontAwesome.TRASH_O);
    CssLayout actions = new CssLayout(save, cancel, delete);

    @Autowired
    public TicketsEditor(TicketsRepository repository){
        this.repository = repository;
        addComponents(serial,datePlaced,dateRemoved, unsoldAmt, actualGross, actualPrizes, actualNet,bin,inplay,
                closed, unsoldTickets, lastSaleRem, prizeRem1, prizeRem2, prizeRem3, prizeRem4, prizeRem5, prizeRem6,
                prizeRem7, prizeRem8, prizeRem9, prizeRem10, prizeRem11, prizeRem12, prizeRem13, prizeRem14, prizeRem15,
                actions);

        setSpacing(true);
        actions.setStyleName(ValoTheme.LAYOUT_COMPONENT_GROUP);
        save.setStyleName(ValoTheme.BUTTON_PRIMARY);
        save.setClickShortcut(ShortcutAction.KeyCode.ENTER);

        save.addClickListener(e -> repository.saveAndFlush(tickets));
        delete.addClickListener(e -> repository.delete(tickets));
        cancel.addClickListener(e -> editTicket(tickets));
        setVisible(false);
    }
    public interface ChangeHandler{
        void onChange();
    }
    public final void editTicket(Tickets tk){
        final boolean persisted = tk.getSerial() != null;
        if(persisted){
            tickets = repository.findOne(tk.getSerial());
        }else{
            tickets = tk;
        }

        cancel.setVisible(persisted);
        BeanFieldGroup.bindFieldsUnbuffered(tickets, this);
        setVisible(true);
        save.focus();
        serial.selectAll();
    }
    public void setChangeHandler(ChangeHandler h){
        save.addClickListener(e -> h.onChange());
        delete.addClickListener(e -> h.onChange());
    }
}

em.find takes in an instance of the IdClass . So in your case you need to pass in an instance of TicketsPK , not one component of it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM