Current Revision posted to Bentley Map | OpenCities Map Wiki by Inga Morozoff on 3/9/2020 6:48:51 PM
The purpose of this entry is to describe the design of Oracle Views for the definition of spatial features used by Bentley Geospatial products ( ie Bentley Map, Bentley Electric, Bentley Gas, Bentley Water, GeoWeb Publisher, and the Oracle Spatial Connector for ProjectWise) to solve a need to both separate and share business and GIS data.
Classical examples of the definition of Oracle spatial tables include both the geometry and the business attributes into the same spatial table. This can, at existing installations, where business data already exists, cause problems with the setup of the spatial tables.
What is needed is a way to ‘reference’ the business data to the spatial data and allow the business data to be maintained, not only by the GIS user, but also by the current business data users.
Some of the requirements for this solution may be:
· The business table is maintained by some person or group outside of the GIS department (we will call this the BUSINESS department).
· The spatial data (geometry) is maintained by the GIS department.
· The GIS users will benefit from at least viewing and searching on the business data.
· The BUSINESS department will benefit by at least viewing and searching on the spatial data.
· Some (or all) business data can be maintained by the GIS users.
· Some (or all) business data can be maintained by the BUSINESS department.
· Do not duplicate the business data into the GIS spatial data.
In summarizing these requirements, there seems to be a need to separate and consolidate the business and spatial data without sacrificing good database design and data integrity.
We will investigate the usage of Oracle Views as one of the solutions to solving this problem. The basic design will comprise of:
1. Creation of the spatial geometry table, including spatial indexes and metadata entries.
2. Loading of existing spatial data into the geometry table.
3. Creation of the view, as a join between the business data and the spatial data, including the creation of the metadata entries.
4. Creation of the triggers to maintain the data between the view and the actual tables.
When finished we will have the business and spatial data separated, but also viewed as a consolidated dataset, that will be maintainable by either the BUSINESS or GIS departments.
Step 1 – Creation of the spatial geometry table
As described in the Bentley Map help file, a spatial table must meet the 4 following requirements.
· The feature table must have a primary key constraint consisting of a single numeric or string/character column to represent the feature ID. This primary key is required to enable versioning using the standard versioning system of the Oracle Workspace Manager.
· The table must have a geometric (SDO_GEOMETRY) column specifying the feature geometry, and this geometry column must be registered in the Oracle Spatial metadata table (ALL_SDO_GEOM_METADATA or the related USER_SDO_GEOM_METADATA view for the user).
· The table fields must be of a common type, not a user defined type.
· Geometry must be of similar types, meaning all geometries must be of point, line, or polygon type, not a mixture of these.
Along with these basic requirements, point features have the following OPTIONAL needs because point features ( text and cells in Microstation) have additional geometric requirements.
· Since there is a rotation value for both text and cells, for their graphical display, there can also be a optional rotation field defined. This can be placed in the spatial table or the business table, but I would suspect that this will be placed in the spatial table, just to keep the spatial data together. For the purpose of this exercise we will call this field ‘ROTATION’, it will be numeric field.
· Since there is also a X and Y scale factor for point features (text and cell), we will also add these fields to a point feature spatial table. We will call these X_SCALE and Y_SCALE and make them numeric also.
If these fields are not defined, for point features, then when data is retrieved from the spatial database and plotted in the drawing ( or displayed in some other fashion), the point feature will always plot at a angle of 0 degrees (or radians) and at a scale of 1 (or text height/width of 1). This is probably not desirable for most types of output.
spatial table definitions
CREATE TABLE
point_feat_geom
(
rec_id NUMBER(22), // used to link to the business table
geometry MDSYS.SDO_GEOMETRY, // required Oracle geometry object
rotation NUMBER, // optional point feature rotation
x_scale NUMBER, // optional point feature x scale
y_scale NUMBER // optional point feature y scale
);
The polyline and polygon tables will look the same as the point feature, except it will not contain the optional columns that can be used for a point feature.
CREATE TABLE
polyline_feat_geom
(
rec_id NUMBER(22), // used to link to the business table
geometry MDSYS.SDO_GEOMETRY // required Oracle geometry object
);
CREATE TABLE
polygon_feat_geom
(
rec_id NUMBER(22), // used to link to the business table
geometry MDSYS.SDO_GEOMETRY // required Oracle geometry object
);
Entry into the SDO_GEOM_METADAtA table.
Now that we have the spatial table defined, we need to add entries into the SDO_GEOM_METADATA table so that Oracle can perform operations on these tables. This satisfies the second bullet item above. These entries are:
INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID)
VALUES ('point_feat_geom', 'geometry',
MDSYS.SDO_DIM_ARRAY
(
MDSYS.SDO_DIM_ELEMENT('X', -5000000, 5000000, 0.000000050),
MDSYS.SDO_DIM_ELEMENT('Y', -5000000, 5000000, 0.000000050)
),
NULL);
INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID)
VALUES ('polyline_feat_geom', 'geometry',
MDSYS.SDO_DIM_ARRAY
(
MDSYS.SDO_DIM_ELEMENT('X', -5000000, 5000000, 0.000000050),
MDSYS.SDO_DIM_ELEMENT('Y', -5000000, 5000000, 0.000000050)
),
NULL);
INSERT INTO USER_SDO_GEOM_METADATA (TABLE_NAME, COLUMN_NAME, DIMINFO, SRID)
VALUES ('polygon_feat_geom', 'geometry',
MDSYS.SDO_DIM_ARRAY
(
MDSYS.SDO_DIM_ELEMENT('X', -5000000, 5000000, 0.000000050),
MDSYS.SDO_DIM_ELEMENT('Y', -5000000, 5000000, 0.000000050)
),
NULL);
Creation of the Spatial indexes
Now we want to define the spatial indexes for each of these tables. The spatial index assists in the retrieval of the data for spatial operations (view, fence, etc.).
CREATE INDEX point_feature_sidx ON point_feat_geom(geometry)
INDEXTYPE IS mdsys.spatial_index
PARAMETERS ('layer_gtype=point');
CREATE INDEX polyline_feature_sidx ON polyline_feat_geom(geometry)
INDEXTYPE IS mdsys.spatial_index
PARAMETERS ('layer_gtype=line’);
CREATE INDEX polyline_feature_sidx ON polyline_feat_geom(geometry)
INDEXTYPE IS mdsys.spatial_index
PARAMETERS ('layer_gtype=polygon’);
Ok, we are done with the table creations. Notice that I did not create a primary key on these tables, which is a requirement for the spatial tables, as per Bentley Map. For this implementation, the primary key is assigned to the views and not to the geometry table, since we are combining multiple tables into the view.
Next we want to review the business table.
Step 2 – Business table definition
We are assuming that the business table is already created and possibly populated. The business table for this example is defined as follows:
CREATE TABLE point_feat_prop
(
unique_id NUMBER(22), // Unique identifier for the business table records
StringValue VARCHAR2(16), // String value
NumberValue NUMBER(32), // Numeric value
DateValue DATE // Date value
);
Now that we have the business and spatial tables defined, we can define the view that links these 2 tables together. Note the same basic process can be used for the polyline and polygon tables.
To link these together we are going to use the rec_id column in the spatial table with the unique_id column in the business table.
Create view
point_feat_vw AS
SELECT
p.unique_id unique_id,
p. StringValue stringValue,
p. NumberValue numberValue,
p. DateValue dateValue,
g.geometry geometry,
g.rotation rotation,
g.x_scale x_scale,
g.y_scale y_scale
FROM
point_feat_prop p, point_feat_geom g
WHERE
p.unique_id = g.rec_id;
Since we have the view created, we need to now finish defining a couple of more items, so that the Geospatial Administrator and Bentley Map will recognize this as a spatial table.
Remember earlier Bentley Map requires a primary key be defined on the spatial table, for the purpose of allowing Oracle to create versions of the data. But we cannot by default have a primary key active on a view. To get around this we create the primary key, but we disable it, by the following:
ALTER VIEW point_feat_vw ADD PRIMARY KEY(unique_id) DISABLE;
Entry to the SDO_GEOM_METADATA table.
Ok, the last task is to add a entry into the SDO_GEOM_METADATA table. This is done as follows:
INSERT INTO
user_sdo_geom_metadata
SELECT
'point_feat_vw',
column_name,
diminfo,
srid
FROM
user_sdo_geom_metadata
WHERE
table_name = 'POINT_FEAT_GEOM';
Step 4 – Setting up the Triggers
Since we are doing selects, deletes, inserts and updates into a view and not the parent tables, we need to create some triggers that properly manipulate the data. Therefore we will be creating a trigger for inserts, updates and deletes on the view.
We redirect the insertion of the data from the view into the actual tables ( business and spatial)
CREATE OR REPLACE TRIGGER point_feat_insert_trigger
INSTEAD OF INSERT ON point_feat_vw
DECLARE
duplicate_info EXCEPTION;
PRAGMA EXCEPTION_INIT (duplicate_info, -00001);
BEGIN
INSERT INTO point_feat_prop
( unique_id,
StringValue,
NumberValue,
DateValue
)
VALUES (
:new.unique_id,
:new.stringValue,
:new.numberValue,
:new.dateValue
);
INSERT INTO point_feat_geom
(rec_id,
geometry,
rotation,
x_scale,
y_scale
)
VALUES
(:new.unique_id,
:new.geometry,
:new.rotation,
:new.x_scale,
:new.y_scale
);
EXCEPTION
WHEN duplicate_info THEN
RAISE_APPLICATION_ERROR (
num=> -20107,
msg=> 'Duplicate ref_id');
END point_feat_insert_trigger;
/
When the user updates the view, we want to update the underlying tables instead.
CREATE OR REPLACE TRIGGER point_feat_update_trigger
INSTEAD OF UPDATE ON point_feat_vw
FOR EACH ROW
BEGIN
UPDATE point_feat_prop
SET
unique_id = :new.unique_id,
StringValue= :new.stringValue,
NumberValue = :new.numberValue,
DateValue=:new.dateValue
WHERE
unique_id = :old.unique_id;
UPDATE point_feat_geom
SET
geometry = :new.geometry,
rotation =:new.rotation,
x_scale=:new.x_scale,
y_scale=:new.y_scale,
rec_id = :new.unique_id
WHERE
rec_id= :new.unique_id;
END point_feat_update_trigger;
/
Lastly, we need to define the delete record trigger for the underlying records of the view. CREATE OR REPLACE TRIGGER point_feat_delete_trigger
INSTEAD OF DELETE ON point_feat_vw
BEGIN
DELETE FROM point_feat_prop WHERE unique_id = :old.unique_id;
DELETE FROM point_feat_geom WHERE rec_id = :old.unique_id;
END point_feat_delete_trigger;
OPTIONAL – Adding test data
I know earlier, I said that the business or spatial data may already exist, which in most cases, it probably does. For completeness of this exercise, I will add test data. This will consist of a couple of rows of data, entered into the spatial and the business tables. This will allow us to set up the XFM Schema and test the placement, editing and removal of the spatial data.
/* Delete all the current records thawe inserted as test records.
DELETE from point_feat_vw where unique_id in (1, 2);
commit;
/* Insert a record into the view */
INSERT INTO point_feat_vw
(
unique_id,
stringValue,
numberValue,
dateValue,
geometry,
rotation,
x_scale,
y_scale
)
values
(
1,
'text1',
1000,
(select sysdate from dual),
mdsys.sdo_geometry
(
2001,
null,
mdsys.sdo_point_type(1,1,null),
null,
null
),
1.00,
1.00,
1.00
);
commit;
/* Insert another record into the view */
INSERT INTO point_feat_vw
(
unique_id,
stringValue,
numberValue,
dateValue,
geometry,
rotation,
x_scale,
y_scale
)
values
(
2,
'text2',
20,
(select sysdate from dual),
mdsys.sdo_geometry
(
2001,
null,
mdsys.sdo_point_type(100,200,null),
null,
null
),
0.785,
0.50,
0.50
);
commit;
OPTIONAL – Creating a sequence Generator
In order for the spatial interface, in the Bentley products, to post new records to a particular spatial feature, a sequence generator must be created for the spatial feature. This is optional at the time of the creation of the spatial feature schema, in the database, because it can be done in the GSA when registering the feature. It is wise though to do this in the database, to keep the schema definition in one place (the database).
DROP SEQUENCE "point_feature_seq";
CREATE SEQUENCE "point_feature_seq" INCREMENT BY 1 START WITH 3 ORDER;
commit;
Registering the Spatial feature with the GSA
Now that we have the spatial feature schema defined in the database, for the example feature, we need to setup the XFM schema through the GSA. The GSA is then used to generate all the feature interfaces, including the placement, viewing and editing of the feature instances. The GSA can also be used to setup the Bentley geospatial product workspaces, as an extension of the standard MicroStation workspaces.
Appendix A – Addition of Annotation sub-features
There are situations where the design warrants the use of a annotation sub-feature. This is typically added using the following setup:
1. Create the spatial table. During table creation, make sure you have a column for maintaining a primary key on the new spatial table and another column to maintain a foreign key to the primary feature table.
2. Make sure you have the SDO.GEOMETRY column defined.
3. If you want to maintain the annotation rotation and size, then make sure you also have a rotation, x_scale and y_scale column.
4. Create a spatial index on the table.
5. Create a reference to this spatial table in the user_sdo_geom_metadata table.
6. Create the primary key constraint.
7. Create a sequence generator for the table if you want to post new instances back to the spatial database.
8. Create the foreign key constraint referencing the primary spatial table.
Steps 1 – 7 are pretty standard for all spatial tables in Oracle, so this should be pretty familiar. Step 8 is added to link this spatial table back to the primary spatial table.
Now we have the added complexity that this annotation sub-feature needs to be referenced by the view, since that view is acting as the spatial table in this case. To do this we need the extra step of adding a foreign key constraint on the annotation sub-feature table but disable this constraint. As long as we have this constraint defined, we can ‘imply’ to the GSA and Bentley Map that the annotation spatial table is a sub-feature of the view.
The setup for the annotation sub-feature, for the point feature is as follows:
-- Resource cleanup.
drop table point_feat_annot;
drop sequence point_feat_anot_seq;
delete from USER_SDO_GEOM_METADATA where table_name = 'POINT_FEAT_ANNOT' AND COLUMN_NAME = 'GEOMETRY';
commit;
-- Create the annotation table.
CREATE TABLE point_feat_annot (
text_id NUMBER,
reference_id NUMBER,
geometry MDSYS.SDO_GEOMETRY,
rotation NUMBER,
x_scale NUMBER,
y_scale NUMBER);
commit;
-- Add this table into the geometry meatdata view.
insert into
user_sdo_geom_metadata
select
'point_feat_annot', column_name, diminfo, srid
from
user_sdo_geom_metadata
where
table_name = 'POINT_FEAT_GEOM';
-- Create the spatial index for the annotation feature.
CREATE INDEX
point_feature_annot_sidx
ON
point_feat_annot(geometry)
INDEXTYPE IS
MDSYS.SPATIAL_INDEX
PARAMETERS ('LAYER_GTYPE=POINT');
-- Create the sequence for the annotation sub-feature.
CREATE SEQUENCE
point_feat_anot_seq
INCREMENT BY
1
START WITH
5
ORDER;
-- Create all the primary and foreign Keys
ALTER TABLE point_feat_annot
ADD CONSTRAINT point_feat_annot_pk
PRIMARY KEY (text_id);
ALTER TABLE point_feat_annot
ADD CONSTRAINT point_feat_annot_fk
FOREIGN KEY (reference_id) REFERENCES point_feat_geom(rec_id)
ON DELETE CASCADE;
ALTER TABLE point_feat_annot
ADD CONSTRAINT point_feat_annot_fk_dis
FOREIGN KEY (reference_id) REFERENCES point_feat_vw(unique_id)
ON DELETE CASCADE disable;
-- Commit changes.
commit;
exit;
Now when we try to register the features, we can see the annotation sub-feature.
Tags: features, Oracle Spatial, GSA, Views