代码之家  ›  专栏  ›  技术社区  ›  Jherico

如何联接辅助表中非主键列上的表?

  •  12
  • Jherico  · 技术社区  · 15 年前

    在ORM类层次结构中,我需要联接对象上的表,其中联接列不是基类的主键。下面是表设计的一个示例:

    CREATE TABLE APP.FOO
    (
        FOO_ID INTEGER NOT NULL,
        TYPE_ID INTEGER NOT NULL,
        PRIMARY KEY( FOO_ID )
    )
    
    CREATE TABLE APP.BAR
    (
        FOO_ID INTEGER NOT NULL,
        BAR_ID INTEGER NOT NULL,
        PRIMARY KEY( BAR_ID ),
        CONSTRAINT bar_fk FOREIGN KEY( FOO_ID ) REFERENCES APP.FOO( FOO_ID )
    )
    
    CREATE TABLE APP.BAR_NAMES
    (
        BAR_ID INTEGER NOT NULL,
        BAR_NAME VARCHAR(128) NOT NULL,
        PRIMARY KEY( BAR_ID, BAR_NAME),
        CONSTRAINT bar_names_fk FOREIGN KEY( BAR_ID ) REFERENCES APP.BAR( BAR_ID )
    )
    

    下面是映射(为简洁而消除的getter和setter)

    @Entity
    @Table(name = "FOO")
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = "TYPE_ID", discriminatorType =    javax.persistence.DiscriminatorType.INTEGER)
    public abstract class Foo {
        @Id
        @Column(name = "FOO_ID")
        private Long fooId;
    }
    
    @Entity
    @DiscriminatorValue("1")
    @SecondaryTable(name = "BAR", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "FOO_ID", referencedColumnName = "FOO_ID") })
    public class Bar extends Foo{
        @Column(table = "BAR", name = "BAR_ID")
        Long barId;
     }    
    

    如何添加映射 BAR_NAMES 假定其联接列不是 FOO_ID 但是 BAR_ID 是吗?

    我尝试了以下方法:

    @CollectionOfElements(fetch = FetchType.LAZY)
    @Column(name = "BAR_NAME")
    @JoinTable(name = "BAR_NAMES", joinColumns = @JoinColumn(table = "BAR", name = "BAR_ID", referencedColumnName="BAR_ID"))
    List<String> names = new ArrayList<String>();
    

    失败的原因是用于检索BAR对象的SQL试图从foo表中获取BAR_id值。我还尝试用

    @JoinTable(name = "BAR_NAMES", joinColumns = @JoinColumn(name = "BAR_ID"))
    

    这不会产生SQL错误,但也不会检索任何数据,因为对bar_名称的查询使用foo_id作为联接值,而不是bar_id。

    出于测试目的,我用以下命令填充了数据库

    insert into FOO (FOO_ID, TYPE_ID) values (10, 1);
    insert into BAR (FOO_ID, BAR_ID) values (10, 20);
    insert into BAR_NAMES (BAR_ID, BAR_NAME) values (20, 'HELLO');
    

    许多看似有效的解决方案在获取ID 10的foo对象时将返回空集合(而不是包含1个名称的集合)

    3 回复  |  直到 15 年前
        1
  •  7
  •   Jherico    15 年前

    我找到了解决办法。如果你像这样映射酒吧类

    @Entity
    @DiscriminatorValue("1")
    @SecondaryTable(name = "BAR", pkJoinColumns = { @PrimaryKeyJoinColumn(name = "FOO_ID", referencedColumnName = "FOO_ID") })
    public class Bar extends Foo {
        @OneToOne
        @JoinColumn(table = "BAR", name = "BAR_ID")
        MiniBar miniBar;
    }
    

    并添加以下类

    @Entity
    @SqlResultSetMapping(name = "compositekey", entities = @EntityResult(entityClass = MiniBar.class, fields = { @FieldResult(name = "miniBar", column = "BAR_ID"), }))
    @NamedNativeQuery(name = "compositekey", query = "select BAR_ID from BAR", resultSetMapping = "compositekey")
    @Table(name = "BAR")
    public class MiniBar {
        @Id
        @Column(name = "BAR_ID")
        Long barId;
    } 
    

    然后,您可以将任何类型的映射添加到 MiniBar 类,就像barid是主键一样,然后进一步使其在外部可用 Bar 班级。

        2
  •  2
  •   matt b    15 年前

    不确定如何使用jpa/annotations执行此操作,但对于Hibernate XML映射文件,它将类似于:

    <class name="Bar" table="BAR">
        <id name="id" type="int">
            <column name="BAR_ID"/>
            <generator class="native"/>
        </id>
        <set name="barNames" table="BAR_NAMES">
            <!-- Key in BAR_NAMES table to map to this class's key -->
            <key column="BAR_ID"/> 
            <!-- The value in the BAR_NAMES table we want to populate this set with -->
            <element type="string" column="BAR_NAME"/>
        </set>
    </class>
    
        3
  •  2
  •   ChssPly76    15 年前

    你不能做你想做的事。@集体犯罪(和@onetomany,就这点而言)是 总是 通过所有者的实体主键映射。

    您映射foo/bar继承的方式也相当奇怪-它们显然不在同一个表中;似乎使用 JoinedSubclass 会是更好的方法。记住,这仍然不能帮助你绘制地图。 bar_names bar_id 因为主键值在层次结构中是共享的(即使子类的列名可能不同)。

    一种可能的替代方法是 @OneToOne foo和bar之间的映射,而不是继承。只有这样你才能绘制地图 巴尔名字 巴尔伊德 以及最适合您的表结构的映射(尽管,可能不适合您的域模型)。