我正在尝试创建一个需要将一些实体存储到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)
答案 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>