Hibernate:无外键约束的映射

问题描述 投票:0回答:1

我有一个

eventchangelog
表和一个
user
表,我正在尝试根据用户名列将
User
对象映射到 eventChangeLog 条目。 user 表将 username 作为唯一字段,但出于业务原因,我无法在 eventchangelog.createdby 和 user.username 之间添加外键约束。

问题

我只想将用户名存储在 eventchangelog 中,但希望 Hibernate 在获取 EventChangeLog 条目时加载整个 User 对象(名字、姓氏、用户名等)。但是,除非我在 HQL 查询中使用构造函数,否则我在将 User 映射到我的 EventChangeLog 类时遇到问题。

这是我正在处理的内容: EventChangeLog 类

@NoArgsConstructor
@Getter
@Setter
public class EventChangeLog {
    private long id;
    private Event event;
    private String createdByUsername;
    private User createdBy;
    
    // Constructor initializes all fields except `id`
}

EventChangeLog Hibernate 映射

<hibernate-mapping>
    <class name="org.event.EventChangeLog" table="eventchangelog">
        <id name="id" column="eventchangelogid">
            <generator class="sequence">
                <param name="sequence_name">eventchangelog_sequence</param>
            </generator>
        </id>
        <many-to-one name="event" class="org.event.Event"
                     column="eventid" foreign-key="fk_eventchangelog_eventid" not-null="true"/>
        <property name="createdByUsername" column="createdby" type="string"/>
        <many-to-one name="createdBy" class="org.event.User" insert="false" update="false" property-ref="username">
            <column name="createdby"/>
        </many-to-one>
    </class>
</hibernate-mapping>

用户类别

@NoArgsConstructor
@Getter
@Setter
public class User {
    private String username;
    private String surname;
    private String firstName;
}

用户休眠映射

<hibernate-mapping>
    <class name="org.event.User" lazy="false" table="userinfo">
        <property name="username" column="username" not-null="true" unique="true"/>
        <property name="surname" not-null="false" length="160"/>
        <property name="firstName" not-null="false" length="160"/>
    </class>
</hibernate-mapping>

尝试查询

When I use this HQL query with a constructor, it maps everything correctly:

String hql = """
    select new org.event.EventChangeLog(
        ecl.event,
        ecl.createdByUsername,
        ecl.createdBy
    )
    from EventChangeLog ecl
    join ecl.event e
    left join ecl.createdBy
    where e.uid = :eventUid
""";

但是,如果我使用以下查询(应直接映射到 EventChangeLog),则不会映射 User 对象 (createdBy):

String hql = """
    select ecl
    from EventChangeLog ecl
    join ecl.event e
    left join ecl.createdBy
    where e.uid = :eventUid
""";

我尝试过的事情

  1. 外键约束:由于业务限制,添加外键不起作用。
  2. 主键映射:通过 user.id 进行映射也不起作用。
  3. Eager 与 Lazy Fetching:两种方法都没有改变结果。
  4. 使用 CriteriaQuery 而不是 HQL:结果相同;未获取用户。
  5. Hibernate 日志:连接查询似乎是正确的,并且在两种情况下看起来完全相同,因此我怀疑问题出在映射配置中。

如何配置 Hibernate 以使用

User
列将
EventChangeLog
对象映射到
username
,而不在 HQL 查询中使用构造函数?

java hibernate
1个回答
0
投票

在 HQL 查询中,您可以使用自定义结果转换器在 EventChangeLog 上手动设置 User 对象,而不是依赖 Hibernate 自动映射 User 对象。即使没有外键约束,这种方法也允许您检索所需的字段并映射它们(通过设置 ResultTransformer)。

以下是如何执行此操作的示例:

Query query = session.createQuery("""
    select ecl.id, ecl.event, ecl.createdByUsername, u
    from EventChangeLog ecl
    join ecl.event e
    left join User u on ecl.createdByUsername = u.username
    where e.uid = :eventUid
""");

query.setParameter("eventUid", eventUid);
query.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE);

List<EventChangeLog> results = query.list();

如果您想更改所选数据,您可以有一个匹配的 DTO 类并调用:

query.setResultTransformer(new AliasToBeanResultTransformer(EventChangeLogDTO.class));

此方法显式获取 EventChangeLog 字段和关联的 User,然后在 EventChangeLog 上手动设置 User 对象。

© www.soinside.com 2019 - 2024. All rights reserved.