Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Двойное поле в инсерте.


Автор: ShurikA 26.10.2009, 10:09
Есть такая сущность:
Код

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

import iib.model.employee.config.EmployeePosition;
import iib.model.employee.config.EmployeeType;
import java.io.Serializable;
import java.util.Date;
import java.util.List;
import javax.persistence.Basic;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinColumns;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;

/**
 *
 * @author ShurikAg
 */
@Entity
@Table(name = "Employee", uniqueConstraints = {@UniqueConstraint(columnNames = {"id", "companyId"})})
@NamedQueries({
    @NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e"),
    @NamedQuery(name = "Employee.findById", query = "SELECT e FROM Employee e WHERE e.employeePK.id = :id"),
    @NamedQuery(name = "Employee.findEmplIdCompId", query = "SELECT e FROM Employee e WHERE e.employeePK.id = :emplId AND e.employeePK.companyId = :companyId"),
    @NamedQuery(name = "Employee.findByCompanyId", query = "SELECT e FROM Employee e WHERE e.employeePK.companyId = :companyId"),
    @NamedQuery(name = "Employee.findHighestEmplIdForCompany", query = "SELECT MAX(e.employeePK.id) FROM Employee e WHERE e.employeePK.companyId = :companyId"),
    @NamedQuery(name = "Employee.findByUserId", query = "SELECT e FROM Employee e WHERE e.userId = :userId"),
    @NamedQuery(name = "Employee.findByUserIdCompanyId", query = "SELECT e FROM Employee e WHERE e.employeePK.companyId = :companyId AND e.userId = :userId"),
    @NamedQuery(name = "Employee.findByOrganizationId", query = "SELECT e FROM Employee e WHERE e.organizationId = :organizationId"),
    @NamedQuery(name = "Employee.findByFirstname", query = "SELECT e FROM Employee e WHERE e.firstname = :firstname"),
    @NamedQuery(name = "Employee.findByLastname", query = "SELECT e FROM Employee e WHERE e.lastname = :lastname"),
    @NamedQuery(name = "Employee.findByManagerIdAndCompanyId", query = "SELECT e FROM Employee e WHERE e.manager.employeePK.id = :managerId AND e.manager.employeePK.companyId = :companyId"),
    @NamedQuery(name = "Employee.findByCreationDate", query = "SELECT e FROM Employee e WHERE e.creationDate = :creationDate"),
    @NamedQuery(name = "Employee.findByUpdateDate", query = "SELECT e FROM Employee e WHERE e.updateDate = :updateDate"),
    @NamedQuery(name = "Employee.findByOperator", query = "SELECT e FROM Employee e WHERE e.operator = :operator"),
    @NamedQuery(name = "Employee.findByPartTimePercent", query = "SELECT e FROM Employee e WHERE e.partTimePercent = :partTimePercent")
})
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;
    protected EmployeePK employeePK;
    private int userId;
    private int organizationId;
    private String firstname;
    private String lastname;
    private Date creationDate;
    private Date updateDate;
    private int operator;
    private Integer partTimePercent;
    //relationships
    private Employee manager;
    private List<Employee> directs;
    private EmployeeType emplType;
    private EmployeePosition emplPosition;

    public Employee() {
    }

    public Employee(EmployeePK employeePK) {
        this.employeePK = employeePK;
    }

    public Employee(EmployeePK employeePK, Integer userId, Integer organizationId, String firstname, String lastname, Date creationDate, Date updateDate, int operator) {
        this.employeePK = employeePK;
        this.userId = userId;
        this.organizationId = organizationId;
        this.firstname = firstname;
        this.lastname = lastname;
        this.creationDate = creationDate;
        this.updateDate = updateDate;
        this.operator = operator;
    }

    public Employee(int id, int companyId) {
        this.employeePK = new EmployeePK(id, companyId);
    }

    @EmbeddedId
    public EmployeePK getEmployeePK() {
        return employeePK;
    }

    public void setEmployeePK(EmployeePK employeePK) {
        this.employeePK = employeePK;
    }

    @Basic(optional = false)
    @Column(name = "userId", nullable = false)
    public int getUserId() {
        return userId;
    }

    public void setUserId(int userId) {
        this.userId = userId;
    }

    @Basic(optional = false)
    @Column(name = "organizationId", nullable = false)
    public int getOrganizationId() {
        return organizationId;
    }

    public void setOrganizationId(int organizationId) {
        this.organizationId = organizationId;
    }

    @Basic(optional = false)
    @Column(name = "firstname", nullable = false)
    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    @Basic(optional = false)
    @Column(name = "lastname", nullable = false)
    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    @Basic(optional = false)
    @Column(name = "creationDate", nullable = false)
    @Temporal(value = TemporalType.TIMESTAMP)
    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    @Basic(optional = true)
    @Column(name = "updateDate", nullable = true)
    @Temporal(value = TemporalType.TIMESTAMP)
    public Date getUpdateDate() {
        return updateDate;
    }

    public void setUpdateDate(Date updateDate) {
        this.updateDate = updateDate;
    }

    @Basic(optional = false)
    @Column(name = "operator", nullable = false)
    public int getOperator() {
        return operator;
    }

    public void setOperator(int operator) {
        this.operator = operator;
    }

    @Column(name = "partTimePercent")
    public Integer getPartTimePercent() {
        return partTimePercent;
    }

    public void setPartTimePercent(Integer partTimePercent) {
        this.partTimePercent = partTimePercent;
    }
    //relationships

    @ManyToOne(optional = true, fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name = "emplTypeId", referencedColumnName = "id", nullable = true)
    public EmployeeType getEmplType() {
        return emplType;
    }

    public void setEmplType(EmployeeType emplType) {
        this.emplType = emplType;
    }

    @ManyToOne(optional = true, fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
    @JoinColumn(name = "positionId", referencedColumnName = "id", nullable = true)
    public EmployeePosition getEmplPosition() {
        return emplPosition;
    }

    public void setEmplPosition(EmployeePosition emplPosition) {
        this.emplPosition = emplPosition;
    }

    @OneToMany(mappedBy = "manager")
    public List<Employee> getDirects() {
        return directs;
    }

    public void setDirects(List<Employee> directs) {
        this.directs = directs;
    }

    public void addDirect(Employee direct) {
        this.directs.add(direct);
    }

    @ManyToOne(fetch = FetchType.LAZY, optional = true, cascade = CascadeType.ALL)
    @JoinColumns({
        @JoinColumn(name = "managerId", referencedColumnName = "id", nullable = true),
        @JoinColumn(name = "companyId", referencedColumnName = "companyId")
    })
    public Employee getManager() {
        return manager;
    }

    public void setManager(Employee manager) {
        this.manager = manager;
    }

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

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof Employee)) {
            return false;
        }
        Employee other = (Employee) object;
        if ((this.employeePK == null && other.employeePK != null) || (this.employeePK != null && !this.employeePK.equals(other.employeePK))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "org.employee.model.Employee[employeePK=" + employeePK + "]";
    }
}


с таким ключом:
Код

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

import java.io.Serializable;
import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;

/**
 *
 * @author ShurikAg
 */
@Embeddable
public class EmployeePK implements Serializable {

    private Integer id;
    private Integer companyId;

    public EmployeePK() {
    }

    public EmployeePK(Integer id, Integer companyId) {
        this.id = id;
        this.companyId = companyId;
    }

    @Basic(optional = false)
    @Column(name = "id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @Basic(optional = false)
    @Column(name = "companyId", nullable = false)
    public Integer getCompanyId() {
        return companyId;
    }

    public void setCompanyId(Integer companyId) {
        this.companyId = companyId;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id == null) ? 0 : id;
        hash += (int) companyId;
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        if (!(object instanceof EmployeePK)) {
            return false;
        }
        EmployeePK other = (EmployeePK) object;
        if (this.id != other.id) {
            return false;
        }
        if (this.companyId != other.companyId) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "org.employee.model.EmployeePK[id=" + id + ", companyId=" + companyId + "]";
    }
}


когда я пытаюсь записать в базу нового работника:
Код

public void save(Employee empl) {
        logger.info("Saving Employee: " + empl.toString());
        try {
            getJpaTemplate().persist(empl);
            getJpaTemplate().flush();
        } catch (RuntimeException e) {
            logger.error("Failed to save entity: " + empl.toString(), e);
            throw e;
        }
    }


получаю такую ошибку:
Код

Error Code: 1110
org.springframework.orm.jpa.JpaSystemException: Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Call: INSERT INTO Employee (firstname, updateDate, lastname, operator, partTimePercent, userId, creationDate, organizationId, emplTypeId, positionId, managerId, companyId, id, companyId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Column 'companyId' specified twice
        bind => [First, null, Last, 1, null, 1, null, 1, 15, 20, null, null, null, null]
Error Code: 1110
Query: InsertObjectQuery(org.employee.model.Employee[employeePK=org.employee.model.EmployeePK[id=null, companyId=1]])
Call: INSERT INTO Employee (firstname, updateDate, lastname, operator, partTimePercent, userId, creationDate, organizationId, emplTypeId, positionId, managerId, companyId, id, companyId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerImpl.flush(EntityManagerImpl.java:353)
        bind => [First, null, Last, 1, null, 1, null, 1, 15, 20, null, null, null, null]
        at org.springframework.orm.jpa.JpaTemplate$8.doInJpa(JpaTemplate.java:290)
Query: InsertObjectQuery(org.employee.model.Employee[employeePK=org.employee.model.EmployeePK[id=null, companyId=1]]); nested exception is javax.persistence.PersistenceException: Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
        at org.springframework.orm.jpa.JpaTemplate.execute(JpaTemplate.java:183)
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Column 'companyId' specified twice
        ... 31 more
Error Code: 1110
Caused by: Exception [TOPLINK-4002] (Oracle TopLink Essentials - 2.0.1 (Build b09d-fcs (12/06/2007))): oracle.toplink.essentials.exceptions.DatabaseException
Call: INSERT INTO Employee (firstname, updateDate, lastname, operator, partTimePercent, userId, creationDate, organizationId, emplTypeId, positionId, managerId, companyId, id, companyId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Column 'companyId' specified twice
Error Code: 1110
Call: INSERT INTO Employee (firstname, updateDate, lastname, operator, partTimePercent, userId, creationDate, organizationId, emplTypeId, positionId, managerId, companyId, id, companyId) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
        bind => [First, null, Last, 1, null, 1, null, 1, 15, 20, null, null, null, null]
Query: InsertObjectQuery(org.employee.model.Employee[employeePK=org.employee.model.EmployeePK[id=null, companyId=1]])
        at oracle.toplink.essentials.exceptions.DatabaseException.sqlException(DatabaseException.java:311)
        bind => [First, null, Last, 1, null, 1, null, 1, 15, 20, null, null, null, null]
        at oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:654)
Query: InsertObjectQuery(org.employee.model.Employee[employeePK=org.employee.model.EmployeePK[id=null, companyId=1]])
        at oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:703)
        at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:312)
        at org.springframework.orm.jpa.DefaultJpaDialect.translateExceptionIfPossible(DefaultJpaDialect.java:120)
        at oracle.toplink.essentials.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:492)
        at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
...


почему?

Автор: ivanovpv 27.10.2009, 12:23
В insert поле CompanyID указано 2 раза. А это надо полагать вызвано тем, что процедура генерации первичного ключа завязана на 2-х полях идентификаторе работничка и компании.

В общем ощибка дизайна (IMHO конечно)

Автор: ShurikA 27.10.2009, 12:32
Цитата(ivanovpv @  27.10.2009,  11:23 Найти цитируемый пост)
В общем ощибка дизайна (IMHO конечно) 

Ну не совсем: база сама по себе позволяет пользоваться одним и тем же полем для ключей (primary и foreign). Но похоже на то что JPA нет...

Автор: ivanovpv 27.10.2009, 15:48
Цитата(ShurikA @  27.10.2009,  12:32 Найти цитируемый пост)
Ну не совсем: база сама по себе позволяет пользоваться одним и тем же полем для ключей (primary и foreign). Но похоже на то что JPA нет... 


Согласен, что с точки зрения БД SQL ошибки нет, просто тул не позволяет использовать задумку

Автор: ShurikA 27.10.2009, 19:31
Цитата(ivanovpv @  27.10.2009,  14:48 Найти цитируемый пост)
Согласен, что с точки зрения БД SQL ошибки нет, просто тул не позволяет использовать задумку 

А есть какой то путь таки да использовать задумку?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)