changeset 8412:17db08570637

SCHEMA CHANGE: removed superfluous columns station and river_id from measurement_stations and adapted other components accordingly.
author Tom Gottfried <tom@intevation.de>
date Wed, 15 Oct 2014 19:20:26 +0200
parents b8c6cb36607e
children 665c8326b1a6
files artifacts/doc/conf/meta-data.xml artifacts/src/main/java/org/dive4elements/river/artifacts/access/SQRelationAccess.java artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadDataFactory.java artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/StaticSQFactory.java artifacts/src/main/java/org/dive4elements/river/artifacts/services/MeasurementStationInfoService.java backend/doc/schema/oracle-minfo.sql backend/doc/schema/postgresql-minfo.sql backend/src/main/java/org/dive4elements/river/importer/ImportMeasurementStation.java backend/src/main/java/org/dive4elements/river/importer/ImportRange.java backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java backend/src/main/java/org/dive4elements/river/importer/ImportSQRelationValue.java backend/src/main/java/org/dive4elements/river/importer/ImportSedimentLoad.java backend/src/main/java/org/dive4elements/river/importer/ImporterSession.java backend/src/main/java/org/dive4elements/river/importer/parsers/MeasurementStationsParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/SQRelationParser.java backend/src/main/java/org/dive4elements/river/importer/parsers/SedimentLoadParser.java backend/src/main/java/org/dive4elements/river/model/MeasurementStation.java backend/src/main/java/org/dive4elements/river/model/River.java gwt-client/src/main/java/org/dive4elements/river/client/client/ui/stationinfo/MeasurementStationRecord.java gwt-client/src/main/java/org/dive4elements/river/client/server/RiverInfoServiceImpl.java gwt-client/src/main/java/org/dive4elements/river/client/shared/model/DefaultMeasurementStation.java gwt-client/src/main/java/org/dive4elements/river/client/shared/model/MeasurementStation.java
diffstat 22 files changed, 291 insertions(+), 301 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/doc/conf/meta-data.xml	Wed Oct 15 14:58:46 2014 +0200
+++ b/artifacts/doc/conf/meta-data.xml	Wed Oct 15 19:20:26 2014 +0200
@@ -1680,12 +1680,14 @@
                       ON sl.id = slv.sediment_load_id
                   JOIN measurement_station ms
                       ON ms.id = slv.measurement_station_id
-                  JOIN rivers r ON ms.river_id = r.id
+                  JOIN ranges ra ON ms.range_id = ra.id
+                  JOIN rivers r ON ra.river_id = r.id
                   JOIN time_intervals ti ON sl.time_interval_id = ti.id
                   LEFT JOIN time_intervals sq ON sl.sq_time_interval_id = sq.id
                   JOIN grain_fraction gf ON gf.id = sl.grain_fraction_id
               WHERE   r.id = ${river_id}
-                  AND ms.station BETWEEN ${fromkm} AND ${tokm}
+                  AND CASE WHEN r.km_up = 1 AND ra.b IS NOT NULL
+                      THEN ra.b ELSE ra.a END BETWEEN ${fromkm} AND ${tokm}
               ORDER BY sqstart DESC, sqstop DESC,
                   fraction, startyear DESC, endyear DESC
             </dc:statement>
@@ -3070,12 +3072,14 @@
                   ON sl.id = slv.sediment_load_id
               JOIN measurement_station ms
                   ON ms.id = slv.measurement_station_id
-              JOIN rivers r ON ms.river_id = r.id
+              JOIN ranges ra ON ms.range_id = ra.id
+              JOIN rivers r ON ra.river_id = r.id
               JOIN time_intervals ti ON sl.time_interval_id = ti.id
               JOIN grain_fraction gf ON gf.id = sl.grain_fraction_id
           WHERE r.id = ${river_id}
               AND sq_time_interval_id = ${sq_time_id}
-              AND ms.station BETWEEN ${fromkm} AND ${tokm}
+              AND CASE WHEN r.km_up = 1 AND ra.b IS NOT NULL
+                  THEN ra.b ELSE ra.a END BETWEEN ${fromkm} AND ${tokm}
               AND slk.kind = 'official'
         </dc:statement>
         <dc:call-macro name="sedimentload_off_epoch_filter">
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/access/SQRelationAccess.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/access/SQRelationAccess.java	Wed Oct 15 19:20:26 2014 +0200
@@ -99,8 +99,8 @@
         if (measurementStation != null) {
             return measurementStation;
         }
-        List<MeasurementStation> candidates = MeasurementStation.getStationsAtKM(
-                getRiverName(), getLocation());
+        List<MeasurementStation> candidates = MeasurementStation
+            .getStationsAtKM(getRiver(), getLocation());
         if (candidates != null && !candidates.isEmpty()) {
             // Just take the first one as we only use the name
             // and that "should" be unique at the location
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadDataFactory.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/minfo/SedimentLoadDataFactory.java	Wed Oct 15 19:20:26 2014 +0200
@@ -41,7 +41,8 @@
           "FROM sediment_load sl " +
             "JOIN sediment_load_values slv ON sl.id = slv.sediment_load_id " +
             "JOIN measurement_station ms ON ms.id = slv.measurement_station_id " +
-            "JOIN rivers r ON r.id = ms.river_id " +
+            "JOIN ranges rs ON rs.id = ms.range_id " +
+            "JOIN rivers r ON r.id = rs.river_id " +
           "WHERE r.name = :river) " +
         "SELECT " +
           "sl.id AS sl_id, " +
@@ -55,15 +56,18 @@
           "slv.value AS slv_value, " +
           "gf.name AS gf_name, " +
           "ms.id AS ms_id, " +
-          "rs.a AS ms_station, " +
+          "CASE WHEN r.km_up = 1 AND rs.b IS NOT NULL " +
+              "THEN rs.b " +
+              "ELSE rs.a " +
+          "END AS ms_station, " +
           "ms.measurement_type AS ms_type " +
         "FROM load_at_river sl " +
           "CROSS JOIN measurement_station ms " +
           "JOIN ranges rs ON ms.range_id = rs.id " +
+          "JOIN rivers r ON rs.river_id = r.id " +
           "JOIN time_intervals ti ON sl.time_interval_id = ti.id " +
           "LEFT JOIN time_intervals sqti ON sl.sq_time_interval_id = sqti.id " +
           "JOIN grain_fraction gf ON sl.grain_fraction_id = gf.id " +
-          "JOIN rivers r ON ms.river_id = r.id " +
           "LEFT JOIN sediment_load_values slv " +
              "ON ms.id=slv.measurement_station_id AND sl.id=slv.sediment_load_id " +
         "WHERE (" +
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/StaticSQFactory.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/model/sq/StaticSQFactory.java	Wed Oct 15 19:20:26 2014 +0200
@@ -34,7 +34,10 @@
             "ti.start_time  AS start_time," +
             "ti.stop_time    AS stop_time, " +
             "ms.name AS station_name, " +
-            "ms.station AS station_km, " +
+            "CASE WHEN r.km_up = 1 AND ra.b IS NOT NULL " +
+                "THEN ra.b " +
+                "ELSE ra.a " +
+            "END AS station_km, " +
             "ms.measurement_type AS measurement_type, " +
             "sqv.parameter AS parameter, " +
             "sqv.a AS a, " +
@@ -42,9 +45,11 @@
             "sqv.qmax AS qmax " +
         "FROM sq_relation sq " +
             "JOIN time_intervals ti ON ti.id   = sq.time_interval_id " +
-            "JOIN rivers r ON r.id = sq.river_id " +
             "JOIN sq_relation_value sqv ON sqv.sq_relation_id = sq.id " +
-            "JOIN measurement_station ms ON sqv.measurement_station_id = ms.id ";
+            "JOIN measurement_station ms " +
+                "ON sqv.measurement_station_id = ms.id " +
+            "JOIN ranges ra ON ra.id = ms.range_id " +
+            "JOIN rivers r ON r.id = ra.river_id ";
 
     public static final String STATION_CLAUSE =
         "WHERE " +
--- a/artifacts/src/main/java/org/dive4elements/river/artifacts/services/MeasurementStationInfoService.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/services/MeasurementStationInfoService.java	Wed Oct 15 19:20:26 2014 +0200
@@ -47,7 +47,8 @@
 
         Element egs = ec.create("measurement-stations");
 
-        List<MeasurementStation> mstations = river.getMeasurementStations();
+        List<MeasurementStation> mstations = MeasurementStation
+            .getStationsAtRiver(river);
 
         if (log.isDebugEnabled()) {
             log.debug("Loaded stations: " + mstations);
@@ -76,21 +77,21 @@
                 ec.addAttr(eg, "riverside", riverside, true);
             }
 
-            Double station = mstation.getStation();
-            if (station != null) {
-                ec.addAttr(eg, "station", Double.toString(station), true);
-            }
-
             Range range = mstation.getRange();
             if (range != null) {
                 BigDecimal a = range.getA();
-                if (a != null) {
-                    ec.addAttr(eg, "start", getStringValue(a), true);
+                BigDecimal b = range.getB();
+
+                // In case river is km_up, station is at larger value of range
+                if (b != null && river.getKmUp()) {
+                    ec.addAttr(eg, "start", getStringValue(b), true);
+                    ec.addAttr(eg, "end", getStringValue(a), true);
                 }
-
-                BigDecimal b = range.getB();
-                if (b != null) {
-                    ec.addAttr(eg, "end", getStringValue(b), true);
+                else {
+                    ec.addAttr(eg, "start", getStringValue(a), true);
+                    if (b != null) {
+                        ec.addAttr(eg, "end", getStringValue(b), true);
+                    }
                 }
             }
 
@@ -113,14 +114,20 @@
                 }
             }
 
-            String gaugename= mstation.getGaugeName();
-
+            String gaugename = mstation.getGaugeName();
             if (gaugename != null) {
                 Element egauge = ec.create("gauge");
                 ec.addAttr(egauge, "name", gaugename, true);
                 eg.appendChild(egauge);
             }
 
+            String comment = mstation.getComment();
+            if (comment != null) {
+                Element ecomment = ec.create("comment");
+                ec.addAttr(ecomment, "comment", comment, true);
+                eg.appendChild(ecomment);
+            }
+
             egs.appendChild(eg);
         }
 
--- a/backend/doc/schema/oracle-minfo.sql	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/doc/schema/oracle-minfo.sql	Wed Oct 15 19:20:26 2014 +0200
@@ -309,24 +309,24 @@
 
 CREATE SEQUENCE MEASUREMENT_STATION_ID_SEQ;
 CREATE TABLE measurement_station (
-    id                       NUMBER(38)   NOT NULL,
-    name                     VARCHAR(256) NOT NULL,
-    river_id                 NUMBER(38)   NOT NULL,
-    station                  NUMBER(38,3) NOT NULL,
-    range_id                 NUMBER(38),
-    measurement_type         VARCHAR(64)  NOT NULL,
-    riverside                VARCHAR(16),
-    reference_gauge_id       NUMBER(38),
+    id                       int          NOT NULL,
+    range_id                 int          NOT NULL,
+    reference_gauge_id       int,
+    time_interval_id         int,
+    name                     VARCHAR2(256 CHAR) NOT NULL,
+    measurement_type         VARCHAR2(64 CHAR)  NOT NULL,
+    riverside                VARCHAR2(16 CHAR),
     -- store name of reference gauges here too, as not all are in gauges
-    reference_gauge_name     VARCHAR(64),
-    observation_timerange_id NUMBER(38),
-    operator                 VARCHAR(64),
-    description              VARCHAR(512),
-    PRIMARY KEY              (id),
-    CONSTRAINT fk_ms_river_id FOREIGN KEY (river_id) REFERENCES rivers(id) ON DELETE CASCADE,
-    CONSTRAINT fk_ms_range_id FOREIGN KEY (range_id) REFERENCES ranges(id) ON DELETE CASCADE,
-    CONSTRAINT fk_ms_reference_gauge_id FOREIGN KEY (reference_gauge_id) REFERENCES gauges(id) ON DELETE CASCADE,
-    CONSTRAINT fk_ms_observation_timerange_id FOREIGN KEY (observation_timerange_id) REFERENCES time_intervals(id)
+    reference_gauge_name     VARCHAR2(64 CHAR),
+    operator                 VARCHAR2(64 CHAR),
+    comment                  VARCHAR2(512 CHAR),
+    PRIMARY KEY (id),
+    CONSTRAINT fk_ms_range_id FOREIGN KEY (range_id)
+        REFERENCES ranges(id) ON DELETE CASCADE,
+    CONSTRAINT fk_ms_reference_gauge_id FOREIGN KEY (reference_gauge_id)
+        REFERENCES gauges(id) ON DELETE CASCADE,
+    CONSTRAINT fk_time_interval_id FOREIGN KEY (time_interval_id)
+        REFERENCES time_intervals(id)
 );
 
 
--- a/backend/doc/schema/postgresql-minfo.sql	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/doc/schema/postgresql-minfo.sql	Wed Oct 15 19:20:26 2014 +0200
@@ -310,23 +310,23 @@
 CREATE SEQUENCE MEASUREMENT_STATION_ID_SEQ;
 CREATE TABLE measurement_station (
     id                       int          NOT NULL,
+    range_id                 int          NOT NULL,
+    reference_gauge_id       int,
+    time_interval_id         int,
     name                     VARCHAR(256) NOT NULL,
-    river_id                 int          NOT NULL,
-    station                  NUMERIC      NOT NULL,
-    range_id                 int,
     measurement_type         VARCHAR(64)  NOT NULL,
     riverside                VARCHAR(16),
-    reference_gauge_id       int,
     -- store name of reference gauges here too, as not all are in gauges
     reference_gauge_name     VARCHAR(64),
-    observation_timerange_id int,
     operator                 VARCHAR(64),
-    description              VARCHAR(512),
+    comment                  VARCHAR(512),
     PRIMARY KEY (id),
-    CONSTRAINT fk_ms_river_id FOREIGN KEY (river_id) REFERENCES rivers(id) ON DELETE CASCADE,
-    CONSTRAINT fk_ms_range_id FOREIGN KEY (range_id) REFERENCES ranges(id) ON DELETE CASCADE,
-    CONSTRAINT fk_ms_reference_gauge_id FOREIGN KEY (reference_gauge_id) REFERENCES gauges(id) ON DELETE CASCADE,
-    CONSTRAINT fk_ms_observation_timerange_id FOREIGN KEY (observation_timerange_id) REFERENCES time_intervals(id)
+    CONSTRAINT fk_ms_range_id FOREIGN KEY (range_id)
+        REFERENCES ranges(id) ON DELETE CASCADE,
+    CONSTRAINT fk_ms_reference_gauge_id FOREIGN KEY (reference_gauge_id)
+        REFERENCES gauges(id) ON DELETE CASCADE,
+    CONSTRAINT fk_time_interval_id FOREIGN KEY (time_interval_id)
+        REFERENCES time_intervals(id)
 );
 
 
@@ -374,8 +374,10 @@
     time_interval_id int NOT NULL,
     description      VARCHAR(256),
     PRIMARY KEY (id),
-    CONSTRAINT fk_sqr_river_id FOREIGN KEY (river_id) REFERENCES rivers(id) ON DELETE CASCADE,
-    CONSTRAINT fk_sqr_tinterval_id FOREIGN KEY (time_interval_id) REFERENCES time_intervals(id)
+    CONSTRAINT fk_sqr_river_id FOREIGN KEY (river_id)
+        REFERENCES rivers(id) ON DELETE CASCADE,
+    CONSTRAINT fk_sqr_tinterval_id FOREIGN KEY (time_interval_id)
+        REFERENCES time_intervals(id)
 );
 
 
@@ -395,7 +397,9 @@
     cferguson              NUMERIC,
     cduan                  NUMERIC,
     PRIMARY KEY (id),
-    CONSTRAINT fk_sqr_id FOREIGN KEY (sq_relation_id) REFERENCES sq_relation(id) ON DELETE CASCADE,
-    CONSTRAINT fk_mstation_id FOREIGN KEY (measurement_station_id) REFERENCES measurement_station(id) ON DELETE CASCADE
+    CONSTRAINT fk_sqr_id FOREIGN KEY (sq_relation_id)
+        REFERENCES sq_relation(id) ON DELETE CASCADE,
+    CONSTRAINT fk_mstation_id FOREIGN KEY (measurement_station_id)
+        REFERENCES measurement_station(id) ON DELETE CASCADE
 );
 COMMIT;
--- a/backend/src/main/java/org/dive4elements/river/importer/ImportMeasurementStation.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImportMeasurementStation.java	Wed Oct 15 19:20:26 2014 +0200
@@ -28,14 +28,13 @@
     private MeasurementStation peer;
 
     public String name;
-    public Double station;
     public ImportRange range;
     public String measurementType;
     public String riverside;
     public String gauge;
     public ImportTimeInterval observationTimerange;
     public String operator;
-    public String description;
+    public String comment;
 
     public ImportMeasurementStation() {
     }
@@ -71,7 +70,7 @@
                 }
             }
             catch (Exception e) {
-                log.error("Exception: " + e.getMessage());
+                log.error(e.getMessage());
             }
 
             Range range = null;
@@ -97,12 +96,10 @@
             org.hibernate.Query query = session
                 .createQuery(
                     "FROM MeasurementStation " +
-                    "WHERE river=:river" +
-                    "   AND station=:station " +
+                    "WHERE range=:range " +
                     "   AND measurement_type=:measurement_type ");
 
-            query.setParameter("river", river);
-            query.setParameter("station", station);
+            query.setParameter("range", range);
             query.setParameter("measurement_type", measurementType);
 
             List<MeasurementStation> stations = query.list();
@@ -110,9 +107,9 @@
             if (stations.isEmpty()) {
                 log.info("create new measurement station '" + name + "'");
 
-                peer = new MeasurementStation(river, name, measurementType,
-                    riverside, station, range, gauge, this.gauge,
-                    observationTimerange, operator, description);
+                peer = new MeasurementStation(name, measurementType,
+                    riverside, range, gauge, this.gauge,
+                    observationTimerange, operator, comment);
 
                 session.save(peer);
             }
--- a/backend/src/main/java/org/dive4elements/river/importer/ImportRange.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImportRange.java	Wed Oct 15 19:20:26 2014 +0200
@@ -30,6 +30,11 @@
     public ImportRange() {
     }
 
+    public ImportRange(BigDecimal a) {
+        this.a = a;
+        this.b = null;
+    }
+
     public ImportRange(BigDecimal a, BigDecimal b) {
 
         // enforce a<b and set only a for zero-length ranges
--- a/backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImportRiver.java	Wed Oct 15 19:20:26 2014 +0200
@@ -676,7 +676,7 @@
 
         log.debug("Parse sediment load data at measurement stations");
 
-        SedimentLoadParser parser = new SedimentLoadParser(name);
+        SedimentLoadParser parser = new SedimentLoadParser(getPeer());
 
         File minfoDir          = getMinfoDir();
         File sedimentLoadDir   = new File(minfoDir, SEDIMENT_LOAD_DIR);
@@ -806,7 +806,7 @@
             return;
         }
 
-        SQRelationParser parser = new SQRelationParser();
+        SQRelationParser parser = new SQRelationParser(getPeer());
 
         for (File file: files) {
             parser.parse(file);
--- a/backend/src/main/java/org/dive4elements/river/importer/ImportSQRelationValue.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImportSQRelationValue.java	Wed Oct 15 19:20:26 2014 +0200
@@ -31,8 +31,7 @@
     private SQRelationValue peer;
 
     private String parameter;
-
-    private Double km;
+    private MeasurementStation station;
     private Double a;
     private Double b;
     private Double qMax;
@@ -45,7 +44,7 @@
 
     public ImportSQRelationValue(
         String parameter,
-        Double km,
+        MeasurementStation station,
         Double a,
         Double b,
         Double qMax,
@@ -56,7 +55,7 @@
         Double cDuan
     ) {
         this.parameter = parameter;
-        this.km        = km;
+        this.station   = station;
         this.a         = a;
         this.b         = b;
         this.qMax      = qMax;
@@ -78,20 +77,6 @@
     public SQRelationValue getPeer(SQRelation owner) {
         if (peer == null) {
             Session session = ImporterSession.getInstance().getDatabaseSession();
-
-            Query query = session.createQuery(
-                "from MeasurementStation " +
-                "   where station between :kml and :kmh");
-            query.setDouble("kml", km - 1e-4);
-            query.setDouble("kmh", km + 1e-4);
-
-            List<MeasurementStation> result = query.list();
-
-            if (result.isEmpty()) {
-                log.error("No measurement stations found at km " + km);
-                return null;
-            }
-
             Query query2 = session.createQuery(
                 "from SQRelationValue " +
                 "   where sqRelation=:owner " +
@@ -106,7 +91,7 @@
 
             query2.setParameter("owner", owner);
             query2.setString("parameter", parameter);
-            query2.setParameter("measurementStation", result.get(0));
+            query2.setParameter("measurementStation", station);
             query2.setBigDecimal("a", toBigDecimal(a));
             query2.setBigDecimal("b", toBigDecimal(b));
             query2.setBigDecimal("qMax", toBigDecimal(qMax));
@@ -120,7 +105,7 @@
                 peer = new SQRelationValue(
                     owner,
                     parameter,
-                    result.get(0),
+                    station,
                     a,
                     b,
                     qMax,
--- a/backend/src/main/java/org/dive4elements/river/importer/ImportSedimentLoad.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImportSedimentLoad.java	Wed Oct 15 19:20:26 2014 +0200
@@ -66,9 +66,9 @@
         if (peer == null) {
             Session session = ImporterSession.getInstance().getDatabaseSession();
 
-            String sqtquery = sqTimeInterval == null ?
-                "sq_time_interval_id is null" :
-                "sqTimeInterval = :sqTimeInterval";
+            String sqtquery = sqTimeInterval == null
+                ? "sq_time_interval_id is null"
+                : "sqTimeInterval = :sqTimeInterval";
             Query query = session.createQuery(
                 "from SedimentLoad where " +
                 "   grainFraction = :grainFraction and " +
--- a/backend/src/main/java/org/dive4elements/river/importer/ImporterSession.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/ImporterSession.java	Wed Oct 15 19:20:26 2014 +0200
@@ -206,27 +206,38 @@
         return range;
     }
 
-    public List<MeasurementStation> getMeasurementStations(String river, double station) {
+    public List<MeasurementStation> getMeasurementStations(
+        River river,
+        double station
+    ) {
+        String rivername = river.getName();
+
         if (riversToMeasurementStations == null) {
             riversToMeasurementStations =
                 new HashMap<String, Map<Double, List<MeasurementStation>>>();
         }
 
         Map<Double, List<MeasurementStation>> km2Stations =
-            riversToMeasurementStations.get(river);
+            riversToMeasurementStations.get(rivername);
         if (km2Stations == null) {
             km2Stations =
                 new TreeMap<Double, List<MeasurementStation>>(EpsilonComparator.CMP);
-            riversToMeasurementStations.put(river, km2Stations);
+            riversToMeasurementStations.put(rivername, km2Stations);
             Query query = databaseSession.createQuery(
-                "from MeasurementStation where river.name = :name");
-            query.setParameter("name", river);
+                "from MeasurementStation where range.river = :river");
+            query.setParameter("river", river);
             for (Iterator iter = query.iterate(); iter.hasNext();) {
                 MeasurementStation st = (MeasurementStation)iter.next();
-                List<MeasurementStation> ms = km2Stations.get(st.getStation());
+
+                // In case river is km_up, station is at larger value of range
+                double stKm = river.getKmUp() && st.getRange().getB() != null
+                    ? st.getRange().getB().doubleValue()
+                    : st.getRange().getA().doubleValue();
+
+                List<MeasurementStation> ms = km2Stations.get(stKm);
                 if (ms == null) {
                     ms = new ArrayList<MeasurementStation>(2);
-                    km2Stations.put(st.getStation(), ms);
+                    km2Stations.put(stKm, ms);
                 }
                 ms.add(st);
             }
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/MeasurementStationsParser.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/MeasurementStationsParser.java	Wed Oct 15 19:20:26 2014 +0200
@@ -32,7 +32,9 @@
         }
     }
 
-    public static final int MIN_COLUMNS = 10;
+    public static final int MIN_COLUMNS = 9;
+
+    public static final int MAX_COMMENT_LENGTH = 512;
 
     private static final Logger log = Logger
         .getLogger(MeasurementStationsParser.class);
@@ -58,7 +60,7 @@
 
         try {
             current = new ImportMeasurementStation();
-            handleDataLine(line);
+            handleDataLine(lineNum, line);
             measurementStations.add(current);
         }
         catch (MeasurementStationParserException e) {
@@ -70,7 +72,7 @@
         return measurementStations;
     }
 
-    protected void handleDataLine(String line)
+    protected void handleDataLine(int lineNum, String line)
         throws MeasurementStationParserException {
         String[] cols = line.split(SEPERATOR_CHAR);
 
@@ -80,116 +82,132 @@
                 + num);
         }
 
-        current.name = getName(cols);
-        current.station = getStation(cols);
-        current.range = getRange(cols);
-        current.measurementType = getMeasurementType(cols);
-        current.riverside = getRiverside(cols);
-        current.gauge = getGauge(cols);
-        current.observationTimerange = getObservationTimerange(cols);
-        current.operator = getOperator(cols);
-        current.description = getDescription(cols);
-
-        log.debug("Found new measurement station '" + current.name + "' at km "
-            + current.station);
+        current.name = getName(cols, lineNum);
+        current.range = getRange(cols, lineNum);
+        current.measurementType = getMeasurementType(cols, lineNum);
+        current.riverside = getRiverside(cols, lineNum);
+        current.gauge = getGauge(cols, lineNum);
+        current.observationTimerange = getObservationTimerange(cols, lineNum);
+        current.operator = getOperator(cols, lineNum);
+        current.comment = getComment(cols, lineNum);
     }
 
-    protected String getName(String[] cols)
+    protected String getName(String[] cols, int lineNum)
         throws MeasurementStationParserException {
         if (cols[0] == null || cols[0].length() == 0) {
-            throw new MeasurementStationParserException("invalid name '"
-                + cols[0] + "'");
+            throw new MeasurementStationParserException("invalid name in line "
+                + lineNum);
         }
 
         return cols[0];
     }
 
-    protected double getStation(String[] cols)
-        throws MeasurementStationParserException {
-        if (cols[1] == null || cols[1].length() == 0) {
-            throw new MeasurementStationParserException("invalid station '"
-                + cols[1] + "'");
-        }
-
-        try {
-            return getDouble(cols[1]);
-        }
-        catch (ParseException e) {
-            throw new MeasurementStationParserException(
-                "unable to parse station: " + e.getMessage());
-        }
-    }
-
-    protected ImportRange getRange(String[] cols) {
-        if (cols[4] == null || cols[4].length() == 0) {
-            log.warn("No upper value for range found in '" + cols[4] + "'");
-            return null;
-        }
-
-        if (cols[5] == null || cols[5].length() == 0) {
-            log.warn("No upper value for range found in '" + cols[5] + "'");
+    protected ImportRange getRange(String[] cols, int lineNum) {
+        String from = cols[1];
+        String to   = cols[4];
+        if (from == null || from.length() == 0) {
+            log.error("No station found in line" + lineNum);
             return null;
         }
 
         try {
-            double lower = getDouble(cols[4]);
-            double upper = getDouble(cols[5]);
+            double lower = getDouble(from);
 
-            return new ImportRange(new BigDecimal(lower), new BigDecimal(upper));
+            if (to == null || to.length() == 0) {
+                log.warn("No end km found in line " + lineNum);
+                return new ImportRange(new BigDecimal(lower));
+            }
+
+            try {
+                double upper = getDouble(to);
+
+                return new ImportRange(new BigDecimal(lower),
+                    new BigDecimal(upper));
+            }
+            catch (ParseException e) {
+                log.warn("Unparseable end km in line " + lineNum +
+                    ". Error: " + e.getMessage());
+                return new ImportRange(new BigDecimal(lower));
+            }
+
         }
         catch (ParseException e) {
-            log.warn("unable to parse range: " + e.getMessage());
+            log.error("Unparseable station in line " + lineNum +
+                    ". Error: " + e.getMessage());
             return null;
         }
     }
 
-    protected String getMeasurementType(String[] cols)
+    protected String getMeasurementType(String[] cols, int lineNum)
         throws MeasurementStationParserException {
         if (cols[2] == null || cols[2].length() == 0) {
             throw new MeasurementStationParserException(
-                "invalid measurement type '" + cols[2] + "'");
+                "invalid measurement type in line " + lineNum);
         }
 
         return cols[2];
     }
 
-    protected String getRiverside(String[] cols) {
-        return cols[3];
+    protected String getRiverside(String[] cols, int lineNum) {
+        String col = cols[3];
+        if (col == null || col.length() == 0) {
+            log.warn("No river side given in line " + lineNum);
+        }
+        return col;
     }
 
-    protected String getGauge(String[] cols) {
-        if (cols[6] == null || cols[6].length() == 0) {
-            log.warn("invalid gauge found: '" + cols[6] + "'");
+    protected String getGauge(String[] cols, int lineNum) {
+        String col = cols[5];
+        if (col == null || col.length() == 0) {
+            log.warn("Invalid gauge found in line " + lineNum);
         }
-
-        return cols[6];
+        return col;
     }
 
-    protected ImportTimeInterval getObservationTimerange(String[] cols) {
-        if (cols[8] == null || cols[8].length() == 0) {
-                log.warn("Found invalid observation time '" + cols[8] + "'");
+    protected ImportTimeInterval getObservationTimerange(
+        String[] cols,
+        int lineNum
+    ) {
+        String col = cols[7];
+        if (col == null || col.length() == 0) {
+            log.warn("Observation time invalid in line " + lineNum);
+            return null;
         }
 
         try {
-            Date date = getDate(cols[8]);
+            Date date = getDate(col);
 
             if (date != null) {
                 return new ImportTimeInterval(date);
             }
-            log.warn("Observation time date invalid: '" + cols[8] + "'");
+            log.warn("Observation time invalid in line " + lineNum);
         }
         catch (ParseException pe) {
-            log.warn("Observation time date not parseable: '" + cols[8] + "'");
-            return null;
+            log.warn("Unparseable observation time '" + col +
+                "' in line " + lineNum);
         }
         return null;
     }
 
-    protected String getOperator(String[] cols) {
-        return cols[9];
+    protected String getOperator(String[] cols, int lineNum) {
+        String col = cols[8];
+        if (col == null || col.length() == 0) {
+            log.warn("No operator given in line " + lineNum);
+        }
+        return col;
     }
 
-    protected String getDescription(String[] cols) {
-        return cols.length > 10 ? cols[10] : null;
+    protected String getComment(String[] cols, int lineNum) {
+        if (cols.length > MIN_COLUMNS) {
+            String col = cols[9];
+            if (col.length() > MAX_COMMENT_LENGTH) {
+                log.warn("Comment in line " + lineNum +
+                    " longer than allowed " + MAX_COMMENT_LENGTH +
+                    " characters. Truncated.");
+                return col.substring(0, MAX_COMMENT_LENGTH);
+            }
+            return col;
+        }
+        return null;
     }
 }
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/SQRelationParser.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/SQRelationParser.java	Wed Oct 15 19:20:26 2014 +0200
@@ -19,6 +19,10 @@
 
 import org.apache.log4j.Logger;
 
+import org.dive4elements.river.model.River;
+import org.dive4elements.river.model.MeasurementStation;
+
+import org.dive4elements.river.importer.ImporterSession;
 import org.dive4elements.river.importer.ImportSQRelation;
 import org.dive4elements.river.importer.ImportSQRelationValue;
 import org.dive4elements.river.importer.ImportTimeInterval;
@@ -36,16 +40,17 @@
     private static final NumberFormat nf =
         NumberFormat.getInstance(DEFAULT_LOCALE);
 
-
     private List<ImportSQRelation> relations;
 
     private ImportSQRelation current;
 
     private String currentDescription;
 
+    protected River river;
 
-    public SQRelationParser() {
+    public SQRelationParser(River river) {
         relations = new ArrayList<ImportSQRelation>();
+        this.river = river;
     }
 
 
@@ -144,17 +149,25 @@
             }
             return;
         }
-        current.addValue(new ImportSQRelationValue(
-            cols[1],
-            km,
-            a,
-            b,
-            qMax,
-            rSq,
-            nTot,
-            nOutlier,
-            cFer,
-            cDuan));
+
+        List<MeasurementStation> ms =
+            ImporterSession.getInstance().getMeasurementStations(
+                river, km);
+
+        if (ms != null && !ms.isEmpty()) {
+            current.addValue(new ImportSQRelationValue(
+                    cols[1],
+                    ms.get(0),
+                    a,
+                    b,
+                    qMax,
+                    rSq,
+                    nTot,
+                    nOutlier,
+                    cFer,
+                    cDuan
+                ));
+        }
     }
 
     private Double parseDouble(String value, String line) {
--- a/backend/src/main/java/org/dive4elements/river/importer/parsers/SedimentLoadParser.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/importer/parsers/SedimentLoadParser.java	Wed Oct 15 19:20:26 2014 +0200
@@ -19,6 +19,7 @@
 import org.dive4elements.river.importer.ImportSedimentLoad;
 import org.dive4elements.river.importer.ImportSedimentLoadValue;
 
+import org.dive4elements.river.model.River;
 import org.dive4elements.river.model.MeasurementStation;
 
 /** Parses sediment load longitudinal section files. */
@@ -39,15 +40,15 @@
 
     protected ImportSedimentLoad[] current;
 
-    protected String rivername;
+    protected River river;
 
     public SedimentLoadParser() {
         sedimentLoads = new ArrayList<ImportSedimentLoad>();
     }
 
-    public SedimentLoadParser(String rivername) {
+    public SedimentLoadParser(River river) {
         sedimentLoads = new ArrayList<ImportSedimentLoad>();
-        this.rivername = rivername;
+        this.river = river;
     }
 
 
@@ -116,7 +117,7 @@
 
             List<MeasurementStation> ms =
                 ImporterSession.getInstance().getMeasurementStations(
-                    rivername, km);
+                    river, km);
 
             String gfn = grainFraction.getPeer().getName();
 
@@ -145,12 +146,12 @@
                 }
                 log.error("SLP: No measurement station at km " + km +
                     " fitting grain fraction " + gfn +
-                    " on river " + rivername);
+                    " on river " + river.getName());
                 return;
             }
             else {
                 log.error("SLP: No measurement station at km " + km +
-                    " on river " + rivername);
+                    " on river " + river.getName());
                 return;
             }
         }
--- a/backend/src/main/java/org/dive4elements/river/model/MeasurementStation.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/MeasurementStation.java	Wed Oct 15 19:20:26 2014 +0200
@@ -8,7 +8,11 @@
 
 package org.dive4elements.river.model;
 
+import java.util.Iterator;
 import java.util.List;
+import java.util.ArrayList;
+
+import java.math.BigDecimal;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
@@ -35,13 +39,10 @@
     private String measurementType;
     private String riverside;
     private String operator;
-    private String description;
+    private String comment;
 
-    private Double station;
     private Range range;
 
-    private River river;
-
     private Gauge gauge;
     private String gaugeName;
 
@@ -50,22 +51,20 @@
     public MeasurementStation() {
     }
 
-    public MeasurementStation(River river, String name, String measurementType,
-        String riverside, Double station, Range range, Gauge gauge,
+    public MeasurementStation(String name, String measurementType,
+        String riverside, Range range, Gauge gauge,
         String gaugeName, TimeInterval observationTimerange, String operator,
-        String description
+        String comment
     ) {
-        this.river = river;
         this.name = name;
         this.measurementType = measurementType;
         this.riverside = riverside;
-        this.station = station;
         this.range = range;
         this.gauge = gauge;
         this.gaugeName = gaugeName;
         this.observationTimerange = observationTimerange;
         this.operator = operator;
-        this.description = description;
+        this.comment = comment;
     }
 
     @Id
@@ -108,16 +107,6 @@
     }
 
     @OneToOne
-    @JoinColumn(name = "river_id")
-    public River getRiver() {
-        return river;
-    }
-
-    public void setRiver(River river) {
-        this.river = river;
-    }
-
-    @OneToOne
     @JoinColumn(name = "reference_gauge_id")
     public Gauge getGauge() {
         return gauge;
@@ -136,15 +125,6 @@
         this.gaugeName = gaugeName;
     }
 
-    @Column(name = "station")
-    public Double getStation() {
-        return station;
-    }
-
-    public void setStation(Double station) {
-        this.station = station;
-    }
-
     @OneToOne
     @JoinColumn(name = "range_id")
     public Range getRange() {
@@ -156,7 +136,7 @@
     }
 
     @OneToOne
-    @JoinColumn(name = "observation_timerange_id")
+    @JoinColumn(name = "time_interval_id")
     public TimeInterval getObservationTimerange() {
         return observationTimerange;
     }
@@ -174,25 +154,53 @@
         this.operator = operator;
     }
 
-    @Column(name = "description")
-    public String getDescription() {
-        return description;
+    @Column(name = "comment")
+    public String getComment() {
+        return comment;
     }
 
-    public void setDescription(String description) {
-        this.description = description;
+    public void setComment(String comment) {
+        this.comment = comment;
     }
 
-    public static List<MeasurementStation> getStationsAtKM(String river, Double river_km)
-    {
+    public static List<MeasurementStation> getStationsAtRiver(River river) {
         Session session = SessionHolder.HOLDER.get();
 
         Query query = session.createQuery(
-            "from MeasurementStation as ms " +
-            "where ms.river.name = :river_name and ms.station = :river_km");
-        query.setParameter("river_name", river);
-        query.setParameter("river_km", river_km);
+            "from MeasurementStation " +
+            "where range.river = :river");
+
+        query.setParameter("river", river);
 
         return query.list();
     }
+
+    public static List<MeasurementStation> getStationsAtKM(
+        River river,
+        Double river_km
+    ) {
+        Session session = SessionHolder.HOLDER.get();
+
+        Query query = session.createQuery(
+            "from MeasurementStation where range.river = :river");
+        query.setParameter("river", river);
+
+        List<MeasurementStation> result = new ArrayList<MeasurementStation>();
+        for (Iterator iter = query.iterate(); iter.hasNext();) {
+            MeasurementStation st = (MeasurementStation)iter.next();
+            Double a = st.getRange().getA().doubleValue();
+            Double b = st.getRange().getB() == null
+                ? null
+                : st.getRange().getB().doubleValue();
+
+            // In case river is km_up, station is at larger value of range
+            if (river.getKmUp() && b != null && b == river_km
+                || !river.getKmUp() && a == river_km
+                || b == null && a == river_km // no end km given
+            ) {
+                result.add(st);
+            }
+        }
+        return result;
+    }
 }
--- a/backend/src/main/java/org/dive4elements/river/model/River.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/backend/src/main/java/org/dive4elements/river/model/River.java	Wed Oct 15 19:20:26 2014 +0200
@@ -65,8 +65,6 @@
 
     private List<Gauge> gauges;
 
-    private List<MeasurementStation> measurementstations;
-
     private Unit wstUnit;
 
     @Id
@@ -141,18 +139,6 @@
         this.gauges = gauges;
     }
 
-
-    @OneToMany
-    @OrderBy("station")
-    @JoinColumn(name="river_id")
-    public List<MeasurementStation> getMeasurementStations() {
-        return measurementstations;
-    }
-
-    public void setMeasurementStations(List<MeasurementStation> mstations) {
-        this.measurementstations = mstations;
-    }
-
     @OneToOne
     @JoinColumn(name = "wst_unit_id" )
     public Unit getWstUnit() {
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/stationinfo/MeasurementStationRecord.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/stationinfo/MeasurementStationRecord.java	Wed Oct 15 19:20:26 2014 +0200
@@ -43,17 +43,9 @@
         this.setCurveLink(MSG.static_sqrelation());
         this.setID(number);
         this.setName(station.getName());
-        if (station.isKmUp()) {
-            this.setKmEnd(station.getKmStart());
-            this.setKmStart(station.getKmEnd());
-        }
-        else {
-            this.setKmEnd(station.getKmEnd());
-            this.setKmStart(station.getKmStart());
-        }
-        this.setKmUp(station.isKmUp());
+        this.setKmEnd(station.getKmEnd());
+        this.setKmStart(station.getKmStart());
         this.setRiverName(station.getRiverName());
-        this.setStation(station.getStation());
         this.setGaugeName(station.getGaugeName());
         this.setMeasurementType(station.getMeasurementType());
         this.setOperator(station.getOperator());
@@ -99,24 +91,6 @@
     }
 
     @Override
-    public boolean isKmUp() {
-        return this.getAttributeAsBoolean("kmup");
-    }
-
-    private void setKmUp(boolean value) {
-        this.setAttribute("kmup", value);
-    }
-
-    @Override
-    public Double getStation() {
-        return this.getAttributeAsDouble("station");
-    }
-
-    private void setStation(Double station) {
-        this.setAttribute("station", station);
-    }
-
-    @Override
     public String getRiverName() {
         return this.getAttributeAsString("rivername");
     }
--- a/gwt-client/src/main/java/org/dive4elements/river/client/server/RiverInfoServiceImpl.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/server/RiverInfoServiceImpl.java	Wed Oct 15 19:20:26 2014 +0200
@@ -129,7 +129,7 @@
 
             DefaultRiverInfo riverinfo = getRiverInfo(result);
             List<MeasurementStation> mstations = createMeasurementStations(
-                    result, riverinfo.getName(), riverinfo.isKmUp());
+                result, riverinfo.getName());
 
             riverinfo.setMeasurementStations(mstations);
 
@@ -201,7 +201,7 @@
     }
 
     private List<MeasurementStation> createMeasurementStations(
-            Document result, String rivername, boolean kmup) {
+        Document result, String rivername) {
 
         NodeList stationnodes = (NodeList) XMLUtils.xpath(
                 result,
@@ -228,8 +228,6 @@
                         ArtifactNamespaceContext.NAMESPACE_URI, "start");
                 String mend = stationele.getAttributeNS(
                         ArtifactNamespaceContext.NAMESPACE_URI, "end");
-                String mstation = stationele.getAttributeNS(
-                        ArtifactNamespaceContext.NAMESPACE_URI, "station");
                 String mtype = stationele.getAttributeNS(
                         ArtifactNamespaceContext.NAMESPACE_URI, "type");
                 String riverside = stationele.getAttributeNS(
@@ -258,10 +256,8 @@
                         rivername,
                         mname,
                         parseInteger(mid),
-                        parseDouble(mstation),
                         parseDouble(mstart),
                         parseDouble(mend),
-                        kmup,
                         riverside,
                         mtype,
                         moperator,
--- a/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/DefaultMeasurementStation.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/DefaultMeasurementStation.java	Wed Oct 15 19:20:26 2014 +0200
@@ -18,12 +18,10 @@
     private String  name;
     private Double  start;
     private Double  end;
-    private Double  station;
     private String  rivername;
     private String  measurementtype;
     private String  riverside;
     private Integer id;
-    private boolean kmup;
     private String  moperator;
     private Date    starttime;
     private Date    stoptime;
@@ -36,10 +34,8 @@
             String  rivername,
             String  name,
             Integer id,
-            Double  station,
             Double  start,
             Double  end,
-            boolean kmup,
             String  riverside,
             String  measurementtype,
             String  moperator,
@@ -49,13 +45,11 @@
     {
         this.rivername       = rivername;
         this.name            = name;
-        this.station         = station;
         this.start           = start;
         this.end             = end;
         this.riverside       = riverside;
         this.measurementtype = measurementtype;
         this.id              = id;
-        this.kmup            = kmup;
         this.moperator       = moperator;
         this.starttime       = starttime;
         this.stoptime        = stoptime;
@@ -103,15 +97,6 @@
     }
 
     /**
-     * Returns the station km of this measurement station
-     */
-    @Override
-    public Double getStation() {
-        return this.station;
-    }
-
-
-    /**
      * Returns the side of the river where this measurement station belongs
      */
     @Override
@@ -127,11 +112,6 @@
         return this.id;
     }
 
-    @Override
-    public boolean isKmUp() {
-        return this.kmup;
-    }
-
     /**
      * Returns the operator of the measurement station
      */
--- a/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/MeasurementStation.java	Wed Oct 15 14:58:46 2014 +0200
+++ b/gwt-client/src/main/java/org/dive4elements/river/client/shared/model/MeasurementStation.java	Wed Oct 15 19:20:26 2014 +0200
@@ -31,14 +31,6 @@
      */
     Double getKmEnd();
 
-    boolean isKmUp();
-
-    /**
-     * Returns the station km of the measurement station or null if not
-     * available
-     */
-    Double getStation();
-
     /**
      * Returns the river to which this measurement station belongs
      */

http://dive4elements.wald.intevation.org