Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Jpa 作为主键/id一部分的鉴别器列 处境_Jpa_Orm_Composite Primary Key_Discriminator - Fatal编程技术网

Jpa 作为主键/id一部分的鉴别器列 处境

Jpa 作为主键/id一部分的鉴别器列 处境,jpa,orm,composite-primary-key,discriminator,Jpa,Orm,Composite Primary Key,Discriminator,我有一个带有DiscriminatorColumn的实体,配置为单表继承: @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="TYPE") public class ContainerAssignment{ ... } “ContainerAsignment”引用了另一个实体: @JoinColumn(name="CONTAINER_ID&q

我有一个带有
DiscriminatorColumn
的实体,配置为单表继承:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="TYPE")
public class ContainerAssignment{
...
}
“ContainerAsignment”引用了另一个实体:

@JoinColumn(name="CONTAINER_ID")
private Container container;
每种类型的容器都可以有一个
containerSignature
。这意味着
containerSignment
表的主键由
CONTAINER\u ID
类型定义

ContainerAssignment
有一些子类,例如

@Entity
@DiscriminatorValue("SOME_TYPE")
public class SomeTypeOfContainerAssignment extends ContainerAssignment{
...
}
对于给定的
容器ID
,只有一个
SomeTypeOfContainerAssignment
实例

问题 如果我将JPA
@Id
定义为ContainerAssignment表上的容器,那么我可以执行
entityManager.find(SomeTypeOfContainerAssignment.class,containerId)
,这很好。这将沿着
SELECT*fromcontainer\u赋值运行,其中CONTAINER\u ID=1,TYPE='SOME\u TYPE'。它知道它需要在这里签入类型,因为实体上有
@DiscriminatorValue(“SOME_TYPE”)
注释

然而,这意味着从容器到容器的反向引用会中断,因为容器实际上不是主键。例如,如果容器有一个
@OneToOne(mappedBy=Container)私有SomeTypeOfContainerAssignment,当您在容器中读取时,它将通过类似以下内容在分配中读取:
SELECT*FROM container\u assignment,其中container\u ID=1,不进行类型检查。这为它提供了一个容器的所有分配,然后它随机选择一个,可能是错误的类型,在这种情况下,它抛出一个异常

相反,如果我使用container和type将ContainerAssignment的JPA
@Id
定义为一个复合Id,那么对ContainerAssignment子类的引用就可以了

但是,我不能做
entityManager.find(SomeTypeOfContainerAssignment.class,containerId)
,因为containerId不是id。我必须做
entityManager.find(SomeTypeOfContainerAssignment.class,new MyPk(containerId,“SOME_TYPE”)
,这似乎违背了
@DiscriminatorValue(“SOME_TYPE”)
。如果我必须在find上指定类型,我还可以使用单个ContainerAssignment实体

问题:
是否有一种方法可以对单个表继承实体的子类进行工作引用,其中表上的主键在鉴别器列上是复合的,同时也可以通过部分查找
EntityManager.find
如果
容器
有一个带有
SomeTypeOfContainerAssignment
的双向OneTONE,该OneTONE扩展了
ContainerAssignment
,则不应在
ContainerAssignment
中定义和映射容器字段,但在
某种类型的容器分配中

public class Container {
    @Id
    private Long id;

    @OneToOne(mappedBy = "container")
    private SomeTypeOfContainerAssignment someTypeOfContainerAssignment;
}

public class ContainerAssignment {
    @Id
    private Long id;
}

public class SomeTypeOfContainerAssignment extends ContainerAssignment {
    @OneToOne
    private Container container;
}
如果所有类型的容器指定都与容器有这样的OneToOne关联,则可以将容器定义为

public abstract class ContainerAssignment {
    @Id
    private Long id;

    public abstract Container getContainer();
    public abstract void setContainer(Container container);
}
老实说,我不知道是否允许您在表中使用相同的联接列来映射每个子类的
@OneToOne container
字段

我想这是你能得到的最好的了。如果将container字段放在基类中,那么必须将该关联定义为OneToMany/manytone关联,因为它实际上就是这样


我不认为你想做什么是可能的,我也不会搞砸复合PK,因为它们被劝阻是有充分理由的,而且使用起来是一场噩梦。

我将假设ContainerSignation的复合主键工作正常(我真的认为它可能依赖于JPA实现!),所有仍然困扰您的是对entityManager.find和PK实例化的恼人调用

我的解决方案是定义独立于jpaapi的finder方法。不要把自己锁定在JPA。 最简单的方法是在您的域类中定义一个静态查找器(或者,如果您想保持域不耦合,请定义另一个只包含查找器的类,然后进行JPA.Dig以了解如何做到这一点)

在ContainerSignment(或您的finder类):


请注意,使类型成为PK的一部分意味着您可以有两个具有相同id的不同类型的ContainerAssignment实例。如果您不知道ContainerAssignment的类型,则需要一个查询来检索ContainerAssignment。但是,如果您的id是从序列生成的,您可以编写另一个finder方法来隐藏对entity framework的内部调用,返回resultset的第一个结果。

如果您同意特定于提供程序的扩展,Hibernate会提供注释@DiscriminatorOptions


它帮助我解决了一个问题,即鉴别器列是复合主键的一部分。

谢谢你的回答,但它并没有真正解决问题-有没有办法将
鉴别器列
放在PK中?我同意人工PK是最佳选择,但在许多系统中,我们无法控制模式,必须处理复合PK。此外,根据Bill Karwin的书,请注意,从不使用复合主键是一种反模式。
public static <T extends ContainerAssignment> T findByPK(EntityManager manager,Class<T> type,long id) {
    DiscriminatorValue val = type.getAnnotation(DiscriminatorValue.class); // this is not optimal...can be cached...
    return (T) manager.find(type, new MyPk(containerId, val.getValue()));
}
SomeTypeOfContainerAssignment ca = ContainerAssignment.findByPK(entityManager,SomeTypeOfContainerAssignment.class,containerId);