Проблема внешнего ключа в Java Persistance API с Netbeans 6.9.1 - PullRequest
2 голосов
/ 03 сентября 2010

У меня ошибка при настройке Java Persistence в Netbeans.Я использовал MySQL в качестве внутреннего сервера базы данных.

Мой код, как показано ниже,

База данных

CREATE TABLE `hub` (
 `hub_ID` INT(11) NOT NULL AUTO_INCREMENT,
 `hub_Name` VARCHAR(45) NOT NULL,
 PRIMARY KEY (`hub_ID`),
 UNIQUE INDEX `hub_Name` (`hub_Name`)
)ENGINE=MyISAM

CREATE TABLE `company` (
 `company_ID` INT(11) NOT NULL AUTO_INCREMENT,
 `company_Name` VARCHAR(45) NOT NULL,
 `company_hub_ID` INT(11) NOT NULL,
 PRIMARY KEY (`company_ID`),
 INDEX `fk_company_hub1` (`company_hub_ID`)
 )

Persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="testJPAPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>testjpa.Hub</class>
    <class>testjpa.Company</class>
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/logistikumdispatch"/>
      <property name="javax.persistence.jdbc.password" value="rootroot"/>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
      <property name="javax.persistence.jdbc.user" value="root"/>
    </properties>
  </persistence-unit>
</persistence>

Hub.java (класс сущности в проекте)

    /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package testjpa;

import java.io.Serializable;
import java.util.Collection;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;

/**
 *
 * @author Anjum
 */
@Entity
@Table(name = "hub")
@NamedQueries({
    @NamedQuery(name = "Hub.findAll", query = "SELECT h FROM Hub h"),
    @NamedQuery(name = "Hub.findByHubID", query = "SELECT h FROM Hub h WHERE h.hubID = :hubID"),
    @NamedQuery(name = "Hub.findByHubName", query = "SELECT h FROM Hub h WHERE h.hubName = :hubName")})
public class Hub implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "hub_ID")
    private Integer hubID;
    @Basic(optional = false)
    @Column(name = "hub_Name")
    private String hubName;

    @OneToMany(mappedBy="hub", cascade=CascadeType.ALL)
    @JoinColumn(name="company_hub_ID")
    private Collection<Company> companies;

    public Hub() {
    }

    public Hub(Integer hubID) {
        this.hubID = hubID;
    }

    public Hub(Integer hubID, String hubName) {
        this.hubID = hubID;
        this.hubName = hubName;
    }

    public Integer getHubID() {
        return hubID;
    }

    public void setHubID(Integer hubID) {
        this.hubID = hubID;
    }

    public String getHubName() {
        return hubName;
    }

    public void setHubName(String hubName) {
        this.hubName = hubName;
    }

    public Collection<Company> getCompanies()
    {
        return companies;
    }

    public void setCompanies(Collection<Company> companies)
    {
        this.companies = companies;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (hubID != null ? hubID.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Hub)) {
            return false;
        }
        Hub other = (Hub) object;
        if ((this.hubID == null && other.hubID != null) || (this.hubID != null && !this.hubID.equals(other.hubID))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "testjpa.Hub[hubID=" + hubID + "]";
    }

}

Company.java (класс сущности в проекте)

package testjpa;

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

/**
 *
 * @author Anjum
 */
@Entity
@Table(name = "company")
@NamedQueries({
    @NamedQuery(name = "Company.findAll", query = "SELECT c FROM Company c"),
    @NamedQuery(name = "Company.findByCompanyID", query = "SELECT c FROM Company c WHERE c.companyID = :companyID"),
    @NamedQuery(name = "Company.findByCompanyName", query = "SELECT c FROM Company c WHERE c.companyName = :companyName"),
    @NamedQuery(name = "Company.findByCompanyhubID", query = "SELECT c FROM Company c WHERE c.companyhubID = :companyhubID")})
public class Company implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "company_ID")
    private Integer companyID;
    @Basic(optional = false)
    @Column(name = "company_Name")
    private String companyName;
    @Basic(optional = false)
    @Column(name = "company_hub_ID")
    private int companyhubID;
    @ManyToOne()
    @JoinColumn(name="hub_ID", insertable=false, updatable=false)
    private Hub hub;
    public Company() {
    }

    public Company(Integer companyID) {
        this.companyID = companyID;
    }

    public Company(Integer companyID, String companyName, int companyhubID) {
        this.companyID = companyID;
        this.companyName = companyName;
        this.companyhubID = companyhubID;
    }

    public Integer getCompanyID() {
        return companyID;
    }

    public void setCompanyID(Integer companyID) {
        this.companyID = companyID;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    public int getCompanyhubID() {
        return companyhubID;
    }

    public void setCompanyhubID(int companyhubID) {
        this.companyhubID = companyhubID;
    }

    public Hub getHub()
    {
        return hub;
    }

    public void setHub(Hub hub)
    {
        this.hub = hub;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (companyID != null ? companyID.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Company)) {
            return false;
        }
        Company other = (Company) object;
        if ((this.companyID == null && other.companyID != null) || (this.companyID != null && !this.companyID.equals(other.companyID))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "testjpa.Company[companyID=" + companyID + "]";
    }

}

Основная программа

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package testjpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

/**
 *
 * @author Anjum
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("testJPAPU");
        EntityManager em = emf.createEntityManager();

        em.getTransaction().begin();

        Company c1 = new Company();
        c1.setCompanyName("ays");


        Hub h1 = new Hub();
        h1.setHubName("abc");
        em.persist(h1);
        c1.setHub(h1);

        em.persist(c1);
        em.flush();

    }
}

Выход

[EL Info]: 2010-09-03 14:39:02.639--ServerSession(3199106)--EclipseLink, version: Eclipse Persistence Services - 2.0.2.v20100323-r6872
[EL Info]: 2010-09-03 14:39:03.371--ServerSession(3199106)--file:/C:/Users/Anjum/Documents/NetBeansProjects/testJPA/build/classes/_testJPAPU login successful

Проблема

Моя проблема в том, чтовнешний ключ company.company_hub_ID обновляется в базе данных с помощью comapany.company_name = "ays".Но всегда есть 0 в company.company_hub_ID.

Концентратор также обновляется должным образом.Значит, нет проблем с подключением или JPA.Проблема заключается только в отношениях.

Заранее спасибо за помощь.

Ответы [ 4 ]

1 голос
/ 04 сентября 2010

Как уже упоминалось, вы не должны использовать JoinColumn на обеих сторонах вашей ассоциации OneToMany / ManyToOne, а только на стороне-владельце (стороне многих).Удалите его со стороны OneToMany и исправьте имя столбца.

У вас также не должно быть атрибута companyhubID в сущности Company для хранения внешнего ключа (такие вещи фактически предполагаютсябыть скрытым на уровне объекта).Удалите атрибут и insertable=false, updatable=false из JoinColumn.

. Таким образом, сопоставления должны быть:

@Entity
...
public class Hub implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "hub_ID")
    private Integer hubID;
    @Basic(optional = false)
    @Column(name = "hub_Name")
    private String hubName;

    <b>@OneToMany(mappedBy="hub", cascade=CascadeType.ALL)
//    @JoinColumn(name="company_hub_ID") // THIS IS WRONG
    private Collection companies = new HashSet()</b>
    ...
    // method to set both sides of the link of the bidirectional association
    public void addToCompanies(Company company) {
        company.setHub(this);
        this.companies.add(company);
    }
}

И

@Entity
...
public class Company implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "company_ID")
    private Integer companyID;
    @Basic(optional = false)
    @Column(name = "company_Name")
    private String companyName;
<b>//    @Basic(optional = false) 
//    @Column(name = "company_hub_ID")
//    private int companyhubID;          // NO, DON'T

    @ManyToOne()
    @JoinColumn(name="company_hub_ID"/*, insertable=false, updatable=false*/)
    private Hub hub;</b>
    ...
}

Некоторые дополнительные замечания:

  • Можно использовать стратегию IDENTITY для генерации идентификаторов.
  • Вы должны использовать таблицы InnoDB для ссылочной целостности.

Также обратите внимание, что ваша демонстрациякод неверный, вы не устанавливаете ассоциацию должным образом.Должно быть:

Company c1 = new Company();
c1.setCompanyName("ays");
Hub h1 = new Hub();
h1.setHubName("abc");
h1.addToCompanies.add(c1);  // set the bidirectional association

em.persist(h1);             // JPA will cascade the persist
em.flush();
0 голосов
/ 04 сентября 2010

Наконец-то я решил эту проблему с поддержкой romanB.

Спасибо за помощь "ROMANB".

Посмотрите ниже, как я решил, что вы можете использовать эту технику для реализации постоянства с внешними ключами в NetBeans.

public class Company implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "company_ID", nullable=true)
    private Integer companyID;
    @Basic(optional = false)
    @Column(name = "company_Name")
    private String companyName;
    @Basic(optional = false)
    @Column(name = "company_hub_ID", nullable=false, updatable=false, insertable=false)
    private int companyhubID;
    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name="company_hub_ID")
    private Hub hub_ref;
..........
..........

public class Hub implements Serializable {
    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "hub_ID")
    private Integer hubID;
    @Basic(optional = false)
    @Column(name = "hub_Name")
    private String hubName;

    @OneToMany(mappedBy="hub_ref", cascade=CascadeType.ALL)
    private Collection<Company> companies;

    ................
    ................
  \\ in Hub class
public void addCompany(Company company)
    {
        if(this.companies == null)
        {
            this.companies = new ArrayList<Company>();
        }
        this.companies.add(company);
        company.setHub(this);
    }

И, наконец, основной класс

 public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("testJPAPU");
        EntityManager em = emf.createEntityManager();



        Company c1 = new Company();
        c1.setCompanyName("ays");

        Hub h1 = new Hub();
        h1.setHubName("abc");

        em.getTransaction().begin();

        h1.addCompany(c1);
        em.persist(h1);

        em.flush();

    }

Используйте ссылку eclipse 2.0 для получения поддержки JPA 2.0.

Еще раз спасибо и благодаря переполнению стека.

Анджум Шримали.

0 голосов
/ 03 сентября 2010

Я согласен с предложением Романба.

Поскольку связь двунаправленная, убедитесь, что вы установили «обе стороны ссылки», как указано в этом сообщении .

Попробуйте изменить свой код следующим образом:

public class Hub {
    ...
    @OneToMany(mappedBy="hub", cascade=CascadeType.ALL)
    private Collection<Company> companies = new ArrayList<Company>();

    ...
    public void addCompany(Company company) {
        company.setHub(this);
        this.companies.add(company);
    }       
    ...
}

public class Company {
    ...         
    @ManyToOne
    @JoinColumn(name="company_hub_ID")
    private Hub hub;    
    ...
}

public class Main {

    public static void Main(String[] args) {
        ...
        Company c1 = new Company();
        c1.setCompanyName("ays");

        Hub h1 = new Hub();
        h1.setHubName("abc");
        h1.addCompany(c1);
        em.persist(h1);
    }

}

Также используйте стратегию генерации идентификатора, отличную от GenerationType.IDENTITY, так как идентификатор недоступен до тех пор, пока не произойдет вставка.

0 голосов
/ 03 сентября 2010

Что-то не совпадает между вашим отображением и схемой базы данных. Схема базы данных генерируется провайдером JPA?

Отображение определяет столбец соединения hub_id для класса компании, однако в схеме базы данных отсутствует этот столбец (вместо этого в нем есть "company_hub_ID").

Попробуйте следующее:

Удалите @JoinColumn со стороны @OneToMany. @ OneToMany + @ JoinColumn используется только для отображения однонаправленных однокомпонентных ассоциаций на внешний ключ (без таблицы соединения). Ваша ассоциация является двунаправленной onetomany, поэтому @OneToMany с mappedBy на обратной стороне и @ManyToOne + @JoinColumn (необязательно) на стороне владельца. Не устанавливайте вставляемый / обновляемый в false.

...