我正在将一些带有NHibernate XML映射的C#转换为带有Annotations映射的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对象失败,并显示“无法初始化集合”错误。这是我最好的代码,因为其他尝试使我的所有测试失败,因为当你的映射错误时会发生。
答案 0 :(得分: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
是因为您将两个字段映射到同一列,并且一列只能有一个可写字段。
我没有对代码进行测试,所以如果它能够正常工作,我会感到惊讶,但希望它能为您提供一些指导方针,并且您至少可以向解决方案迈进几步。
答案 1 :(得分:0)
除了Predrag Maric建议的另一种方法之外,还有另外一种方法。这里详细说明: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()
}
}