执行查询时双向@OneToOne导致N + 1

时间:2013-12-04 12:09:00

标签: hibernate

当我在非拥有方(User)上添加@OneToOne映射时,我在执行查询时会额外选择加载Staff。一旦我删除了用户类中的@OneToOne,就解决了N + 1问题。

User.staff设置为lazy,因此不应该尝试加载它。

我缺少什么,或双向关联总是如此?

/* named HQL query Staff.findByName */ 
/* load com.xxx.Staff */
/* load com.xxx.Staff */
/* load com.xxx.Staff */

PS。用户不一定是工作人员,但工作人员必须是用户。

员工班级

@Entity
@Table(name = "staff")
@NamedQueries({
@NamedQuery(name = Staff.QUERY_BY_NAME, query = "from Staff s left join fetch s.user u left join fetch u.staff where (lower(s.user.displayName) like :key) or (lower(s.user.lastName) like :key)")})
public class Staff extends AbstractDomainObject<Long> {
    public static final String QUERY_BY_NAME = "Staff.findByName";

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @OneToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "user_id")
    private User user;

用户类

@Entity
@Table(name = "env_user")
@SecondaryTable(name = "app_user")
public class User extends AbstractUserDetailsDomainObject<Long> {
    public static final String QUERY_BY_USERNAME = "User.findByUsername";

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;


    @OneToOne(optional = true, fetch = FetchType.LAZY, mappedBy = "user")
    private Staff staff;
}

1 个答案:

答案 0 :(得分:0)

感谢Alan Hay提供解决方案的链接。我选择的最干净的解决方案是使用FieldHandled。 @OneToMany破坏了逻辑结构,仪器的东西很容易被未来的开发人员遗忘和遗忘。

public class User extends AbstractUserDetailsDomainObject<Long> implements FieldHandled {
    public static final String QUERY_BY_USERNAME = "User.findByUsername";
    /**
     * <p>
     * Required to allow lazy loading of Staff @OneToOne association
     * </p>
     */
    private FieldHandler fieldHandler;

    @OneToOne(mappedBy = "user", fetch = FetchType.LAZY, optional = true)
    @LazyToOne(LazyToOneOption.NO_PROXY)
    private Staff staff;

   /**
     * <p>
     * Staff Getter
     * </p>
     * Uses fieldhandler to force lazy loading
     * 
     * @return the staff
     */
    public Staff getStaff() {
        Staff result = this.staff;
        if (this.fieldHandler != null) {
            result = (Staff) this.fieldHandler.readObject(this, "staff", this.staff);
        }
        return result;
    }

    /**
     * <p>
     * Staff Setter
     * </p>
     * Uses fieldhandler to force lazy loading
     * 
     * @param staff
     *            the staff to set
     */
    public void setStaff(final Staff staff) {
        if (this.fieldHandler != null) {
            this.staff = (Staff) this.fieldHandler.writeObject(this, "staff", this.staff, staff);
        } else {
            this.staff = staff;
        }
    }

    /**
     * <p>
     * FieldHandled interface method.
     * </p>
     * Required to allow lazy loading of Staff @OneToOne association
     */
    public FieldHandler getFieldHandler() {
        return this.fieldHandler;
    }

    /**
     * <p>
     * FieldHandled interface method.
     * </p>
     * Required to allow lazy loading of Staff @OneToOne association
     */
    public void setFieldHandler(final FieldHandler fieldHandler) {
        this.fieldHandler = fieldHandler;

    }

}