【问题标题】:Add extra property to intermediary table when mapping many-to-many association with Hibernate与 Hibernate 映射多对多关联时向中间表添加额外属性
【发布时间】:2015-01-13 06:33:48
【问题描述】:

在数据库中,我有以下三个表,其中UserProfile 具有多对多关系,并与User_Profile 连接如下:

User                User_Profile            Profile
----                ------------            ------- 
user_id             user_id                 profile_id
user_name           profile_id              profile_description
user_time

使用UserHbmProfileHbm 类:

@Entity
@Table(name = "User")
public class UserHbm {

    @Id
    @GeneratedValue(generator = "id-generator")
    @GenericGenerator(name = "id-generator",
            strategy = "com.xx.xxx.XXXSequenceGenerator", 
            parameters = { @Parameter(name = "sequenceName", value = "User") })
    @Column(name = "user_id")
    private long user_id;   

    @Column
    private String user_name; 

    @Column
    private Date user_time; 

    @ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
    @JoinTable(name="User_Profile", 
            joinColumns = { @JoinColumn(name = "identityProfileID") },
            inverseJoinColumns={@JoinColumn(name="profile_id")})
    private Set<ProfileHbm> profiles = new HashSet<ProfileHbm>();

    //irrelevant other codes

}

@Entity
@Table(name = "Profile")
public class ProfileHbm {

    @Id
    @GeneratedValue(generator = "id-generator")
    @GenericGenerator(name = "id-generator",
            strategy = "com.xx.xxx.XXXSequenceGenerator", 
            parameters = { @Parameter(name = "sequenceName", value = "Profile") })
    @Column(name = "profile_id")
    private long profile_id;    

    @Column 
    private String profile_description;   

    //irrelevant other codes

}

到目前为止,一切都很好,直到出现新要求:将 user_time 放入 User_Profile 以便架构看起来像:

User                User_Profile            Profile
----                ------------            ------- 
user_id             user_id                 profile_id
user_name           profile_id              profile_description
user_time           user_time

谁能告诉我如何做到这一点?

我是否必须创建另一个中介 HBM 来执行此操作?

【问题讨论】:

  • user_time 中有哪些数据?
  • 只是日期类型的用户更新时间
  • User Table 和 user_profile 表中的 user_time 是否都是相同的数据。 ?如果是这样,您可以从用户表中获取它吗?为什么要再次出现在 user_profile 表中
  • @Ramesh User_Profile 上还有另一个触发器用于审计目的

标签: hibernate jpa join many-to-many


【解决方案1】:

一种解决方案是为 UserProfile 连接表创建一个新实体。
设置从 User 实体到新 UserProfile 实体的 OneToMany 关系以及从 Profile 到 User_Profile 的 OneToMany。
您必须为由 user_id 和 profile_id 组成的复合索引的 User_Profile 实体创建一个附加类,比如说 UserProfilePk。

@Embeddable
public class UserProfilePk {
  @ManyToOne
  private User

  @ManyToOne
  private Profile
}

那么您必须将该类用于 User_Profile 索引:

@Entity
public class UserProfile {
  @EmbeddedId
  private UserProfilePk pk;

  @Column(name = "user_time")
  private Date userTime;

}

您的班级用户:

@Entity
public class User {
  @Id
  private Long id;

  private String name;

  private Date userTime;

  @OneToMany(mappedBy = "pk.user", cascade=CascadeType.ALL)
  private Set<UserProfile> userProfiles;
}

还有班级简介:

@Entity
public class Profile {
  @Id
  private Long id;

  private String description;

  @OneToMany(mappedBy = "pk.profile")
  private Set<UserProfile> userProfiles;
}

下面是保存用户和相关配置文件的代码:

Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.getCurrentSession();

User user = new User();
user.setId(1l);
user.setName("Scott");
user.setUserTime(new Date());
Profile profile = new Profile();
profile.setId(1l);
profile.setDescription("some user");

Transaction tx = session.beginTransaction();     
session.save(profile);

UserProfilePk pk = new UserProfilePk();
pk.setProfile(profile);
pk.setUser(user);

UserProfile userProfile = new UserProfile();
userProfile.setPk(pk);
userProfile.setUserTime(new Date());

Set<UserProfile> ups = new HashSet<>();
ups.add(userProfile);    
user.setUserProfiles(ups);

session.save(user);
tx.commit();

【讨论】:

  • 你能用一些代码解释更多吗?我可以在没有新实体 User_Profile 的情况下这样做吗?
  • 我不知道没有连接表的额外实体的解决方案。
  • 顺便说一句,还有一个问题:如果我不需要在Profile 中使用userProfiles,我还应该在Profile 类中定义吗?我的意思是@OneToMany@ManyToOne 双方都是强制性的吗?
  • 不,如果不需要,可以省略 Profile 类中的 OneToMany。
【解决方案2】:

如果您只需要向映射表添加一个列,您只需更改您的 UserHbm 类。而不是:

@ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)
@JoinTable(name="User_Profile", 
        joinColumns = { @JoinColumn(name = "identityProfileID") },
        inverseJoinColumns={@JoinColumn(name="profile_id")})
private Set<ProfileHbm> profiles = new HashSet<ProfileHbm>();

用途:

@ElementCollection
@JoinTable(name="User_profile")
@MapKeyJoinColumn(name="profile_id")
@Temporal(TemporalType.TIMESTAMP)
@Column(name="user_time")
private Map<Profile, Date> profiles = new HashMap<>();

当您需要在表中放置更多列时,您甚至可以将映射的值更改为 @Embeddable 类。

【讨论】:

    猜你喜欢
    • 2011-07-04
    • 1970-01-01
    • 1970-01-01
    • 2017-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-23
    相关资源
    最近更新 更多