当审核表没有具有ID的记录时,hibernate会抛出未找到的实体异常

时间:2018-10-15 17:54:02

标签: hibernate-envers

帐户实体

@Getter
@Accessors(chain = true, fluent = true)
@NoArgsConstructor
@AllArgsConstructor(staticName = "of")
@ToString(of = {"customerName"}, callSuper = true)
@Entity

@Table(name = "ACCOUNTS", 
    uniqueConstraints = @UniqueConstraint(name = UNQ_CUSTOMER_NAME, columnNames = { "CUSTOMER_NAME" }),
    indexes = { 
            @Index(name = IDX_CUSTOMER_ENTITY, columnList = "CUSTOMER_ENTITY")  
    }
)

public class Account extends BaseAutoAssignableVersionableEntity<String, Long> implements Diffable<Account> {

public static final String CUSTOMER_ENTITY = "Customer Entity";
public static final String CUSTOMER_REPORTING_MANAGER = "Customer Reporting Manager";
public static final String CUSTOMER_NAME = "Customer Name";
public static final String ACCOUNT_MANAGER = "Account Manager";
public static final String CITY = "City";
public static final String CUSTOMER_TIME_TRACKING = "Customer Time Tracking";

@NotNull
@Column(name = "CUSTOMER_NAME", nullable = false, length = 150)
@Audited(withModifiedFlag = true)
private String customerName; // Unique

@NotNull
@Size(min = 1, max = 4)
@Column(name = "CUSTOMER_GROUP", nullable = false, length = 4)
@Audited(withModifiedFlag = true)
private String customerGroup;

// @NotNull
@Column(name = "CUSTOMER_ENTITY", nullable = true, length = 150)
@Audited(withModifiedFlag = true)
private String customerEntity; // customer entity is optional and can be same for multiple accounts

@NotNull
@Column(name = "CUSTOMER_REPORTING_MANAGER", nullable = false, length = 150)
@Audited(withModifiedFlag = true)
private String customerReportingManager;

@Column(name = "CUSTOMER_TIME_TRACKING", length = 1)
@Audited(withModifiedFlag = true)
private boolean customerTimeTracking = false;

@NotNull
@OneToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "ACCOUNT_MANAGER_CODE", unique = false, nullable = false, foreignKey = @ForeignKey(name = FK_ACCOUNTS_MGR_RESOURCE_CODE))
@Audited(withModifiedFlag = true, targetAuditMode = RelationTargetAuditMode.NOT_AUDITED, modifiedColumnName = "ACCOUNT_MANAGER_CODE_MOD")
private Resource accountManager;

资源实体

@Getter
@Accessors(chain = true, fluent = true)
@NoArgsConstructor
@ToString(of = { "name" }, callSuper = true)
@Entity
// @formatter:off
@Table(name = "RESOURCES", 
    uniqueConstraints = {
        @UniqueConstraint(name = UNQ_RESOURCES_LOGIN_ID, columnNames = {"LOGIN_ID"}),
        @UniqueConstraint(name = UNQ_RESOURCES_EMAIL_ID, columnNames = {"EMAIL_ID"}),
        @UniqueConstraint(name = UNQ_RESOURCES_PAYROLL_ID, columnNames = {"PAYROLL_ID"})
    },
    indexes = { 
        @Index(name = IDX_RESOURCES_NAME, columnList = "NAME")    
    }
)
// @formatter:on
public class Resource extends BaseAutoAssignableVersionableEntity<String, Long> implements Diffable<Resource> {

public static final String EMAIL_ID = "Email ID";
public static final String GRAYT_HR_ID = "Grayt HR ID";
public static final String NAME = "Name";
public static final String GENEDER = "Gender";
public static final String DESIGNATION = "Designation";
public static final String TYPE_OF_RESOURCE = "Resource Type";
public static final String STATUS_OF_RESOURCE = "Resource Status";
public static final String BASE_LOCATION = "Base Location";
public static final String DEPUTED_LOCATION = "Deputed Location";
public static final String PRIMARY_SKILLS = "Primary Skills";
public static final String SECONDARY_SKILLS = "Secondary Skills";
public static final String EXPECTED_JOINING_DATE = "Expected Joining Date";
public static final String ACTUAL_JOINING_DATE = "Actual Joining Date";
public static final String EXIST_DATE = "Exist Date";

// @Pattern(regexp = REGEX_LOGIN_ID, message = MESSAGE_LOGIN_ID_INVALID)
// @NotNull(message = MESSAGE_LOGIN_ID_MANDATORY)
@Column(name = "LOGIN_ID", nullable = false, length = 100)
private String loginId;

@Email(message = MESSAGE_EMAIL_INVALID)
@Column(name = "EMAIL_ID", nullable = true, length = 255)
@Audited(withModifiedFlag = true)
private String emailId;

@Pattern(regexp = REGEX_PAYROLL_ID, message = MESSAGE_PAYROLL_ID_INVALID)
@Column(name = "PAYROLL_ID", nullable = true, length = 100)
@Audited(withModifiedFlag = true, modifiedColumnName = "PAYROLL_ID_MOD")
private String payrollId;

@NotNull
@Column(name = "NAME", nullable = false, length = 255)
@Audited(withModifiedFlag = true)
private String name;

@NotNull
@Enumerated(EnumType.STRING)
@Column(name = "GENDER", nullable = false, length = 10)
@Audited(withModifiedFlag = true)
private Gender gender;

@NotNull
@OneToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "DESIGNATION_ID", unique = false, nullable = false, foreignKey = @ForeignKey(name = FK_RESOURCES_DESIGNATION_ID))
@Audited(withModifiedFlag = true, targetAuditMode = RelationTargetAuditMode.NOT_AUDITED, modifiedColumnName = "DESIGNATION_ID_MOD")
private Designation designation;

@NotNull
@OneToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "EMP_TYPE_CODE", unique = false, nullable = false, foreignKey = @ForeignKey(name = FK_RESOURCES_EMP_TYPE_CODE))
@Audited(withModifiedFlag = true, targetAuditMode = RelationTargetAuditMode.NOT_AUDITED, modifiedColumnName = "EMP_TYPE_CODE_MOD")
private EmploymentType employmentType;

public boolean isFTE() {
    return (this.employmentType.equals(EmploymentType.fullTimeEmployee()));
}

@Audited(withModifiedFlag = true,  modifiedColumnName = "EMP_STATUS_ID_MOD")
@OneToOne(optional = false, cascade = CascadeType.PERSIST, orphanRemoval = true)
@JoinColumn(name = "emp_status_id", unique = false, foreignKey = @ForeignKey(name = FK_RESOURCES_EMP_STATUS_ID))
private EmploymentStatus employmentStatus;

创建帐户时,请使用现有资源作为帐户管理员并成功创建。然后成功获取历史记录。但是很遗憾,删除了resource_aud表中的资源记录,然后获取了历史记录。它抛出错误以下

javax.persistence.EntityNotFoundException: Unable to find com.gspann.itrack.domain.model.staff.Resource with id IN10000
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:159)
at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:244)
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:166)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:268)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)
at com.gspann.itrack.domain.model.staff.Resource_$$_jvst4e_12.name(Resource_$$_jvst4e_12.java)
at com.gspann.itrack.domain.model.business.Account.diff(Account.java:328)
at com.gspann.itrack.domain.model.business.Account.diff(Account.java:1)
at com.gspann.itrack.domain.model.common.audit.util.AuditQueryUtils.getAllRevisionById(AuditQueryUtils.java:66)
at com.gspann.itrack.domain.service.impl.AccountManagementServiceImpl.getAllRevisionByAccountCode(AccountManagementServiceImpl.java:268)

下面是由休眠envers生成的查询

/* select
    e__,
    r 
from
    com.gspann.itrack.domain.model.business.Account_AUD e__,
    com.gspann.itrack.audit.domain.CustomRevisionEntity r 
where
    e__.REVTYPE <> :_p0 
    and e__.originalId.code = :_p1 
    and e__.originalId.REV.id = r.id 
order by
    e__.originalId.REV.id asc */ select
        account_au0_.code as code1_1_0_,
        account_au0_.rev as rev2_1_0_,
        customrevi1_.id as id1_49_1_,
        account_au0_.revtype as revtype3_1_0_,
        account_au0_.customer_entity as customer4_1_0_,
        account_au0_.customer_entity_mod as customer5_1_0_,
        account_au0_.customer_group as customer6_1_0_,
        account_au0_.customer_group_mod as customer7_1_0_,
        account_au0_.customer_name as customer8_1_0_,
        account_au0_.customer_name_mod as customer9_1_0_,
        account_au0_.customer_reporting_manager as custome10_1_0_,
        account_au0_.customer_reporting_manager_mod as custome11_1_0_,
        account_au0_.customer_time_tracking as custome12_1_0_,
        account_au0_.customer_time_tracking_mod as custome13_1_0_,
        account_au0_.account_manager_code as account14_1_0_,
        account_au0_.account_manager_code_mod as account15_1_0_,
        account_au0_.country_code as country16_1_0_,
        account_au0_.country_code_mod as country17_1_0_,
        customrevi1_.last_modified_on as last_mod2_49_1_,
        customrevi1_.modified_by as modified3_49_1_,
        customrevi1_.timestamp as timestam4_49_1_ 
    from
        accounts_aud account_au0_ cross 
    join
        revinfo customrevi1_ 
    where
        account_au0_.revtype<>? 
        and account_au0_.code=? 
        and account_au0_.rev=customrevi1_.id 
    order by
        account_au0_.rev asc

调用资源的getter方法后,它会生成另一个与资源相关的查询,如下所示

/* select
    e__ 
from
    com.gspann.itrack.domain.model.staff.Resource_AUD e__ 
where
    e__.originalId.REV.id = (
        select
            max(e2__.originalId.REV.id) 
        from
            com.gspann.itrack.domain.model.staff.Resource_AUD e2__ 
        where
            e2__.originalId.REV.id <= :revision 
            and e__.originalId.code = e2__.originalId.code
    ) 
    and e__.REVTYPE <> :_p0 
    and e__.originalId.code = :_p1 */ select
        resource_a0_.code as code1_48_,
        resource_a0_.rev as rev2_48_,
        resource_a0_.revtype as revtype3_48_,
        resource_a0_.actual_joining_date as actual_j4_48_,
        resource_a0_.actual_joining_date_mod as actual_j5_48_,
        resource_a0_.email_id as email_id6_48_,
        resource_a0_.email_id_mod as email_id7_48_,
        resource_a0_.exit_date as exit_dat8_48_,
        resource_a0_.exit_date_mod as exit_dat9_48_,
        resource_a0_.gender as gender10_48_,
        resource_a0_.gender_mod as gender_11_48_,
        resource_a0_.name as name12_48_,
        resource_a0_.name_mod as name_mo13_48_,
        resource_a0_.payroll_id as payroll14_48_,
        resource_a0_.payroll_id_mod as payroll15_48_,
        resource_a0_.utilization as utiliza16_48_,
        resource_a0_.utilization_mod as utiliza17_48_,
        resource_a0_.utilization_type as utiliza18_48_,
        resource_a0_.utilization_type_mod as utiliza19_48_,
        resource_a0_.base_loc_id as base_lo20_48_,
        resource_a0_.base_loc_id_mod as base_lo21_48_,
        resource_a0_.deputed_loc_id as deputed22_48_,
        resource_a0_.deputed_loc_id_mod as deputed23_48_,
        resource_a0_.designation_id as designa24_48_,
        resource_a0_.designation_id_mod as designa25_48_,
        resource_a0_.emp_status_id as emp_sta26_48_,
        resource_a0_.emp_status_id_mod as emp_sta27_48_,
        resource_a0_.emp_type_code as emp_typ28_48_,
        resource_a0_.emp_type_code_mod as emp_typ29_48_,
        resource_a0_.image_id as image_i30_48_,
        resource_a0_.image_id_mod as image_i31_48_ 
    from
        resources_aud resource_a0_ 
    where
        resource_a0_.rev=(
            select
                max(resource_a1_.rev) 
            from
                resources_aud resource_a1_ 
            where
                resource_a1_.rev<=? 
                and resource_a0_.code=resource_a1_.code
        ) 
        and resource_a0_.revtype<>? 
        and resource_a0_.code=?

下面是获取修订的代码

AuditReader auditReader = this.getAuditReader();
    return auditReader.createQuery().forRevisionsOfEntity(clazz, selectedEntitiesOnly, selectDeletedEntities);

我的问题是,为什么它引用审计表而不是主表?

预先感谢

0 个答案:

没有答案