JPA"多部分标识符......无法绑定"

时间:2014-05-02 16:53:02

标签: java sql-server jpa eclipselink

有一个抽象类NodeBase和几个扩展类(NodeAnnounceNodeTransfer,...),我想在JPA的注释中应用继承@Inheritance@DiscriminatorColumn

以下是我的课程(我稍微强调了一下,虽然吸气剂和制定者很明显,但这并不是我的风格):

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="nodeType")
@Table(name="node_base")
@NamedQueries({
  @NamedQuery(name="NodeBase.findAll", query="SELECT n FROM NodeBase n"),
  @NamedQuery(name="NodeBase.findByTarget", query="SELECT n FROM NodeBase n JOIN Target t ON t.firstNode = n.id WHERE t.id = :targetID")
})
public abstract class NodeBase implements Serializable {
  private static final long serialVersionUID = 1L;
  @Id
  private int id;
  private int customer;
  private String exitNames;
  private int nodeType;
  private int diagramPosX;
  private int diagramPosY;

  public NodeBase() {}

  public int getId() { return this.id; }
  public void setId(int id) { this.id = id; }

  public int getCustomer() { return this.customer; }
  public void setCustomer(int customer) { this.customer = customer;}

  public String getExitNames() { return this.exitNames; }
  public void setExitNames(String exitNames) { this.exitNames = exitNames; }

  public int getDiagramPosX() { return diagramPosX; }
  public void setDiagramPosX(int diagramPosX) { this.diagramPosX = diagramPosX; }

  public int getDiagramPosY() { return diagramPosY; }
  public void setDiagramPosY(int diagramPosY) { this.diagramPosY = diagramPosY; }

  public int getNodeType() { return nodeType; }
  public void setNodeType(int nodeType) { this.nodeType = nodeType; }  
}

一个继承类(仅一个示例)

@Entity
@Table(name="node_announce")
@DiscriminatorValue(value="2")
@NamedQuery(name="NodeAnnounce.findAll", query="SELECT n FROM NodeAnnounce n")
public class NodeAnnounce extends NodeBase implements Serializable {
  private static final long serialVersionUID = 1L;

  private String wavefile;

  public NodeAnnounce() {}

  public String getWavefile() { return this.wavefile; }
  public void setWavefile(String wavefile) { this.wavefile = wavefile; }
}

我现在正在调用之前定义的命名查询

NodeBase nodeBase =
(NodeBase) em.createNamedQuery("NodeBase.findByTarget")
  .setParameter("targetID", target.getId())
  .getSingleResult();

我可以确保target不为空,并且它返回的ID是存在的。在上面的函数调用中,抛出了一个非常长的异常:

[EL Warning]: 2014-05-02 18:39:31.287--UnitOfWork(138297553)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.5.0.v20130507-3faac2b): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.microsoft.sqlserver.jdbc.SQLServerException: The multi-part identifier "node_base.nodeType" could not be bound.
Error Code: 4104
Call: SELECT DISTINCT node_base.nodeType FROM target t0, node_base t1 WHERE ((t0.ID = ?) AND (t0.FIRSTNODE = t1.ID))
  bind => [1 parameter bound]
Query: ReadObjectQuery(name="NodeBase.findByTarget" referenceClass=NodeBase sql="SELECT DISTINCT node_base.nodeType FROM target t0, node_base t1 WHERE ((t0.ID = ?) AND (t0.FIRSTNODE = t1.ID))")
  at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:340)
  at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:679)
  at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:558)
  (...)
Caused by: com.microsoft.sqlserver.jdbc.SQLServerException: The multi-part identifier "node_base.nodeType" could not be bound.
  at com.microsoft.sqlserver.jdbc.SQLServerException.makeFromDatabaseError(SQLServerException.java:216)
  at com.microsoft.sqlserver.jdbc.SQLServerStatement.getNextResult(SQLServerStatement.java:1515)
  (...)

堆栈跟踪的这一行看起来很奇怪:

SELECT DISTINCT node_base.nodeType FROM target t0, node_base t1 WHERE ((t0.ID = ?) AND (t0.FIRSTNODE = t1.ID))

为什么t0.ID = ??它不应该。

我知道,这是另一个The multi-part identifier问题。但我认为这与JPA有关。 数据库中的字段nodeType与表node_type有关系 - 我在Java项目中没有使用该表。但无论如何,这个领域的价值很重要。

后端是SQL Server。这里有相关的表定义:

CREATE TABLE [dbo].[node_base](
  [id] [int] IDENTITY(1,1) NOT NULL,
  [nodeType] [int] NOT NULL,
  [exitNames] [varchar](20) NOT NULL,
  [customer] [int] NOT NULL,
  [diagramPosX] [int] NULL,
  [diagramPosY] [int] NULL,
 CONSTRAINT [PK_node_base] PRIMARY KEY CLUSTERED 
(
  [id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

1 个答案:

答案 0 :(得分:2)

正如评论中所提到的,您的查询中的问题不在于t0.ID = ?,因为这是JPQL SELECT n FROM NodeBase n JOIN Target t ON t.firstNode = n.id WHERE t.id = :targetID所期望的。问题是当查询NodeBase时,EclipseLink首先会检查要从查询返回的所有子类,因此只选择DiscriminatorColumn," nodeType"。这将返回由于继承而需要构建的所有子类,然后EclipseLink将用于后续查询 不幸的是,您正在使用继承来访问EclipseLink错误https://bugs.eclipse.org/bugs/show_bug.cgi?id=344721

我的解决方法是让EclipseLink使用外连接策略来引入子类而不是单独的查询。这允许使用单个查询引入所有内容,并且可以使用此处所述的自定义程序进行配置:https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Entities/Inheritance#Outer_Joining_Subclasses

这里讨论使用一个查询与多个查询进行继承的利弊:http://en.wikibooks.org/wiki/Java_Persistence/Inheritance