2014-10-29 4 views
0

Я преобразовываю некоторые C# с XML-сопоставлением NHibernate в Java с сопоставлением аннотаций, и есть сущность, которую я пробовал преобразовать без успеха. У нас есть MAIN_TABLE, JOIN_TABLE и THIRD_TABLE. Одна запись из MAIN_TABLE может иметь много от THIRD_TABLE, и их отношение хранится в JOIN_TABLE, который имеет только три столбца: первичный ключ, состоящий из ключей из MAIN_TABLE и THIRD_TABLE, и третья строка с некоторыми нерелевантными дополнительными данными. Это оригинальный NHibernate XML отображение:Сопоставление элементов с составным первичным ключом с аннотациями

<class name="MainTable" table="MAIN_TABLE" mutable="false"> 
<id name="Id" column="rvcplc" type="int" length="10"> 
    <generator class="assigned"/> 
</id> 
<bag name="JoinedRecords" table="JOIN_TABLE" order-by="main_table_id"> 
    <key column="main_table_id" not-null="true"/> 
    <composite-element class="JoinTable"> 
    <parent name="parentRecord"/> 
    <many-to-one name="ThirdTable" column="third_table_id"/> 
    </composite-element> 
</bag> 

И это текущее состояние моего кода:

@Entity() 
@Table(name="MAIN_TABLE") 
@Immutable 
public class MainTable extends BusinessEntity implements IMainTable 
{ 
    @Id 
    @Type(type = "LongToNull") 
    @Column(name = "id") 
    private long id; 

    @ElementCollection 
    @CollectionTable(name="JOIN_TABLE", joinColumns={@JoinColumn(name="main_table_id")}) 
    private List<IJoinTable> joinedRecords = new ArrayList<IJoinTable>(); 
} 

@Embeddable() 
@Table(name = "JOIN_TABLE") 
@Immutable 
public class JoinTable implements Serializable, IJoinTable 
{ 
    @SuppressWarnings("unused") 
    @Id 
    private JoinTablePK pkId; 

    @Parent 
    @Column(name = "main_table_id") 
    private IMainTable parentRecord; 

    @ManyToOne(targetEntity = ThirdTable.class) 
    @JoinColumn(name = "third_table_id") 
    private IThirdTable thirdTable; 

    public static class JoinTablePK implements Serializable 
    { 
      // foo 
    } 
} 

Когда я пытаюсь модульного тестирования этой ассоциации, просто загружая известную MainTable сущность и утверждая его имеет три дочерних объекта JoinTable в своей коллекции, с ошибкой «Не удалось инициализировать сбор». Это мой лучший код, хотя, поскольку другие попытки сделали ВСЕ мои тесты неудачными, как это происходит, когда у вас неправильное сопоставление.

ответ

2

Вот как я попытаюсь это сделать (я буду использовать простые классы в коде, надеюсь, что суперклассы и интерфейсы не имеют отношения к проблеме).

Существует два варианта. Первый, тем легче, если эти «нерелевантные дополнительные данные» в JOIN_TABLE действительно не имеют отношения к модели.

@Entity 
@Table(name="MAIN_TABLE") 
public class MainTable { 
    @Id 
    @Type(type = "LongToNull") 
    private long id; 

    @ManyToMany 
    @JoinTable(name = "JOIN_TABLE", joinColumns = @JoinColumn(name = "JOIN_TABLE_ID"), 
     inverseJoinColumns = @JoinColumn(name = "THIRD_TABLE_ID") 
    private List<ThirdTable> thirdTableRecords = new ArrayList<ThirdTable>(); 
} 

@Entity 
@Table(name="THIRD_TABLE") 
public class ThirdTable { 
    @Id 
    @Type(type = "LongToNull") 
    private long id; 

    @ManyToMany(mappedBy = "thirdTableRecords") 
    private List<MainTable> mainTableRecords = new ArrayList<MainTable>(); 

    ... 
} 

Если «не имеет значения дополнительных данных» по-прежнему должен быть смоделирован, то объекты будут выглядеть примерно так

@Entity 
@Table(name="MAIN_TABLE") 
public class MainTable { 
    @Id 
    @Type(type = "LongToNull") 
    private long id; 

    @OneToMany(mappedBy = "mainTable") 
    private List<JoinTable> joinTableRecords = new ArrayList<JoinTable>(); 
} 

@Entity 
@Table(name="THIRD_TABLE") 
public class ThirdTable { 
    @Id 
    @Type(type = "LongToNull") 
    private long id; 

    @OneToMany(mappedBy = "thirdTable") 
    private List<JoinTable> joinTableRecords = new ArrayList<joinTable>(); 

    ... 
} 

@Entity 
@Table(name="JOIN_TABLE") 
public class JoinTable { 
    @EmbeddedId 
    private JoinTablePK pkId; 

    private String irrelevantData; 

    @ManyToOne 
    @JoinColumn(name = "MAIN_TABLE_ID", insertable = false, updateable = false) 
    private MainTable mainTable; 

    @ManyToOne 
    @JoinColumn(name = "THIRD_TABLE_ID", insertable = false, updateable = false) 
    private ThirdTable thirdTable; 

    ... 
} 

@Embeddable 
public class JoinTablePK { 
    @Column(name = "MAIN_TABLE_ID") 
    private Long mainTableId; 

    @Column(name = "THIRD_TABLE_ID") 
    private Long thirdTableId; 

    // getters and setters 
} 

insertable = false и updateable = false там, потому что вы отображения двух полей в одной и той же колонке, и для одного столбца может быть только одно записываемое поле.

Я не тестировал код, поэтому я был бы удивлен, если он будет работать так, как он есть, но, надеюсь, он дает вам некоторые рекомендации, которые следует соблюдать, и вы получите по крайней мере несколько шагов ближе к решению ,

+0

Прежде всего, спасибо за ваш ответ. К сожалению, «несущественные дополнительные данные» должны быть сопоставлены, потому что это не имеет отношения к отношениям, но содержащиеся в них данные должны использоваться в коде. Поэтому я попробовал свой второй пример и получил «AnnotationException: JoinTable $ JoinTablePK не имеет постоянного свойства id» Любые идеи? – CMPerez

+0

Я знал, что это не сработает, так как это :) Если вы посмотрите на подобные проблемы, у вас есть getters и seters в классе 'JoinTablePK', для' mainTableId' и 'thirdTableId'? –

+0

@Picacodigos Я добавил код 'JoinTablePK' для справки, чтобы иметь полное изображение и полную базу для следующих попыток –

0

Существует еще один подход, помимо предложенного Предрага Марика. Он подробно описан здесь: http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/

Я добавил этот ответ, если ссылка полезна кому-либо еще. Это мой полный код:

@Entity() 
@Table(name="MAIN_TABLE") 
@Immutable 
public class MainTable extends BusinessEntity implements IMainTable 
{ 
    @Id 
    @Type(type = "LongToNull") 
    @Column(name = "MAIN_TABLE_ID") 
    private long id; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.parentRecord", targetEntity =  JoinTable.class) 
    private List<IJoinTable> joinedRecords = new ArrayList<IJoinTable>(); 
} 

@Entity 
@Table(name = "JOIN_TABLE") 
@AssociationOverrides({ 
    @AssociationOverride(name="pk.parentMainTable", joinColumns = @JoinColumn(name="MAIN_TABLE_ID")), 
    @AssociationOverride(name="pk.parentThirdTable", joinColumns = @JoinColumn(name="THIRD_TABLE_ID")) 
     }) 
public class JoinTable implements Serializable, IJoinTable 
{ 
    private JoinTablePK pkId; 
    private BigDecimal irrelevantData; 

    // Ctor 
    public JoinTable(MainTable mainTable, ThirdTable thirdTable) 
    { 
     pk = new JoinTablePK(mainTable, thirdTable); 
    } 

    @EmbeddedId 
    public JoinTablePK getPk() 
    { 
     return pk; 
    } 

    // here goes the setter, no annotations 

    @Transient 
    public IMainTable getMainTable() 
    { 
     return getPk().getMainTable(); 
    } 

    // here goes the setter, no annotations 

    @Transient 
    public IThirdTable getThirdTable() 
    { 
     return getPk().getThirdTable(); 
    } 

    // here goes the setter, no annotations 

    @Column(name = "JOIN_TABLE_IRRELEVANT_DATA") 
    public BigDecimal getIrrelevantData() 
    { 
     return irrelevantData; 
    } 

    // here goes the setter, no annotations 

    /** 
    * PRIMARY KEY CLASS 
    */ 
    @Embeddable 
    public static class JoinTablePK implements Serializable 
    { 
     private MainTable parentMainTable; 

     @ManyToOne 
     public MainTable getParentMainTable() 
     { 
     return parentMainTable; 
     } 

     // here goes the setter, no annotations 

     private ThirdTable parentThirdTable; 

     @ManyToOne 
     public ThirdTable getParentThirdTable() 
     { 
     return parentThirdTable(); 
     } 

     // here goes the setter, no annotations 

     // empty ctor 
     public JoinTablePK() {} 

     // ctor with parameters 
     public JoinTablePK(MainTable parentMainTable, ThirdTable parentThirdTable) 
     { 
     this.parentMainTable = parentMainTable; 
     this.parentThirdTable = parentThirdTable; 
     } 

     // rest of the class, implement equals() and hashCode() 
    } 
} 
Смежные вопросы