From 8be2e0569535a39e678065448a5dc79a0b7ce319 Mon Sep 17 00:00:00 2001
From: Piotr Gawron <piotr.gawron@uni.lu>
Date: Tue, 6 Feb 2018 17:23:14 +0100
Subject: [PATCH] persistence annotations added

---
 .../lcsb/mapviewer/model/map/MiriamData.java  |   2 +-
 .../model/map/kinetics/SbmlFunction.java      |  20 +-
 .../model/map/kinetics/SbmlKinetics.java      |  24 +-
 .../model/map/kinetics/SbmlParameter.java     |   4 +
 .../model/map/kinetics/SbmlUnit.java          |  25 +-
 .../map/kinetics/SbmlUnitTypeFactor.java      |  18 +
 .../mapviewer/model/map/model/ModelData.java  |  20 +-
 .../model/map/model/ModelFullIndexed.java     |   3 +-
 .../model/map/reaction/Reaction.java          |   4 +-
 .../mapviewer/model/map/species/Species.java  |   1 +
 persist/src/db/12.0.0/fix_db_20180206.sql     | 208 +++++
 .../resources/applicationContext-persist.xml  |   6 +
 .../persist/dao/map/ModelDaoTest.java         | 808 ++++++++++--------
 13 files changed, 769 insertions(+), 374 deletions(-)
 create mode 100644 persist/src/db/12.0.0/fix_db_20180206.sql

diff --git a/model/src/main/java/lcsb/mapviewer/model/map/MiriamData.java b/model/src/main/java/lcsb/mapviewer/model/map/MiriamData.java
index f6f3ba7142..5e5dffd5a5 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/MiriamData.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/MiriamData.java
@@ -49,7 +49,7 @@ public class MiriamData implements Comparable<MiriamData>, Serializable {
 	private int								 id;
 
 	/**
-	 * What is the connection between element and the anntoation.
+	 * What is the connection between element and the annotation.
 	 */
 	private MiriamRelationType relationType			= null;
 
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlFunction.java b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlFunction.java
index 03680db73c..c3e23b4573 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlFunction.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlFunction.java
@@ -8,16 +8,20 @@ import javax.persistence.CollectionTable;
 import javax.persistence.Column;
 import javax.persistence.ElementCollection;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
 import javax.persistence.Table;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import org.apache.log4j.Logger;
 import org.hibernate.annotations.IndexColumn;
 
+import lcsb.mapviewer.model.map.model.ModelData;
+
 /**
  * Representation of a single SBML function
  * 
@@ -62,6 +66,12 @@ public class SbmlFunction implements Serializable, SbmlArgument {
   @Column(name = "argument_name")
   private List<String> arguments = new ArrayList<>();
 
+  /**
+   * Map model object to which function belongs to.
+   */
+  @ManyToOne(fetch = FetchType.LAZY)
+  private ModelData model;
+
   /**
    * Constructor required by hibernate.
    */
@@ -77,7 +87,7 @@ public class SbmlFunction implements Serializable, SbmlArgument {
     this.functionId = original.getFunctionId();
     this.definition = original.getDefinition();
     this.name = original.getName();
-    for (String argument: original.getArguments()) {
+    for (String argument : original.getArguments()) {
       this.addArgument(argument);
     }
   }
@@ -128,4 +138,12 @@ public class SbmlFunction implements Serializable, SbmlArgument {
     return getFunctionId();
   }
 
+  public ModelData getModel() {
+    return model;
+  }
+
+  public void setModel(ModelData model) {
+    this.model = model;
+  }
+
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlKinetics.java b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlKinetics.java
index a4f1ec484c..aa0a577447 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlKinetics.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlKinetics.java
@@ -9,10 +9,15 @@ import java.util.Set;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
-import javax.persistence.OneToMany;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
 import javax.persistence.Table;
 import javax.xml.bind.annotation.XmlRootElement;
 
@@ -20,6 +25,7 @@ import org.apache.log4j.Logger;
 import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.CascadeType;
 
+import lcsb.mapviewer.model.map.reaction.Reaction;
 import lcsb.mapviewer.model.map.species.Element;
 
 /**
@@ -46,13 +52,24 @@ public class SbmlKinetics implements Serializable {
   private static final long serialVersionUID = 1L;
 
   @Cascade({ CascadeType.ALL })
-  @OneToMany(mappedBy = "model", orphanRemoval = true)
+  @ManyToMany(fetch = FetchType.EAGER)
+  @JoinTable(name = "kinetic_law_parameters", joinColumns = {
+      @JoinColumn(name = "kinetic_law_id", referencedColumnName = "idDb", nullable = false, updatable = false) }, inverseJoinColumns = {
+          @JoinColumn(name = "parameter_id", referencedColumnName = "idDb", nullable = true, updatable = true) })
   private Set<SbmlParameter> parameters = new HashSet<>();
 
   @Cascade({ CascadeType.ALL })
-  @OneToMany(mappedBy = "model", orphanRemoval = true)
+  @ManyToMany(fetch = FetchType.EAGER)
+  @JoinTable(name = "kinetic_law_functions", joinColumns = {
+      @JoinColumn(name = "kinetic_law_id", referencedColumnName = "idDb", nullable = false, updatable = false) }, inverseJoinColumns = {
+          @JoinColumn(name = "function_id", referencedColumnName = "idDb", nullable = true, updatable = true) })
   private Set<SbmlFunction> functions = new HashSet<>();
 
+  @Cascade({ CascadeType.ALL })
+  @ManyToMany(fetch = FetchType.EAGER)
+  @JoinTable(name = "kinetic_law_elements", joinColumns = {
+      @JoinColumn(name = "kinetic_law_id", referencedColumnName = "idDb", nullable = false, updatable = false) }, inverseJoinColumns = {
+          @JoinColumn(name = "element_id", referencedColumnName = "idDb", nullable = true, updatable = true) })
   private Set<Element> elements = new HashSet<>();
 
   /**
@@ -163,5 +180,4 @@ public class SbmlKinetics implements Serializable {
   public void removeElement(Element elementToRemove) {
     elements.remove(elementToRemove);
   }
-
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlParameter.java b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlParameter.java
index cef71ff79a..acd4e885ec 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlParameter.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlParameter.java
@@ -4,9 +4,11 @@ import java.io.Serializable;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
+import javax.persistence.ManyToOne;
 import javax.persistence.Table;
 import javax.xml.bind.annotation.XmlRootElement;
 
@@ -48,6 +50,8 @@ public class SbmlParameter implements Serializable, SbmlArgument {
   private String name;
 
   private Double value;
+  
+  @ManyToOne()
   private SbmlUnit units;
 
   /**
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlUnit.java b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlUnit.java
index 004f9c533b..3a0b60ad84 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlUnit.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlUnit.java
@@ -2,18 +2,24 @@ package lcsb.mapviewer.model.map.kinetics;
 
 import java.io.Serializable;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
 import javax.persistence.Table;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import org.apache.log4j.Logger;
+import org.hibernate.annotations.Cascade;
+import org.hibernate.annotations.CascadeType;
+
+import lcsb.mapviewer.model.map.model.ModelData;
 
 /**
  * Representation of a single SBML unit
@@ -49,8 +55,16 @@ public class SbmlUnit implements Serializable {
   private String unitId;
   private String name;
 
+  @Cascade({ CascadeType.ALL })
+  @OneToMany(mappedBy = "unit", orphanRemoval = true)
   private Set<SbmlUnitTypeFactor> unitTypeFactors = new HashSet<>();
 
+  /**
+   * Map model object to which unit belongs to.
+   */
+  @ManyToOne(fetch = FetchType.LAZY)
+  private ModelData model;
+
   /**
    * Constructor required by hibernate.
    */
@@ -80,10 +94,19 @@ public class SbmlUnit implements Serializable {
 
   public void addUnitTypeFactor(SbmlUnitTypeFactor factor) {
     unitTypeFactors.add(factor);
+    factor.setUnit(this);
   }
 
   public Set<SbmlUnitTypeFactor> getUnitTypeFactors() {
     return unitTypeFactors;
   }
 
+  public ModelData getModel() {
+    return model;
+  }
+
+  public void setModel(ModelData model) {
+    this.model = model;
+  }
+
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlUnitTypeFactor.java b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlUnitTypeFactor.java
index 16f20feb52..1e4c15b550 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlUnitTypeFactor.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlUnitTypeFactor.java
@@ -4,14 +4,20 @@ import java.io.Serializable;
 
 import javax.persistence.Column;
 import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
+import javax.persistence.ManyToOne;
 import javax.persistence.Table;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import org.apache.log4j.Logger;
 
+import lcsb.mapviewer.model.map.model.ModelData;
+
 /**
  * Representation of a single SBML unit factor. For example unit for velocity is
  * m/s. It means that we have two unit types here:
@@ -48,12 +54,16 @@ public class SbmlUnitTypeFactor implements Serializable {
   @Column(name = "idDb", unique = true, nullable = false)
   private int id;
 
+  @Enumerated(EnumType.STRING)
   private SbmlUnitType unitType;
 
   private int exponent = 1;
   private int scale = 0;
   private double multiplier = 1.0;
 
+  @ManyToOne(fetch = FetchType.LAZY)
+  private SbmlUnit unit;
+
   /**
    * Constructor required by hibernate.
    */
@@ -100,4 +110,12 @@ public class SbmlUnitTypeFactor implements Serializable {
     this.multiplier = multiplier;
   }
 
+  public SbmlUnit getUnit() {
+    return unit;
+  }
+
+  public void setUnit(SbmlUnit unit) {
+    this.unit = unit;
+  }
+
 }
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/model/ModelData.java b/model/src/main/java/lcsb/mapviewer/model/map/model/ModelData.java
index f0644e2241..4090c9f25a 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/model/ModelData.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/model/ModelData.java
@@ -14,6 +14,9 @@ import javax.persistence.FetchType;
 import javax.persistence.GeneratedValue;
 import javax.persistence.GenerationType;
 import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
 import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
 import javax.persistence.OrderBy;
@@ -115,7 +118,10 @@ public class ModelData implements Serializable {
   private Set<SbmlFunction> functions = new HashSet<>();
 
   @Cascade({ CascadeType.ALL })
-  @OneToMany(mappedBy = "model", orphanRemoval = true)
+  @ManyToMany(fetch = FetchType.EAGER)
+  @JoinTable(name = "model_parameters", joinColumns = {
+      @JoinColumn(name = "model_id", referencedColumnName = "idDb", nullable = false, updatable = false) }, inverseJoinColumns = {
+          @JoinColumn(name = "parameter_id", referencedColumnName = "idDb", nullable = true, updatable = true) })
   private Set<SbmlParameter> parameters = new HashSet<>();
 
   @Cascade({ CascadeType.ALL })
@@ -763,7 +769,9 @@ public class ModelData implements Serializable {
   }
 
   public void addUnits(Collection<SbmlUnit> units) {
-    this.units.addAll(units);
+    for (SbmlUnit sbmlUnit : units) {
+      addUnit(sbmlUnit);
+    }
   }
 
   public Set<SbmlUnit> getUnits() {
@@ -772,6 +780,7 @@ public class ModelData implements Serializable {
 
   public void addUnit(SbmlUnit unit) {
     this.units.add(unit);
+    unit.setModel(this);
   }
 
   public void addParameters(Collection<SbmlParameter> sbmlParameters) {
@@ -784,5 +793,12 @@ public class ModelData implements Serializable {
 
   public void addFunction(SbmlFunction sbmlFunction) {
     this.functions.add(sbmlFunction);
+    sbmlFunction.setModel(this);
+  }
+
+  public void addFunctions(Collection<SbmlFunction> functions) {
+    for (SbmlFunction sbmlFunction : functions) {
+      addFunction(sbmlFunction);
+    }
   }
 }
\ No newline at end of file
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/model/ModelFullIndexed.java b/model/src/main/java/lcsb/mapviewer/model/map/model/ModelFullIndexed.java
index 93768e9ab6..4d2d833420 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/model/ModelFullIndexed.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/model/ModelFullIndexed.java
@@ -18,7 +18,6 @@ import lcsb.mapviewer.model.map.BioEntity;
 import lcsb.mapviewer.model.map.MiriamData;
 import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.graph.DataMiningSet;
-import lcsb.mapviewer.model.map.kinetics.SbmlArgument;
 import lcsb.mapviewer.model.map.kinetics.SbmlFunction;
 import lcsb.mapviewer.model.map.kinetics.SbmlParameter;
 import lcsb.mapviewer.model.map.kinetics.SbmlUnit;
@@ -667,7 +666,7 @@ public class ModelFullIndexed implements Model {
 
   @Override
   public void addFunctions(Collection<SbmlFunction> functions) {
-    modelData.getFunctions().addAll(functions);
+    modelData.addFunctions(functions);
   }
 
   @Override
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java b/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java
index 43299fd65b..567e40b0cf 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java
@@ -27,6 +27,7 @@ import javax.persistence.JoinTable;
 import javax.persistence.ManyToMany;
 import javax.persistence.ManyToOne;
 import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
 import javax.persistence.OrderBy;
 import javax.persistence.Table;
 import javax.xml.bind.annotation.XmlTransient;
@@ -36,7 +37,6 @@ import org.hibernate.annotations.Cascade;
 import org.hibernate.annotations.CascadeType;
 import org.hibernate.annotations.IndexColumn;
 
-import lcsb.mapviewer.common.exception.InvalidStateException;
 import lcsb.mapviewer.common.exception.NotImplementedException;
 import lcsb.mapviewer.common.geometry.LineTransformation;
 import lcsb.mapviewer.model.map.BioEntity;
@@ -209,6 +209,8 @@ public class Reaction implements BioEntity {
   @ManyToOne(fetch = FetchType.LAZY)
   private ModelData model;
 
+  @Cascade({ CascadeType.ALL })
+  @OneToOne
   private SbmlKinetics kinetics;
 
   /**
diff --git a/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java b/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java
index 5f8e2f0b25..9d631041aa 100644
--- a/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java
+++ b/model/src/main/java/lcsb/mapviewer/model/map/species/Species.java
@@ -127,6 +127,7 @@ public abstract class Species extends Element {
 
   private Boolean constant;
 
+  @Enumerated(EnumType.STRING)
   private SbmlUnitType substanceUnits;
 
   /**
diff --git a/persist/src/db/12.0.0/fix_db_20180206.sql b/persist/src/db/12.0.0/fix_db_20180206.sql
new file mode 100644
index 0000000000..ec3c2a8e25
--- /dev/null
+++ b/persist/src/db/12.0.0/fix_db_20180206.sql
@@ -0,0 +1,208 @@
+alter table element_table drop column if exists boundarycondition;
+alter table element_table add boundarycondition boolean;
+
+alter table element_table drop column if exists constant;
+alter table element_table add constant boolean;
+
+alter table element_table drop column if exists substanceunits;
+alter table element_table add substanceunits varchar(255);
+
+alter table reaction_table drop column if exists kineticlaw;
+
+alter table reaction_table drop column if exists kinetics_iddb;
+alter table reaction_table add kinetics_iddb integer;
+
+drop table if exists kinetic_law_parameters;
+drop table if exists kinetic_law_functions;
+drop table if exists kinetic_law_elements;
+drop table if exists sbml_function_arguments;
+drop table if exists sbml_unit_factor;
+DROP SEQUENCE if exists sbml_unit_factor_iddb_seq;
+drop table if exists sbml_kinetics;
+DROP SEQUENCE if exists sbml_kinetics_iddb_seq;
+drop table if exists sbml_function;
+DROP SEQUENCE if exists sbml_function_iddb_seq;
+drop table if exists model_parameters;
+drop table if exists sbml_parameter;
+DROP SEQUENCE if exists sbml_parameter_iddb_seq;
+drop table if exists sbml_unit;
+DROP SEQUENCE if exists sbml_unit_iddb_seq;
+
+--definition of sbml unit
+
+CREATE SEQUENCE sbml_unit_iddb_seq
+  INCREMENT 1
+  MINVALUE 1
+  MAXVALUE 9223372036854775807
+  START 1
+  CACHE 1;
+
+CREATE TABLE sbml_unit
+(
+  iddb integer NOT NULL DEFAULT nextval('sbml_unit_iddb_seq'::regclass),
+  unitid  varchar(255),  
+  name  varchar(255),
+  model_iddb integer NOT NULL,
+  
+  CONSTRAINT sbml_unit_pk PRIMARY KEY (iddb),
+  CONSTRAINT sbml_unit_model_fk FOREIGN KEY (model_iddb)
+      REFERENCES public.model_table (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+);
+
+--definition of sbml parameter
+CREATE SEQUENCE sbml_parameter_iddb_seq
+  INCREMENT 1
+  MINVALUE 1
+  MAXVALUE 9223372036854775807
+  START 1
+  CACHE 1;
+
+CREATE TABLE sbml_parameter
+(
+  iddb integer NOT NULL DEFAULT nextval('sbml_parameter_iddb_seq'::regclass),
+  parameterid  varchar(255),  
+  name  varchar(255),
+	value  numeric,
+	units_iddb integer,
+  
+  CONSTRAINT sbml_parameter_pk PRIMARY KEY (iddb),
+  CONSTRAINT sbml_parameter_units_fk FOREIGN KEY (units_iddb)
+      REFERENCES public.sbml_unit (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+);
+
+
+--definition of many to many relation between model and sbml parameter
+CREATE TABLE model_parameters
+(
+  model_id integer NOT NULL,
+  parameter_id integer NOT NULL,  
+  CONSTRAINT model_parameters_unique UNIQUE (model_id, parameter_id),
+  CONSTRAINT model_parameters_model_fk FOREIGN KEY (model_id)
+      REFERENCES public.model_table (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE,
+  CONSTRAINT model_parameters_parameter_fk FOREIGN KEY (parameter_id)
+      REFERENCES public.sbml_parameter (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+);
+
+--definition of sbml function
+CREATE SEQUENCE sbml_function_iddb_seq
+  INCREMENT 1
+  MINVALUE 1
+  MAXVALUE 9223372036854775807
+  START 1
+  CACHE 1;
+
+CREATE TABLE sbml_function
+(
+  iddb integer NOT NULL DEFAULT nextval('sbml_function_iddb_seq'::regclass),
+  functionid  varchar(255),  
+  name  varchar(255),
+  definition  text,
+  model_iddb integer NOT NULL,
+  
+  CONSTRAINT sbml_function_pk PRIMARY KEY (iddb),
+  CONSTRAINT sbml_function_model_fk FOREIGN KEY (model_iddb)
+      REFERENCES public.model_table (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+);
+
+--definition of sbml kinetics
+CREATE SEQUENCE sbml_kinetics_iddb_seq
+  INCREMENT 1
+  MINVALUE 1
+  MAXVALUE 9223372036854775807
+  START 1
+  CACHE 1;
+
+CREATE TABLE sbml_kinetics
+(
+  iddb integer NOT NULL DEFAULT nextval('sbml_function_iddb_seq'::regclass),
+  definition  text,
+  
+  CONSTRAINT sbml_kinetics_pk PRIMARY KEY (iddb)
+);
+
+ALTER TABLE reaction_table ADD FOREIGN KEY (kinetics_iddb) REFERENCES sbml_kinetics(iddb);
+
+
+--definition of sbml kinetics
+CREATE SEQUENCE sbml_unit_factor_iddb_seq
+  INCREMENT 1
+  MINVALUE 1
+  MAXVALUE 9223372036854775807
+  START 1
+  CACHE 1;
+
+CREATE TABLE sbml_unit_factor
+(
+  iddb integer NOT NULL DEFAULT nextval('sbml_unit_factor_iddb_seq'::regclass),
+  unit_iddb  integer not null,
+  exponent  integer not null default 1,
+  scale  integer not null default 0,
+  multiplier  numeric not null default 1.0,
+  unittype varchar(255), 
+  
+  CONSTRAINT sbml_unit_factor_pk PRIMARY KEY (iddb),
+  CONSTRAINT sbml_unit_factor_unit_fk FOREIGN KEY (unit_iddb)
+      REFERENCES public.sbml_unit (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+  
+);
+
+CREATE TABLE sbml_function_arguments
+(
+  idx integer NOT NULL,
+  sbml_function_iddb integer not null,
+  argument_name varchar(255), 
+  
+  CONSTRAINT sbml_function_arguments_sbml_function_fk FOREIGN KEY (sbml_function_iddb)
+      REFERENCES public.sbml_function (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+  
+);
+
+CREATE TABLE kinetic_law_parameters
+(
+  kinetic_law_id integer NOT NULL,
+  parameter_id integer not null,
+  
+  CONSTRAINT kinetic_law_parameters_unique UNIQUE (kinetic_law_id, parameter_id),
+  CONSTRAINT kinetic_law_parameters_sbml_kinetics_fk FOREIGN KEY (kinetic_law_id)
+      REFERENCES public.sbml_kinetics (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE,
+  CONSTRAINT kinetic_law_parameters_parameter_fk FOREIGN KEY (parameter_id)
+      REFERENCES public.sbml_parameter (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+);
+
+CREATE TABLE kinetic_law_functions
+(
+  kinetic_law_id integer NOT NULL,
+  function_id integer not null,
+  
+  CONSTRAINT kinetic_law_functions_unique UNIQUE (kinetic_law_id, function_id),
+  CONSTRAINT kinetic_law_functions_sbml_kinetics_fk FOREIGN KEY (kinetic_law_id)
+      REFERENCES public.sbml_kinetics (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE,
+  CONSTRAINT kinetic_law_functions_function_fk FOREIGN KEY (function_id)
+      REFERENCES public.sbml_function (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+);
+
+CREATE TABLE kinetic_law_elements
+(
+  kinetic_law_id integer NOT NULL,
+  element_id integer not null,
+  
+  CONSTRAINT kinetic_law_elements_unique UNIQUE (kinetic_law_id, element_id),
+  CONSTRAINT kinetic_law_elements_sbml_kinetics_fk FOREIGN KEY (kinetic_law_id)
+      REFERENCES public.sbml_kinetics (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE,
+  CONSTRAINT kinetic_law_elements_element_fk FOREIGN KEY (element_id)
+      REFERENCES public.element_table (iddb) MATCH SIMPLE
+      ON UPDATE CASCADE ON DELETE CASCADE
+);
+
diff --git a/persist/src/main/resources/applicationContext-persist.xml b/persist/src/main/resources/applicationContext-persist.xml
index 329bbf4c8b..718f752f95 100644
--- a/persist/src/main/resources/applicationContext-persist.xml
+++ b/persist/src/main/resources/applicationContext-persist.xml
@@ -98,6 +98,12 @@
 				<value>lcsb.mapviewer.model.map.OverviewLink</value>
 				<value>lcsb.mapviewer.model.map.OverviewModelLink</value>
 				<value>lcsb.mapviewer.model.map.OverviewSearchLink</value>
+
+				<value>lcsb.mapviewer.model.map.kinetics.SbmlFunction</value>
+				<value>lcsb.mapviewer.model.map.kinetics.SbmlKinetics</value>
+				<value>lcsb.mapviewer.model.map.kinetics.SbmlParameter</value>
+				<value>lcsb.mapviewer.model.map.kinetics.SbmlUnit</value>
+				<value>lcsb.mapviewer.model.map.kinetics.SbmlUnitTypeFactor</value>
 	
 				<value>lcsb.mapviewer.model.map.layout.Layout</value>
 
diff --git a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/ModelDaoTest.java b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/ModelDaoTest.java
index 315bc6abbd..a364f4f340 100644
--- a/persist/src/test/java/lcsb/mapviewer/persist/dao/map/ModelDaoTest.java
+++ b/persist/src/test/java/lcsb/mapviewer/persist/dao/map/ModelDaoTest.java
@@ -19,10 +19,17 @@ import lcsb.mapviewer.model.map.MiriamRelationType;
 import lcsb.mapviewer.model.map.MiriamType;
 import lcsb.mapviewer.model.map.compartment.Compartment;
 import lcsb.mapviewer.model.map.graph.DataMiningSet;
+import lcsb.mapviewer.model.map.kinetics.SbmlFunction;
+import lcsb.mapviewer.model.map.kinetics.SbmlKinetics;
+import lcsb.mapviewer.model.map.kinetics.SbmlParameter;
+import lcsb.mapviewer.model.map.kinetics.SbmlUnit;
+import lcsb.mapviewer.model.map.kinetics.SbmlUnitType;
+import lcsb.mapviewer.model.map.kinetics.SbmlUnitTypeFactor;
 import lcsb.mapviewer.model.map.layout.Layout;
 import lcsb.mapviewer.model.map.layout.graphics.Layer;
 import lcsb.mapviewer.model.map.layout.graphics.LayerRect;
 import lcsb.mapviewer.model.map.model.Model;
+import lcsb.mapviewer.model.map.model.ModelComparator;
 import lcsb.mapviewer.model.map.model.ModelData;
 import lcsb.mapviewer.model.map.model.ModelFullIndexed;
 import lcsb.mapviewer.model.map.reaction.Product;
@@ -38,367 +45,444 @@ import lcsb.mapviewer.model.map.species.field.ModificationResidue;
 import lcsb.mapviewer.persist.PersistTestFunctions;
 
 public class ModelDaoTest extends PersistTestFunctions {
-	Logger					logger						= Logger.getLogger(ModelDaoTest.class);
-	private Project	project;
-	String					projectId					= "Some_id";
-	int							identifierCounter	= 0;
-
-	@Before
-	public void setUp() throws Exception {
-		project = projectDao.getProjectByProjectId(projectId);
-		if (project != null) {
-			projectDao.delete(project);
-		}
-		project = new Project();
-		project.setProjectId(projectId);
-		projectDao.add(project);
-	}
-
-	@After
-	public void tearDown() throws Exception {
-		projectDao.delete(project);
-	}
-
-	@Test
-	public void testLoadFromDb() throws Exception {
-		try {
-			Model model = createModel();
-			project.addModel(model);
-			modelDao.add(model);
-			projectDao.update(project);
-			projectDao.evict(project);
-
-			modelDao.evict(model);
-			ModelData model2 = modelDao.getById(model.getId());
-			assertNotNull(model2);
-			assertFalse(model2 == model);
-
-			assertEquals(model.getElements().size(), model2.getElements().size());
-			assertEquals(model.getLayers().size(), model2.getLayers().size());
-			assertEquals(model.getReactions().size(), model2.getReactions().size());
-
-			modelDao.delete(model2);
-			model2 = modelDao.getById(model.getId());
-			assertNull(model2);
-			project = projectDao.getById(project.getId());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testIndexesReload() throws Exception {
-		try {
-			Model model = createModel();
-			project.addModel(model);
-			modelDao.add(model);
-			modelDao.evict(model);
-			ModelData model2 = modelDao.getById(model.getId());
-			Model fullModel = new ModelFullIndexed(model2);
-			assertNotNull(model2);
-
-			assertEquals(model.getElements().size(), model2.getElements().size());
-			assertEquals(model.getLayers().size(), model2.getLayers().size());
-			assertEquals(model.getReactions().size(), model2.getReactions().size());
-
-			// check if we really performed a test
-			boolean test = false;
-
-			for (Element alias : model.getElements()) {
-				assertNotNull(fullModel.getElementByElementId(alias.getElementId()));
-				test = true;
-			}
-			assertTrue(test);
-
-			test = false;
-			for (Element alias : model.getElements()) {
-				if (alias instanceof Compartment) {
-					assertNotNull(fullModel.getElementByElementId(alias.getElementId()));
-					test = true;
-				}
-			}
-			assertTrue(test);
-
-			model2.setHeight(32);
-			modelDao.update(model2.getModel());
-
-			modelDao.delete(model2);
-			model2 = modelDao.getById(model.getId());
-			assertNull(model2);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testReactionInModelAfterReload() throws Exception {
-		try {
-			Model model = createModel();
-			Reaction reaction = model.getReactions().iterator().next();
-			project.addModel(model);
-			modelDao.add(model);
-			projectDao.update(project);
-			projectDao.evict(project);
-			modelDao.evict(model);
-			ModelData model2 = modelDao.getById(model.getId());
-
-			Reaction reaction2 = null;
-			for (Reaction r : model2.getReactions()) {
-				if (r.getIdReaction().equals(reaction.getIdReaction())) {
-					reaction2 = r;
-				}
-			}
-			assertNotNull(reaction2);
-			assertFalse(reaction.equals(reaction2));
-
-			assertEquals(reaction.getNodes().size(), reaction2.getNodes().size());
-
-			modelDao.delete(model2);
-			model2 = modelDao.getById(model.getId());
-			assertNull(model2);
-			project = projectDao.getById(project.getId());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	@Test
-	public void testGetLastModelForProjectName() throws Exception {
-		try {
-			ModelData model3 = modelDao.getLastModelForProjectIdentifier(projectId, false);
-			assertNull(model3);
-
-			Model model = createModel();
-			project.addModel(model);
-			modelDao.add(model);
-
-			ModelData newModel = modelDao.getLastModelForProjectIdentifier(projectId, false);
-			assertNotNull(newModel);
-			assertEquals(model.getId(), newModel.getId());
-
-			Model model2 = createModel();
-			project.addModel(model2);
-			modelDao.add(model2);
-
-			newModel = modelDao.getLastModelForProjectIdentifier(projectId, false);
-			assertNotNull(newModel);
-			assertEquals(model2.getId(), newModel.getId());
-
-			modelDao.delete(model2);
-			modelDao.delete(model);
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	/**
-	 * After adding model to db, modification residues disappear from the model...
-	 * 
-	 * @throws Exception
-	 */
-	@Test
-	public void testModificationsInProteins() throws Exception {
-		try {
-			Model model = createModel();
-			Project project = new Project();
-			project.addModel(model);
-			projectDao.add(project);
-
-			modelDao.evict(model);
-			projectDao.evict(project);
-			Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
-
-			Protein originalSpecies = (Protein) model.getElementByElementId("pr1");
-			Protein fromDbSpecies = (Protein) model2.getElementByElementId("pr1");
-
-			assertFalse(originalSpecies.equals(fromDbSpecies));
-			assertEquals(originalSpecies.getModificationResidues().size(), fromDbSpecies.getModificationResidues().size());
-
-			project = projectDao.getById(project.getId());
-			projectDao.delete(project);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	/**
-	 * After adding model to db, miriam annotations disappear...
-	 * 
-	 * @throws Exception
-	 */
-	@Test
-	public void testMiriamInSpecies() throws Exception {
-		try {
-			Model model = createModel();
-			Project project = new Project();
-			project.addModel(model);
-			projectDao.add(project);
-
-			modelDao.evict(model);
-			projectDao.evict(project);
-			Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
-
-			Protein originalSpecies = (Protein) model.getElementByElementId("pr1");
-			Protein fromDbSpecies = (Protein) model2.getElementByElementId("pr1");
-
-			assertFalse(originalSpecies.equals(fromDbSpecies));
-			assertEquals(originalSpecies.getMiriamData().size(), fromDbSpecies.getMiriamData().size());
-
-			project = projectDao.getById(project.getId());
-			projectDao.delete(project);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	/**
-	 * After adding layouts to model.
-	 * 
-	 * @throws Exception
-	 */
-	@Test
-	public void testLayoutsInModel() throws Exception {
-		try {
-			Model model = createModel();
-
-			Layout layout = new Layout();
-			layout.setDirectory("tmp");
-			layout.setTitle("temporary name");
-			model.addLayout(layout);
-			Project project = new Project();
-			project.addModel(model);
-			projectDao.add(project);
-
-			modelDao.evict(model);
-			projectDao.evict(project);
-			ModelData model2 = modelDao.getById(model.getId());
-
-			assertEquals(1, model2.getLayouts().size());
-			assertEquals("tmp", model2.getLayouts().get(0).getDirectory());
-			assertEquals("temporary name", model2.getLayouts().get(0).getTitle());
-
-			project = projectDao.getById(project.getId());
-			projectDao.delete(project);
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
-
-	private Model createModel() {
-		Model model = new ModelFullIndexed(null);
-
-		GenericProtein alias = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "sa2");
-		model.addElement(alias);
-		alias = createSpeciesAlias(267.6666666666665, 438.75, 80.0, 40.0, "sa1117");
-		model.addElement(alias);
-		alias = createSpeciesAlias(261.6666666666665, 600.75, 92.0, 52.0, "sa1119");
-		model.addElement(alias);
-		alias = createSpeciesAlias(203.666666666667, 687.75, 98.0, 58.0, "sa1121");
-		model.addElement(alias);
-
-		alias = createSpeciesAlias(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
-		Species alias2 = createSpeciesAlias(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
-		Complex alias3 = createComplexAlias(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
-		alias3.addSpecies(alias);
-		alias3.addSpecies(alias2);
-		alias.setComplex(alias3);
-		alias2.setComplex(alias3);
-
-		model.addElement(alias);
-		model.addElement(alias2);
-		model.addElement(alias3);
-
-		Compartment cAlias = createCompartmentAlias(380.0, 416.0, 1893.0, 1866.0, "ca1");
-		model.addElement(cAlias);
-		model.setWidth(2000);
-		model.setHeight(2000);
-
-		Layer layer = new Layer();
-		model.addLayer(layer);
-
-		LayerRect lr = new LayerRect();
-		lr.setColor(Color.YELLOW);
-		layer.addLayerRect(lr);
-
-		Reaction reaction = new TransportReaction();
-		reaction.addProduct(new Product(alias));
-		reaction.addReactant(new Reactant(alias2));
-		reaction.setIdReaction("re" + identifierCounter++);
-		model.addReaction(reaction);
-
-		alias = createSpeciesAlias(264.8333333333335, 517.75, 86.0, 46.0, "pr1");
-		model.addElement(alias);
-
-		ModificationResidue mr = new ModificationResidue();
-		mr.setName("mr");
-		alias.addModificationResidue(mr);
-
-		alias.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.CHEBI, "c"));
-		return model;
-	}
-
-	private Compartment createCompartmentAlias(double x, double y, double width, double height, String aliasId) {
-		Compartment alias = new Compartment(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	private GenericProtein createSpeciesAlias(double x, double y, double width, double height, String aliasId) {
-		GenericProtein alias = new GenericProtein(aliasId);
-		alias.setName("SNCA");
-		alias.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA"));
-		alias.addMiriamData(new MiriamData(MiriamType.HGNC, "11138"));
-		alias.setElementId(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	private Complex createComplexAlias(double x, double y, double width, double height, String aliasId) {
-		Complex alias = new Complex(aliasId);
-		alias.setX(x);
-		alias.setY(y);
-		alias.setWidth(width);
-		alias.setHeight(height);
-		return alias;
-	}
-
-	@Test
-	public void testModelWithDataMining() throws Exception {
-		try {
-			Model model = createModel();
-			model.addDataMiningSet(new DataMiningSet());
-			project.addModel(model);
-			modelDao.add(model);
-			projectDao.update(project);
-			projectDao.evict(project);
-
-			modelDao.evict(model);
-			ModelData model2 = modelDao.getById(model.getId());
-			assertEquals(1, model2.getDataMiningSets().size());
-
-			project = projectDao.getById(project.getId());
-
-		} catch (Exception e) {
-			e.printStackTrace();
-			throw e;
-		}
-	}
+  ModelComparator modelComparator = new ModelComparator();
+
+  Logger logger = Logger.getLogger(ModelDaoTest.class);
+  private Project project;
+  String projectId = "Some_id";
+  int identifierCounter = 0;
+
+  @Before
+  public void setUp() throws Exception {
+    project = projectDao.getProjectByProjectId(projectId);
+    if (project != null) {
+      projectDao.delete(project);
+    }
+    project = new Project();
+    project.setProjectId(projectId);
+    projectDao.add(project);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    projectDao.delete(project);
+  }
+
+  @Test
+  public void testLoadFromDb() throws Exception {
+    try {
+      Model model = createModel();
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+      assertNotNull(model2);
+      assertFalse(model2 == model);
+
+      assertEquals(model.getElements().size(), model2.getElements().size());
+      assertEquals(model.getLayers().size(), model2.getLayers().size());
+      assertEquals(model.getReactions().size(), model2.getReactions().size());
+
+      modelDao.delete(model2);
+      model2 = modelDao.getById(model.getId());
+      assertNull(model2);
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testIndexesReload() throws Exception {
+    try {
+      Model model = createModel();
+      project.addModel(model);
+      modelDao.add(model);
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+      Model fullModel = new ModelFullIndexed(model2);
+      assertNotNull(model2);
+
+      assertEquals(model.getElements().size(), model2.getElements().size());
+      assertEquals(model.getLayers().size(), model2.getLayers().size());
+      assertEquals(model.getReactions().size(), model2.getReactions().size());
+
+      // check if we really performed a test
+      boolean test = false;
+
+      for (Element alias : model.getElements()) {
+        assertNotNull(fullModel.getElementByElementId(alias.getElementId()));
+        test = true;
+      }
+      assertTrue(test);
+
+      test = false;
+      for (Element alias : model.getElements()) {
+        if (alias instanceof Compartment) {
+          assertNotNull(fullModel.getElementByElementId(alias.getElementId()));
+          test = true;
+        }
+      }
+      assertTrue(test);
+
+      model2.setHeight(32);
+      modelDao.update(model2.getModel());
+
+      modelDao.delete(model2);
+      model2 = modelDao.getById(model.getId());
+      assertNull(model2);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testReactionInModelAfterReload() throws Exception {
+    try {
+      Model model = createModel();
+      Reaction reaction = model.getReactions().iterator().next();
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+
+      Reaction reaction2 = null;
+      for (Reaction r : model2.getReactions()) {
+        if (r.getIdReaction().equals(reaction.getIdReaction())) {
+          reaction2 = r;
+        }
+      }
+      assertNotNull(reaction2);
+      assertFalse(reaction.equals(reaction2));
+
+      assertEquals(reaction.getNodes().size(), reaction2.getNodes().size());
+
+      modelDao.delete(model2);
+      model2 = modelDao.getById(model.getId());
+      assertNull(model2);
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testReactionInWithKinetics() throws Exception {
+    try {
+      Model model = createModel();
+      Reaction reaction = model.getReactions().iterator().next();
+      SbmlKinetics kinetics = new SbmlKinetics();
+      kinetics.addElement(reaction.getReactants().get(0).getElement());
+      kinetics.addFunction(createFunction());
+      model.addFunctions(kinetics.getFunctions());
+      kinetics.addParameter(createParameter());
+      model.addUnit(kinetics.getParameters().iterator().next().getUnits());
+      reaction.setKinetics(kinetics);
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+
+      assertEquals(0, modelComparator.compare(model, new ModelFullIndexed(model2)));
+
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  @Test
+  public void testModelWithParameters() throws Exception {
+    try {
+      Model model = createModel();
+      model.addParameter(createParameter());
+      model.addUnit(model.getParameters().iterator().next().getUnits());
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+
+      assertEquals(0, modelComparator.compare(model, new ModelFullIndexed(model2)));
+
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private SbmlParameter createParameter() {
+    SbmlParameter parameter = new SbmlParameter("param_id");
+    parameter.setName("X");
+    parameter.setValue(4.7);
+    parameter.setUnits(createUnits());
+    return parameter;
+  }
+
+  private SbmlUnit createUnits() {
+    SbmlUnit unit = new SbmlUnit("unit_id");
+    unit.setName("u name");
+    unit.addUnitTypeFactor(new SbmlUnitTypeFactor(SbmlUnitType.AMPERE, 1, 2, 3));
+    return unit;
+  }
+
+  private SbmlFunction createFunction() {
+    SbmlFunction  result = new SbmlFunction ("fun_id");
+    result.setDefinition("def(k1)");
+    result.addArgument("k1");
+    result.setName("fun name");
+    return result;
+  }
+
+  @Test
+  public void testGetLastModelForProjectName() throws Exception {
+    try {
+      ModelData model3 = modelDao.getLastModelForProjectIdentifier(projectId, false);
+      assertNull(model3);
+
+      Model model = createModel();
+      project.addModel(model);
+      modelDao.add(model);
+
+      ModelData newModel = modelDao.getLastModelForProjectIdentifier(projectId, false);
+      assertNotNull(newModel);
+      assertEquals(model.getId(), newModel.getId());
+
+      Model model2 = createModel();
+      project.addModel(model2);
+      modelDao.add(model2);
+
+      newModel = modelDao.getLastModelForProjectIdentifier(projectId, false);
+      assertNotNull(newModel);
+      assertEquals(model2.getId(), newModel.getId());
+
+      modelDao.delete(model2);
+      modelDao.delete(model);
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  /**
+   * After adding model to db, modification residues disappear from the model...
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testModificationsInProteins() throws Exception {
+    try {
+      Model model = createModel();
+      Project project = new Project();
+      project.addModel(model);
+      projectDao.add(project);
+
+      modelDao.evict(model);
+      projectDao.evict(project);
+      Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
+
+      Protein originalSpecies = (Protein) model.getElementByElementId("pr1");
+      Protein fromDbSpecies = (Protein) model2.getElementByElementId("pr1");
+
+      assertFalse(originalSpecies.equals(fromDbSpecies));
+      assertEquals(originalSpecies.getModificationResidues().size(), fromDbSpecies.getModificationResidues().size());
+
+      project = projectDao.getById(project.getId());
+      projectDao.delete(project);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  /**
+   * After adding model to db, miriam annotations disappear...
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testMiriamInSpecies() throws Exception {
+    try {
+      Model model = createModel();
+      Project project = new Project();
+      project.addModel(model);
+      projectDao.add(project);
+
+      modelDao.evict(model);
+      projectDao.evict(project);
+      Model model2 = new ModelFullIndexed(modelDao.getById(model.getId()));
+
+      Protein originalSpecies = (Protein) model.getElementByElementId("pr1");
+      Protein fromDbSpecies = (Protein) model2.getElementByElementId("pr1");
+
+      assertFalse(originalSpecies.equals(fromDbSpecies));
+      assertEquals(originalSpecies.getMiriamData().size(), fromDbSpecies.getMiriamData().size());
+
+      project = projectDao.getById(project.getId());
+      projectDao.delete(project);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  /**
+   * After adding layouts to model.
+   * 
+   * @throws Exception
+   */
+  @Test
+  public void testLayoutsInModel() throws Exception {
+    try {
+      Model model = createModel();
+
+      Layout layout = new Layout();
+      layout.setDirectory("tmp");
+      layout.setTitle("temporary name");
+      model.addLayout(layout);
+      Project project = new Project();
+      project.addModel(model);
+      projectDao.add(project);
+
+      modelDao.evict(model);
+      projectDao.evict(project);
+      ModelData model2 = modelDao.getById(model.getId());
+
+      assertEquals(1, model2.getLayouts().size());
+      assertEquals("tmp", model2.getLayouts().get(0).getDirectory());
+      assertEquals("temporary name", model2.getLayouts().get(0).getTitle());
+
+      project = projectDao.getById(project.getId());
+      projectDao.delete(project);
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
+
+  private Model createModel() {
+    Model model = new ModelFullIndexed(null);
+
+    GenericProtein alias = createSpecies(264.8333333333335, 517.75, 86.0, 46.0, "sa2");
+    model.addElement(alias);
+    alias = createSpecies(267.6666666666665, 438.75, 80.0, 40.0, "sa1117");
+    model.addElement(alias);
+    alias = createSpecies(261.6666666666665, 600.75, 92.0, 52.0, "sa1119");
+    model.addElement(alias);
+    alias = createSpecies(203.666666666667, 687.75, 98.0, 58.0, "sa1121");
+    model.addElement(alias);
+
+    alias = createSpecies(817.714285714286, 287.642857142859, 80.0, 40.0, "sa1422");
+    Species alias2 = createSpecies(224.964285714286, 241.392857142859, 80.0, 40.0, "sa1419");
+    Complex alias3 = createComplex(804.714285714286, 182.642857142859, 112.0, 172.0, "csa152");
+    alias3.addSpecies(alias);
+    alias3.addSpecies(alias2);
+    alias.setComplex(alias3);
+    alias2.setComplex(alias3);
+
+    model.addElement(alias);
+    model.addElement(alias2);
+    model.addElement(alias3);
+
+    Compartment cAlias = createCompartment(380.0, 416.0, 1893.0, 1866.0, "ca1");
+    model.addElement(cAlias);
+    model.setWidth(2000);
+    model.setHeight(2000);
+
+    Layer layer = new Layer();
+    model.addLayer(layer);
+
+    LayerRect lr = new LayerRect();
+    lr.setColor(Color.YELLOW);
+    layer.addLayerRect(lr);
+
+    Reaction reaction = new TransportReaction();
+    reaction.addProduct(new Product(alias));
+    reaction.addReactant(new Reactant(alias2));
+    reaction.setIdReaction("re" + identifierCounter++);
+    model.addReaction(reaction);
+
+    alias = createSpecies(264.8333333333335, 517.75, 86.0, 46.0, "pr1");
+    model.addElement(alias);
+
+    ModificationResidue mr = new ModificationResidue();
+    mr.setName("mr");
+    alias.addModificationResidue(mr);
+
+    alias.addMiriamData(new MiriamData(MiriamRelationType.BQ_BIOL_IS_DESCRIBED_BY, MiriamType.CHEBI, "c"));
+    return model;
+  }
+
+  private Compartment createCompartment(double x, double y, double width, double height, String aliasId) {
+    Compartment alias = new Compartment(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private GenericProtein createSpecies(double x, double y, double width, double height, String aliasId) {
+    GenericProtein alias = new GenericProtein(aliasId);
+    alias.setName("SNCA");
+    alias.addMiriamData(new MiriamData(MiriamType.HGNC_SYMBOL, "SNCA"));
+    alias.addMiriamData(new MiriamData(MiriamType.HGNC, "11138"));
+    alias.setElementId(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  private Complex createComplex(double x, double y, double width, double height, String aliasId) {
+    Complex alias = new Complex(aliasId);
+    alias.setX(x);
+    alias.setY(y);
+    alias.setWidth(width);
+    alias.setHeight(height);
+    return alias;
+  }
+
+  @Test
+  public void testModelWithDataMining() throws Exception {
+    try {
+      Model model = createModel();
+      model.addDataMiningSet(new DataMiningSet());
+      project.addModel(model);
+      modelDao.add(model);
+      projectDao.update(project);
+      projectDao.evict(project);
+
+      modelDao.evict(model);
+      ModelData model2 = modelDao.getById(model.getId());
+      assertEquals(1, model2.getDataMiningSets().size());
+
+      project = projectDao.getById(project.getId());
+
+    } catch (Exception e) {
+      e.printStackTrace();
+      throw e;
+    }
+  }
 
 }
-- 
GitLab