Hibernate如何将String字段映射到数字列

时间:2017-08-08 13:21:57

标签: java oracle hibernate spring-boot

我正在尝试创建一个需要将一些实体存储到Oracle 12c数据库中的SpringBoot 1.5.6应用程序。这些实体仅作为Maven依赖项提供,因此我无法编辑其代码。问题是,这些Entites使用的String ID通过注释映射到整数列,但Hibernate尝试生成失败的String id:

org.hibernate.id.IdentifierGenerationException: Unknown integral data type for ids : java.lang.String

我解决这个问题的方法是使用orm.xml文件覆盖注释,并告诉Hibernate使用Oracle身份标识功能。但是现在它尝试将Identity列创建为varchar2,因此我无法测试它是否有效。我尝试搜索如何指定列定义并找到“type”和“sql-type”但这似乎不起作用。 如何使用orm.xml文件将实体的String字段映射到Oracle中的Identity列? Hibernate甚至可以自动地将一个Identity转换为一个String吗?

到目前为止我的orm.xml:

<?xml version="1.0" encoding="UTF-8" ?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm    
http://java.sun.com/xml/ns/persistence/orm_1_0.xsd"
    version="1.0">
    <entity class="org.owasp.appsensor.core.Attack" name="ATTACK">
        <attributes>
            <id name="id" type="string">
            <column name="id" sql-type="number"/>
                <generated-value strategy="IDENTITY" />
            </id>
        </attributes>
    </entity>
</entityMapping>

其中一个实体(我无法编辑):

package org.owasp.appsensor.core;

import java.util.ArrayList;
import java.util.Collection;

import javax.persistence.*;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.owasp.appsensor.core.rule.Rule;
import org.owasp.appsensor.core.util.DateUtils;

/**
 * An attack can be added to the system in one of two ways:
 * <ol>
 *      <li>Analysis is performed by the event analysis engine and determines an attack has occurred</li>
 *      <li>Analysis is performed by an external system (ie. WAF) and added to the system.</li>
 * </ol>
 *
 * The key difference between an {@link Event} and an {@link Attack} is that an {@link Event}
 * is "suspicous" whereas an {@link Attack} has been determined to be "malicious" by some analysis.
 *
 * @author John Melton (jtmelton@gmail.com) http://www.jtmelton.com/
 */
@Entity
public class Attack implements IAppsensorEntity {

    private static final long serialVersionUID = 7231666413877649836L;

    @Id
    @Column(columnDefinition = "integer")
    @GeneratedValue

    private String id;

    /** User who triggered the attack, could be anonymous user */
    @ManyToOne(cascade = CascadeType.ALL)
    private User user;

    /** Detection Point that was triggered */
    @ManyToOne(cascade = CascadeType.ALL)
    private DetectionPoint detectionPoint;

    /** When the attack occurred */
    @Column
    private String timestamp;

    /**
     * Identifier label for the system that detected the attack.
     * This will be either the client application, or possibly an external
     * detection system, such as syslog, a WAF, network IDS, etc.  */
    @ManyToOne(cascade = CascadeType.ALL)
    private DetectionSystem detectionSystem;

    /**
     * The resource being requested when the attack was triggered, which can be used
     * later to block requests to a given function.
     */
    @ManyToOne(cascade = CascadeType.ALL)
    private Resource resource;

    /** Rule that was triggered */
    @ManyToOne(cascade = CascadeType.ALL)
    private Rule rule;

    /** Represent extra metadata, anything client wants to send */
    @ElementCollection
    @OneToMany(cascade = CascadeType.ALL)
    private Collection<KeyValuePair> metadata = new ArrayList<>();

    public Attack () { }

    public Attack (User user, DetectionPoint detectionPoint, DetectionSystem detectionSystem) {
        this(user, detectionPoint, DateUtils.getCurrentTimestampAsString(), detectionSystem);
    }

    public Attack (User user, DetectionPoint detectionPoint, String timestamp, DetectionSystem detectionSystem) {
        setUser(user);
        setDetectionPoint(detectionPoint);
        setTimestamp(timestamp);
        setDetectionSystem(detectionSystem);
    }

    public Attack (User user, DetectionPoint detectionPoint, String timestamp, DetectionSystem detectionSystem, Resource resource) {
        setUser(user);
        setDetectionPoint(detectionPoint);
        setTimestamp(timestamp);
        setDetectionSystem(detectionSystem);
        setResource(resource);
    }

    public Attack (Event event) {
        setUser(event.getUser());
        setDetectionPoint(event.getDetectionPoint());
        setTimestamp(event.getTimestamp());
        setDetectionSystem(event.getDetectionSystem());
        setResource(event.getResource());
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public User getUser() {
        return user;
    }

    public Attack setUser(User user) {
        this.user = user;
        return this;
    }

    public DetectionPoint getDetectionPoint() {
        return detectionPoint;
    }

    public Attack setDetectionPoint(DetectionPoint detectionPoint) {
        this.detectionPoint = detectionPoint;
        return this;
    }

    public String getTimestamp() {
        return timestamp;
    }

    public Attack setTimestamp(String timestamp) {
        this.timestamp = timestamp;
        return this;
    }

    public DetectionSystem getDetectionSystem() {
        return detectionSystem;
    }

    public Attack setDetectionSystem(DetectionSystem detectionSystem) {
        this.detectionSystem = detectionSystem;
        return this;
    }

    public Resource getResource() {
        return resource;
    }

    public Attack setResource(Resource resource) {
        this.resource = resource;
        return this;
    }

    public Rule getRule() {
        return this.rule;
    }

    public Attack setRule(Rule rule) {
        this.rule = rule;
        return this;
    }

    public Collection<KeyValuePair> getMetadata() {
        return metadata;
    }

    public void setMetadata(Collection<KeyValuePair> metadata) {
        this.metadata = metadata;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder(17,31).
                append(user).
                append(detectionPoint).
                append(timestamp).
                append(detectionSystem).
                append(resource).
                append(metadata).
                toHashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;

        Attack other = (Attack) obj;

        return new EqualsBuilder().
                append(user, other.getUser()).
                append(detectionPoint, other.getDetectionPoint()).
                append(timestamp, other.getTimestamp()).
                append(detectionSystem, other.getDetectionSystem()).
                append(resource, other.getResource()).
                append(metadata, other.getMetadata()).
                isEquals();
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).
                   append("user", user).
                   append("detectionPoint", detectionPoint).
                   append("rule", rule).
                   append("timestamp", timestamp).
                   append("detectionSystem", detectionSystem).
                   append("resource", resource).
                   append("metadata", metadata).
                   toString();
    }

}

尝试创建架构时会产生以下错误:

Hibernate: create table AS_ATTACK (id varchar2(255 char) generated as identity, timestamp varchar2(255 char), detection_point_id varchar2(255 char), detection_system_id varchar2(255 char), resource_id varchar2(255 char), rule_id varchar2(255 char), user_id varchar2(255 char), primary key (id))
14:06:42.880 [main] ERROR o.h.t.h.SchemaExport - HHH000389: Unsuccessful: create table AS_ATTACK (id varchar2(255 char) generated as identity, timestamp varchar2(255 char), detection_point_id varchar2(255 char), detection_system_id varchar2(255 char), resource_id varchar2(255 char), rule_id varchar2(255 char), user_id varchar2(255 char), primary key (id))
 - 14:06:42.881 [main] ERROR o.h.t.h.SchemaExport - ORA-00604: Fehler auf rekursiver SQL-Ebene 1 (= Error on recursive SQL-Level 1)
ORA-06502: PL/SQL: numerischer oder Wertefehler (= numerical or value error)
ORA-06512: in Zeile 17 (= in line 17)
ORA-30675: Identity-Spalte muss einen numerischen Typ aufweisen (= Identity-column must have a numerical type)

1 个答案:

答案 0 :(得分:1)

我通过废弃想法将字符串ID映射到标识列来解决了这个问题。对我有用的解决方案是将varchar2 ID列与序列和触发器结合使用。

orm.xml中:

<entity class="org.owasp.appsensor.core.Attack" name="ATTACK">
    <attributes>
        <id name="id">
            <generated-value strategy="IDENTITY" />
        </id>
    </attributes>
</entity>