0

我注意到我的一个应用程序中有一些奇怪的行为。我在两个类 Frame 和 Brand 之间有一个 ManyToOne 关系。就数据库而言,关系是单向的。表中的每个 Frame 都有一个 brand_id 列,但 Brand 没有任何指向另一个方向的列。到目前为止一切都很好,但在实际代码中,我有时需要获取有关与特定品牌关联的所有框架的信息。为了促进这一点,我在 Brand 类中添加了一个字段,该字段包含一组框架 ID,并使用 @ElementCollection 和 @CollectionTable 对其进行注释。

这是事情变得有点时髦的地方。Frame 类是使用单表继承的层次结构的一部分。并非所有映射到该表的类都有品牌,因此brand_id 列必须可以为空。从我目前能够确定的情况来看,对于使用@ElementCollection 注释的关系,Hibernate 强制“可为空”为假。似乎没有任何文档解释原因。相关代码可以在 hibernate-core-5.3.13.Final.jar 的 'org.hibernate.cfg.Ejb3JoinColumn.buildJoinTableJoinColumns()' 中找到,但它所说的只是

currentJoinColumn.setNullable(false); //我打破了规范,但它是好的

有什么方法可以覆盖 Hibernate 中的这个限制吗?如果没有,是否有其他方法可以在不使用@ElementCollection 的情况下做我想做的事情?

我的代码:

@Entity(name = "Frame")
@DiscriminatorValue("FRAME")
public class Frame extends Product
{
    @ManyToOne(optional=true)
    @JoinColumn(name = "brand_id")
    @IndexedEmbedded
    protected Brand brand;

    public Brand getBrand()
    {
        return brand;
    }
}

@Entity(name = "Brand")
@Table(name = "brands")
public class Brand extends Entity
{
    @ElementCollection
    @CollectionTable(name = "products", joinColumns = @JoinColumn(name = "brand_id"))
    @Column(name = "id")
    protected Set<BigInteger> frameIds;

    public Set<BigInteger> getFrameIds()
    {
        return frameIds;
    }

    public void setFrameIds(Set<BigInteger> frameIds)
    {
        this.frameIds = frameIds;
    }
}

public class Foo extends Entity
{
    @ManyToOne
    @JoinColumn(name = "brand_id")
    protected Brand brand;

    @ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    @JoinTable(name = "frames_to_features", inverseJoinColumns = {
        @JoinColumn(name = "frame_id", referencedColumnName = "id") }, joinColumns = {
                @JoinColumn(name = "feature_id", referencedColumnName = "id") })
    protected Set<Frame> frames;

    public List<BigInteger> getExcludedFrameIds()
    {
        List<BigInteger> brandFrames = new ArrayList<BigInteger>();
        if (getBrand() != null)
        {
            brandFrames.addAll(getBrand().getFrameIds());
            Set<BigInteger> localFrames = getFrameIds();
            if (localFrames != null)
            {
                brandFrames.removeAll(localFrames);
            }
        }
        return brandFrames;
    }
}
4

0 回答 0