简体   繁体   English

使用中间表(中间实体)与两个ManyToOne进行JPA映射

[英]JPA mapping with two ManyToOne using an intermediary table (middle entity)

I am trying to set a JPA mapping with JoinTable, and it seems to be ignored when Hibernate (my JPA implementation) is doing a query. 我正在尝试使用JoinTable设置JPA映射,当Hibernate(我的JPA实现)正在执行查询时,它似乎被忽略了。

To explain the use case 解释用例

Each time a user gets a page of my app, I insert a line in the USAGE_LOG table (with the id of the user and the id of the page). 每次用户访问我的应用页面时,我都会在USAGE_LOG表中插入一行(带有用户ID和页面ID)。

Each page is related to a category (for instance: settings, orders, items, news...) and a type (for instance create, update, display, delete). 每个页面都与一个类别(例如:设置,订单,项目,新闻...)和一个类型(例如创建,更新,显示,删除)相关。

So, I have some kind of middle entity table, that links a page to: a category + a type. 因此,我有某种中间实体表,该表将页面链接到:类别+类型。 Like a triplet: (page, category, type) 像三元组一样:(页面,类别,类型)

My table structure 我的表结构

table USAGE_LOG (for information only, this one works well)
   ID PrimaryKey
   USER_ID Foreign key to column ID of table USER
   USAGE_LOG_PAGE_ID Foreign key to column ID of table USER_LOG_PAGE

table USAGE_LOG_PAGE
   ID PrimaryKey
   URL VARCHAR
   USER_ACTION_ID Foreign key to column ID of table USER_ACTION

table USER_ACTION
   ID PrimaryKey
   ACTION_CATEGORY_ID Foreign key to column ID of table ACTION_CATEGORY
   ACTION_TYPE_ID Foreign key to column ID of table ACTION_CATEGORY

table ACTION_CATEGORY
   ID PrimaryKey
   NAME VARCHAR

table ACTION_TYPE
   ID PrimaryKey
   NAME VARCHAR

So the USER_ACTION table is a join table with the particularity that it links a USAGE_LOG_PAGE to a ACTION_CATEGORY and a ACTION_TYPE at the same time. 因此,USER_ACTION表是一个联接表,其特殊性是它同时将USAGE_LOG_PAGE链接到ACTION_CATEGORY和ACTION_TYPE。

Also, I can have several USAGE_LOG_PAGE that are linked to the same ACTION_CATEGORY and ACTION_TYPE. 另外,我可以有多个USAGE_LOG_PAGE链接到相同的ACTION_CATEGORY和ACTION_TYPE。

Unfortunately, I cannot change the database structure (it is legacy code). 不幸的是,我无法更改数据库结构(它是遗留代码)。

I have tried the following Mappping on the Entity "UsageLogPage" 我已经尝试在实体“ UsageLogPage”上进行以下映射

@ManyToOne
@JoinTable(name="action",
        joinColumns=@JoinColumn(name="ID", referencedColumnName="USER_ACTION_ID"),
        inverseJoinColumns=@JoinColumn(name="ACTION_CATEGORY_ID", referencedColumnName="ID"))
@Getter @Setter
private ActionCategory actionCategory;

@ManyToOne
@JoinTable(name="action",
    joinColumns=@JoinColumn(name="ID", referencedColumnName="USER_ACTION_ID"),
    inverseJoinColumns=@JoinColumn(name="ACTION_TYPE_ID", referencedColumnName="ID"))
@Getter @Setter
private ActionType actionType;

(I use Lombok for @Getter and @Setter) (我将Lombok用于@Getter和@Setter)

This mapping compiles, but when I try to get data, I have the following exception: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'usagelogpa0_.actionCategory' in 'field list' 编译此映射,但是当我尝试获取数据时,出现以下异常:com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException:“字段列表”中的未知列“ usagelogpa0_.actionCategory”

Indeed, the Hibernate query is: 实际上,Hibernate查询是:

select usagelogpa0_.ID as ID1_80_0_,
   usagelogpa0_.actionCategory as actionCa2_80_0_,
   usagelogpa0_.actionType as actionTy3_80_0_,
   usagelogpa0_.URL as URL5_80_0_
from usage_log_page usagelogpa0_
where usagelogpa0_.ID=?

(the key part is the "actionCategory" and "actionType" in the select) (关键部分是选择中的“ actionCategory”和“ actionType”)

This is not what I expect, Hibernate should do a join. 这不是我期望的,Hibernate应该加入。

Have you any idea of what I did wrong? 您知道我做错了什么吗?

Thanks ! 谢谢 !

After lots of investigations, I have found that: 经过大量调查,我发现:

  • it wasn't working as expected because I put the @ManyToOne and the @JoinTable annotations at the attribute level. 它没有按预期工作,因为我将@ManyToOne和@JoinTable批注放在属性级别。 I created a getter by hand and put the annotations on it, and they were taken into account 我手动创建了一个吸气剂,并在上面加上了注释,然后将它们考虑在内
  • it still wasn't working correctly, because Hibernate didn't find the column "USER_ACTION_ID" on the USAGE_LOG_PAGE table, at run time. 它仍然无法正常运行,因为Hibernate在运行时未在USAGE_LOG_PAGE表上找到“ USER_ACTION_ID”列。 This column wasn't in the available fields, for a reason (that I coudn't find). 由于某种原因(我找不到),该列不在可用字段中。 When adding a field "usage_action_id" in the entity "UsageLogPage", it found the attribute, but refused to create the mapping because USAGE_ACTION_ID isn't a primary key. 在实体“ UsageLogPage”中添加字段“ usage_action_id”时,它找到了属性,但是由于USAGE_ACTION_ID不是主键而拒绝创建映射。

At the end, even if I couldn't change the database, I could change the object model. 最后,即使我不能更改数据库,也可以更改对象模型。

So I created the middle entity "UserAction", binded it with ManyToOne on the UsageLogPage entity, removed the attribute "actionCategory" and "actionType" from the UsageLogPage and added them as ManyToOne in the new UserAction entity. 因此,我创建了中间实体“ UserAction”,将其与UsageLogPage实体上的ManyToOne绑定,从UsageLogPage中删除了属性“ actionCategory”和“ actionType”,并将它们作为ManyToOne添加到了新的UserAction实体中。

If you have a table that acts as a middle entity for 2 different ManyToOne relationships, perhaps the best solution is to create the middle entity in your object model. 如果您有一个表充当2个不同的ManyToOne关系的中间实体,那么最好的解决方案是在对象模型中创建中间实体。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM