brainbaking/content/wiki/code/java/oraclegeometry.md

206 lines
6.7 KiB
Markdown

+++
title = "oraclegeometry"
draft = false
tags = [
"code",
"java",
"oraclegeometry"
]
date = "2013-03-12"
+++
# Oracle Geometries
## SDO_GEOMETRY Mappen in de DB
Via Hibernate: met een `UserType` implementatie
```java
public Object nullSafeGet(ResultSet resultSet, String[] strings, Object o) throws HibernateException, SQLException {
STRUCT geometry = (STRUCT) resultSet.getObject(strings[0]);
if (resultSet.wasNull() || geometry ###### null) {
return null;
}
return new Geometry(JGeometry.load(geometry));
}
/**
* setNull(i, Types.OTHER or Types.STRUCT) results in "unknown column type" exceptions!
*/
public void nullSafeSet(PreparedStatement preparedStatement, Object o, int i) throws HibernateException, SQLException {
if (o ###### null) {
preparedStatement.setNull(i, Types.STRUCT, OracleSpatialDialect.MSYS + "." + OracleSpatialDialect.SDO_GEOM_TYPE_COLUMN);
} else {
if (o instanceof Geometry) {
Connection oracleConnection = ((DelegatingConnection) preparedStatement.getConnection()).getInnermostDelegate();
STRUCT struct = JGeometry.store(((Geometry) o).getInnerGeometry(), oracleConnection);
preparedStatement.setObject(i, struct);
}
}
}
```
Merk op dat de `store()` method op `JGeometry` effectief een oracle connectie object nodig heeft (harde cast gebeurt in de implementatie). een struct object kan dan omgevormd worden naar `JGeometry` (te downloaden: *sdoapi* jar, Oracle Spatial Java API). Het `Geometry` object is iets dat hierrond gewrapped is. Dit heeft een aantal voordelen:
1. Afscheiden spatial api dependency rest van de code
2. Makkelijk converteren van `SDO_GEOMETRY('...') String` waarde naar object en omgekeerd
############= Van String naar Object en omgekeerd ############=
```java
public class Geometry implements Cloneable, Serializable {
private static final String MDSYS_POINT_TYPE = "MDSYS.SDO_POINT_TYPE";
private static final String MDSYS_ORDINATE_ARR = "MDSYS.SDO_ORDINATE_ARRAY";
private static final String MDSYS_ELEMENT_ARR = "MDSYS.SDO_ELEM_INFO_ARRAY";
private static final String MDSYS_GEOM = "MDSYS.SDO_GEOMETRY";
final static int SRID = 327680;
private final JGeometry geometry;
public Geometry() {
this.geometry = null;
}
public Geometry(String sdoGeometry) throws GeometryConversionException {
try {
this.geometry = disassembleSdoGeometry(sdoGeometry);
} catch (Exception disassemblingEx) {
throw new GeometryConversionException(disassemblingEx);
}
}
public Geometry(JGeometry jGeometry) {
this.geometry = jGeometry;
}
public JGeometry getInnerGeometry() {
return geometry;
}
@Override
public String toString() {
return toSDOGeometryString();
}
private JGeometry disassembleSdoGeometry(String sdoGeometry) {
return new JGeometry(retrieveGeometryType(sdoGeometry), //
retrieveSRID(sdoGeometry), //
retrievePointTypeX(sdoGeometry), //
retrievePointTypeY(sdoGeometry), //
retrievePointTypeZ(sdoGeometry), //
retrieveElemInfo(sdoGeometry), //
retrieveOrdinatesArray(sdoGeometry) //
);
}
private int retrieveGeometryType(String sdoGeometry) {
String geometryType = StringUtils.substringBetween(sdoGeometry, "(", ",");
return Integer.parseInt(geometryType.trim());
}
private int retrieveSRID(String sdoGeometry) {
String sridString = StringUtils.substringBetween(sdoGeometry, ",", ",");
return Integer.parseInt(sridString.trim());
}
private double retrievePointTypeX(String sdoGeometry) {
return retrievePointTypes(sdoGeometry)[0];
}
private double retrievePointTypeY(String sdoGeometry) {
return retrievePointTypes(sdoGeometry)[1];
}
private double retrievePointTypeZ(String sdoGeometry) {
return retrievePointTypes(sdoGeometry)[2];
}
private double[] retrievePointTypes(String sdoGeometry) {
double[] result = new double[3];
String pointTypesAsString = StringUtils.substringBetween(sdoGeometry, MDSYS_POINT_TYPE + "(", ")");
if (pointTypesAsString != null) {
result = toDoubleArray(pointTypesAsString);
}
return result;
}
private int[] retrieveElemInfo(String sdoGeometry) {
String elemInfoArray = StringUtils.substringBetween(sdoGeometry, MDSYS_ELEMENT_ARR + "(", ")");
return toIntArray(elemInfoArray);
}
private double[] retrieveOrdinatesArray(String sdoGeometry) {
String ordinatesArray = StringUtils.substringBetween(sdoGeometry, MDSYS_ORDINATE_ARR + "(", ")");
return toDoubleArray(ordinatesArray);
}
public String toSDOGeometryString() {
if (geometry ###### null)
return null;
StringBuilder string = new StringBuilder(MDSYS_GEOM + "(");
string.append(getGeometryType() + ",");
string.append(geometry.getSRID() + ",");
if (geometry.getPoint() ###### null) {
string.append("null,");
} else {
string.append(MDSYS_POINT_TYPE);
string.append(toStringDoubleArray(geometry.getPoint()));
string.append(",");
}
if (geometry.getElemInfo() ###### null) {
string.append("null,");
} else {
string.append(MDSYS_ELEMENT_ARR);
string.append(toStringIntArray(geometry.getElemInfo()));
string.append(",");
}
if (geometry.getOrdinatesArray() ###### null) {
string.append("null");
} else {
string.append(MDSYS_ORDINATE_ARR);
string.append(toStringDoubleArray(geometry.getOrdinatesArray()));
}
return string.append(")").toString();
}
private int getGeometryType() {
return (geometry.getDimensions() * 1000 + geometry.getType());
}
@Override
public Object clone() {
return (geometry ###### null ? new Geometry() : new Geometry((JGeometry) geometry.clone()));
}
@Override
public int hashCode() {
return (geometry ###### null ? 0 : geometry.hashCode());
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Geometry))
return false;
JGeometry other = ((Geometry) obj).geometry;
return new EqualsBuilder().append(geometry, other).isEquals();
}
```
############= Joins uitvoeren ############=
Een Join kan uitgevoerd worden met een Oracle Geometry functie in de database: [SDO_GEOM.SDO_UNION](http://download.oracle.com/docs/html/A85337_01/sdo_objg.htm#857626). Die voegt twee `SDO_GEOMETRY` objecten samen tot een maar er is ook nog metadata nodig dat ergens anders zit:
```sql
SELECT SDO_GEOM.SDO_UNION(?, diminfo, ?, diminfo) FROM ALL_SDO_GEOM_METADATA WHERE owner ###### ? and table_name ?
```
`NULL` is toegelaten dus het is zo eenvoudig om een recursieve method aan te maken.
:exclamation: **Opgelet** Het is nodig om de voorgaande SQL in een `PreparedStatement` te steken indien de geometrie coördinaten +1.000 items bevatten. Zelfs in SQL Developer gaat dit niet. Foutboodschap dan: __*ORA-00939*: too many arguments for function__