You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@empire-db.apache.org by do...@apache.org on 2022/02/07 21:11:42 UTC

[empire-db] 01/01: EMPIREDB-369 prepare generics

This is an automated email from the ASF dual-hosted git repository.

doebele pushed a commit to branch version-3-generic
in repository https://gitbox.apache.org/repos/asf/empire-db.git

commit f81869e264ee1df1a168398dff332937359b038a
Author: Rainer Döbele <do...@apache.org>
AuthorDate: Mon Feb 7 22:11:41 2022 +0100

    EMPIREDB-369 prepare generics
---
 .../apache/empire/jsf2/components/InputTag.java    |    8 +-
 .../empire/jsf2/utils/TagEncodingHelper.java       |   20 +-
 .../main/java/org/apache/empire/data/Record.java   |    2 +-
 .../java/org/apache/empire/data/RecordData.java    |    2 +-
 .../java/org/apache/empire/db/DBCommandExpr.java   |    6 +-
 .../main/java/org/apache/empire/db/DBQuery.java    |   12 +-
 .../main/java/org/apache/empire/db/DBReader.java   |    6 +-
 .../main/java/org/apache/empire/db/DBRecord.java   | 1158 +-------------------
 .../empire/db/{DBRecord.java => DBRecordBase.java} |  501 ++-------
 .../main/java/org/apache/empire/db/DBRowSet.java   |   34 +-
 .../main/java/org/apache/empire/db/DBTable.java    |    6 +-
 .../main/java/org/apache/empire/db/DBUtils.java    |   14 +-
 .../src/main/java/org/apache/empire/db/DBView.java |    4 +-
 .../db/exceptions/RecordReadOnlyException.java     |    4 +-
 .../apache/empire/db/list/DBRecordListFactory.java |    4 +-
 .../empire/db/list/DBRecordListFactoryImpl.java    |    6 +-
 16 files changed, 190 insertions(+), 1597 deletions(-)

diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
index c457cab..6a8309f 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/components/InputTag.java
@@ -31,7 +31,7 @@ import javax.faces.convert.ConverterException;
 import javax.faces.view.AttachedObjectHandler;
 
 import org.apache.empire.data.Column;
-import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordBase;
 import org.apache.empire.db.exceptions.FieldIllegalValueException;
 import org.apache.empire.exceptions.EmpireException;
 import org.apache.empire.exceptions.InvalidArgumentException;
@@ -152,12 +152,12 @@ public class InputTag extends UIInput implements NamingContainer
                 throw new InvalidArgumentException("column", null);
             // Check record
             Object record = helper.getRecord();
-            if (record!=null && (record instanceof DBRecord) && ((DBRecord)record).isValid())
+            if (record!=null && (record instanceof DBRecordBase) && ((DBRecordBase)record).isValid())
             {   // Check if column exists
-                if (((DBRecord)record).getFieldIndex(column)<0)
+                if (((DBRecordBase)record).getFieldIndex(column)<0)
                     throw new InvalidArgumentException("column", column.getName());
                 // not visible
-                log.info("Column {} is not visible for record of {} and will not be rendered!", column.getName(), ((DBRecord)record).getRowSet().getName());
+                log.info("Column {} is not visible for record of {} and will not be rendered!", column.getName(), ((DBRecordBase)record).getRowSet().getName());
             }    
             else
             {   // Record not valid
diff --git a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
index ede9cc8..808b26a 100644
--- a/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
+++ b/empire-db-jsf2/src/main/java/org/apache/empire/jsf2/utils/TagEncodingHelper.java
@@ -51,7 +51,7 @@ import org.apache.empire.data.Record;
 import org.apache.empire.data.RecordData;
 import org.apache.empire.db.DBColumn;
 import org.apache.empire.db.DBDatabase;
-import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordBase;
 import org.apache.empire.db.DBRowSet;
 import org.apache.empire.db.exceptions.FieldNotNullException;
 import org.apache.empire.exceptions.BeanPropertyGetException;
@@ -554,11 +554,11 @@ public class TagEncodingHelper implements NamingContainer
             {   // Record has changed
                 if (log.isTraceEnabled())
                 {   // Debug output
-                    if ((rec instanceof DBRecord) && (this.record instanceof DBRecord))
+                    if ((rec instanceof DBRecordBase) && (this.record instanceof DBRecordBase))
                     {   // a database record change
-                        String keyOld = StringUtils.toString(((DBRecord)this.record).getKey());
-                        String keyNew = StringUtils.toString(((DBRecord)rec).getKey());
-                        String rowSet = StringUtils.valueOf(((DBRecord)rec).getRowSet().getName());
+                        String keyOld = StringUtils.toString(((DBRecordBase)this.record).getKey());
+                        String keyNew = StringUtils.toString(((DBRecordBase)rec).getKey());
+                        String rowSet = StringUtils.valueOf(((DBRecordBase)rec).getRowSet().getName());
                         log.trace("Changing "+component.getClass().getSimpleName()+" record of rowset "+rowSet+" from {} to {}", keyOld, keyNew);
                     }
                     else
@@ -760,7 +760,7 @@ public class TagEncodingHelper implements NamingContainer
                 }
                 // check whether to skip validation
                 boolean reenableValidation = false;
-                if (skipValidation && (record instanceof DBRecord))
+                if (skipValidation && (record instanceof DBRecordBase))
                 {   // Ignore read only values
                     if (this.isReadOnly())
                         return;
@@ -768,9 +768,9 @@ public class TagEncodingHelper implements NamingContainer
                     if (ObjectUtils.isEmpty(value) && ((Record) this.record).isFieldRequired(column))
                         return; // Cannot set required value to null
                     // Disable Validation
-                    reenableValidation = ((DBRecord)record).isValidateFieldValues();
+                    reenableValidation = ((DBRecordBase)record).isValidateFieldValues();
                     if (reenableValidation)
-                        ((DBRecord)record).setValidateFieldValues(false);
+                        ((DBRecordBase)record).setValidateFieldValues(false);
                     // Validation skipped for
                     if (log.isDebugEnabled())
                         log.debug("Input Validation skipped for {}.", column.getName());
@@ -782,7 +782,7 @@ public class TagEncodingHelper implements NamingContainer
                 } finally {
                     // re-enable validation
                     if (reenableValidation)
-                        ((DBRecord)record).setValidateFieldValues(true);
+                        ((DBRecordBase)record).setValidateFieldValues(true);
                 }
             }
             else if (record instanceof RecordData)
@@ -851,7 +851,7 @@ public class TagEncodingHelper implements NamingContainer
         if (this.record!=null)
         {   // Check attribute
             Object recordTagValue = getTagAttributeValue("record");
-            if ((recordTagValue instanceof DBRecord) && this.record!=recordTagValue)
+            if ((recordTagValue instanceof DBRecordBase) && this.record!=recordTagValue)
             {   // shoud not come here
                 log.warn("Record in call to IsVisible has unexpectedly changed!");
                 this.record=null;
diff --git a/empire-db/src/main/java/org/apache/empire/data/Record.java b/empire-db/src/main/java/org/apache/empire/data/Record.java
index afbd9a2..0c9b3d0 100644
--- a/empire-db/src/main/java/org/apache/empire/data/Record.java
+++ b/empire-db/src/main/java/org/apache/empire/data/Record.java
@@ -31,7 +31,7 @@ import org.apache.empire.exceptions.InvalidArgumentException;
  * <P>
  * This interface inherits from RecordData which provides further data access methods.
  * <P>
- * The Record interface is implemented by the class {@link org.apache.empire.db.DBRecord}
+ * The Record interface is implemented by the class {@link org.apache.empire.db.DBRecordBase}
  */
 public interface Record extends RecordData
 {
diff --git a/empire-db/src/main/java/org/apache/empire/data/RecordData.java b/empire-db/src/main/java/org/apache/empire/data/RecordData.java
index 0fd9acf..6e37c3e 100644
--- a/empire-db/src/main/java/org/apache/empire/data/RecordData.java
+++ b/empire-db/src/main/java/org/apache/empire/data/RecordData.java
@@ -24,7 +24,7 @@ import java.util.Collection;
  * The RecordData interface provides methods for accessing data and context specific metadata.
  * <P>
  * The Record interface is implemented by the classes {@link org.apache.empire.db.DBReader}
- * and {@link org.apache.empire.db.DBRecord}.
+ * and {@link org.apache.empire.db.DBRecordData}.
  * <P>
  */
 public interface RecordData
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java b/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
index fb48502..f78ea46 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBCommandExpr.java
@@ -120,21 +120,21 @@ public abstract class DBCommandExpr extends DBExpr
 
         /** throws ERR_NOTSUPPORTED */
         @Override
-        public void createRecord(DBRecord record, Object[] initalKey, boolean deferredInit)
+        public void createRecord(DBRecordBase record, Object[] initalKey, boolean deferredInit)
         {
             throw new NotSupportedException(this, "addRecord");
         }
 
         /** throws ERR_NOTSUPPORTED */
         @Override
-        public void readRecord(DBRecord record, Object[] key)
+        public void readRecord(DBRecordBase record, Object[] key)
         {
             throw new NotSupportedException(this, "getRecord");
         }
 
         /** throws ERR_NOTSUPPORTED */
         @Override
-        public void updateRecord(DBRecord rec)
+        public void updateRecord(DBRecordBase rec)
         {
             throw new NotSupportedException(this, "updateRecord");
         }
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
index adcb882..166634b 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBQuery.java
@@ -305,7 +305,7 @@ public class DBQuery extends DBRowSet
      * @param record the DBRecord object, contains all fields and the field properties
      * @return a array of primary key columns
      */
-    protected Object[] getRecordKey(DBRecord record)
+    protected Object[] getRecordKey(DBRecordBase record)
     {
         if (record == null || record.getRowSet() != this)
             throw new InvalidArgumentException("record", record);
@@ -341,7 +341,7 @@ public class DBQuery extends DBRowSet
      * Add rowset data
      */
     @Override
-    public void initRecord(DBRecord record, DBRecordData recData)
+    public void initRecord(DBRecordBase record, DBRecordData recData)
     {
         // init
         super.initRecord(record, recData);
@@ -371,7 +371,7 @@ public class DBQuery extends DBRowSet
      * @throws NotImplementedException because this is not implemented
      */
     @Override
-    public void createRecord(DBRecord record, Object[] initalKey, boolean deferredInit)
+    public void createRecord(DBRecordBase record, Object[] initalKey, boolean deferredInit)
     {
         throw new NotImplementedException(this, "createRecord");
     }
@@ -384,7 +384,7 @@ public class DBQuery extends DBRowSet
      * @param conn a valid connection to the database.
      */
     @Override
-    public void readRecord(DBRecord record, Object[] key)
+    public void readRecord(DBRecordBase record, Object[] key)
     {
         if (record == null)
             throw new InvalidArgumentException("conn|rec", null);
@@ -411,7 +411,7 @@ public class DBQuery extends DBRowSet
      * @param conn a valid connection to the database.
      */
     @Override
-    public void updateRecord(DBRecord record)
+    public void updateRecord(DBRecordBase record)
     {
         // check updateable
         if (isUpdateable()==false)
@@ -599,7 +599,7 @@ public class DBQuery extends DBRowSet
     /**
      * Adds join restrictions to the supplied command object.
      */
-    protected boolean addJoinRestriction(DBCommand cmd, DBColumn updCol, DBColumn joinCol, DBColumn[] keyColumns, Object[] key, DBRecord record)
+    protected boolean addJoinRestriction(DBCommand cmd, DBColumn updCol, DBColumn joinCol, DBColumn[] keyColumns, Object[] key, DBRecordBase record)
     {   // Find key for foreign field
         for (int i = 0; key!=null && i < keyColumns.length; i++)
             if (keyColumns[i]==joinCol)
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBReader.java b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
index 7c8d098..15e506c 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBReader.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBReader.java
@@ -65,7 +65,7 @@ import org.w3c.dom.Element;
  *  <li>access field values directly by using one of the get... functions (see {@link DBRecordData})</li> 
  *  <li>get the rows as a list of Java Beans using by using {@link DBReader#getBeanList(Class, int)}</li> 
  *  <li>get the rows as an XML-Document using {@link DBReader#getXmlDocument()} </li> 
- *  <li>initialize a DBRecord with the current row data using {@link DBReader#initRecord(DBRowSet, DBRecord)}<br>
+ *  <li>initialize a DBRecord with the current row data using {@link DBReader#initRecord(DBRowSet, DBRecordBase)}<br>
  *      This will allow you to modify and update the data. 
  *  </li> 
  * </ul>
@@ -647,12 +647,12 @@ public class DBReader extends DBRecordData implements Closeable
      * initializes a DBRecord object with the values of the current row.
      * At least all primary key columns of the target rowset must be provided by this reader.
      * This function is equivalent to calling rowset.initRecord(rec, reader) 
-     * set also {@link DBRowSet#initRecord(DBRecord, DBRecordData)});
+     * set also {@link DBRowSet#initRecord(DBRecordBase, DBRecordData)});
      * </PRE>
      * @param rowset the rowset to which to attach
      * @param rec the record which to initialize
      */
-    public void initRecord(DBRecord rec)
+    public void initRecord(DBRecordBase rec)
     {
         // init Record
         DBRowSet rowset = rec.getRowSet();
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java b/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
index 135ff9c..abebaac 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
@@ -21,205 +21,41 @@ package org.apache.empire.db;
 import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
-import java.io.Serializable;
-import java.lang.reflect.InvocationTargetException;
 import java.sql.Connection;
-import java.util.Collection;
-import java.util.List;
 
-import org.apache.commons.beanutils.BeanUtilsBean;
-import org.apache.commons.beanutils.PropertyUtilsBean;
 import org.apache.empire.commons.ClassUtils;
-import org.apache.empire.commons.ObjectUtils;
-import org.apache.empire.commons.Options;
 import org.apache.empire.commons.StringUtils;
 import org.apache.empire.data.Column;
-import org.apache.empire.data.ColumnExpr;
-import org.apache.empire.data.Entity;
-import org.apache.empire.data.Record;
 import org.apache.empire.db.DBRowSet.PartialMode;
-import org.apache.empire.db.context.DBRollbackHandler;
-import org.apache.empire.db.exceptions.FieldReadOnlyException;
-import org.apache.empire.db.exceptions.FieldValueNotFetchedException;
 import org.apache.empire.db.exceptions.NoPrimaryKeyException;
-import org.apache.empire.db.exceptions.RecordReadOnlyException;
 import org.apache.empire.db.expr.compare.DBCompareExpr;
-import org.apache.empire.exceptions.BeanPropertyGetException;
 import org.apache.empire.exceptions.InvalidArgumentException;
 import org.apache.empire.exceptions.ItemNotFoundException;
 import org.apache.empire.exceptions.NotSupportedException;
 import org.apache.empire.exceptions.ObjectNotValidException;
 import org.apache.empire.exceptions.UnspecifiedErrorException;
-import org.apache.empire.xml.XMLUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
 
 /**
  * This class represents a record from a database table, view or query
  * 
  * The class provides methods to create, read, update and delete records
- * The class provides methods to obtain as well as to modify its fields
  * 
  * If an Idendity-column (AUTOINC) is defined, the value will be set upon creation by the dbms to the next value
  * If a Timestamp-column is defined the value will be automatically set and concurrent changes of the record will be detected
  * 
  * If changes to the record are made, but a rollback on the connection is performed, the changes will be reverted (Rollback-Handling)
  * 
- * The class provides methods that are useful for frontend-form development like
- *   - providing information about the allowed values for a field (field options)
- *   - providing information about whether or not a field is visible to the user    
- *   - providing information about whether or not a field is required (mandantory)    
- *   - providing information about whether or not a field is read-only    
- *   - providing information about whether a particular field value is valid    
- *   - providing information about whether a field was modified since it was read from the database
- *   - providing information about whether the record was modified
- * 
- * Also, field value changes, can be handled using the onFieldChanged event.
- * 
  * The record is Serializable either if the provided DBContext is serializable, or if the Context is provided on deserialization in a derived class.
  */
-public class DBRecord extends DBRecordData implements Record, Cloneable, Serializable
+public class DBRecord extends DBRecordBase
 {
     private static final long serialVersionUID = 1L;
     
     private static final Logger log  = LoggerFactory.getLogger(DBRecord.class);
     
     /**
-     * DBRecordRollbackHandler
-     * @author doebele
-     */
-    public static class DBRecordRollbackHandler implements DBRollbackHandler
-    {
-        // Logger
-        private static final Logger log = LoggerFactory.getLogger(DBRecordRollbackHandler.class);
-        
-        public final DBRecord   record;
-        
-        private final State     state;  /* the original state */
-        private Object[]        fields;
-        private boolean[]       modified;
-        private Object          rowsetData;
-        
-        public DBRecordRollbackHandler(DBRecord record)
-        {
-            this.record = record;
-            // check
-            if (record.state==State.Invalid)
-                throw new ObjectNotValidException(record);
-            // save state
-            this.state = record.state;            
-            this.modified = copy(record.modified);
-            this.fields   = copy(record.fields);
-            this.rowsetData = record.rowsetData;
-        }
-
-        @Override
-        public DBObject getObject()
-        {
-            return record;
-        }
-
-        @Override
-        public String getObjectInfo()
-        {
-            return "Record "+record.getRowSet().getName()+":"+StringUtils.arrayToString(record.getKey(), "|");
-        }
-
-        @Override
-        public void combine(DBRollbackHandler successor)
-        {
-            if (record!=successor.getObject())
-                throw new InvalidArgumentException("successor", successor);
-            // combine now
-            DBRecordRollbackHandler s = (DBRecordRollbackHandler)successor;
-            log.info("combining rollback state for record {}/{}", record.getRowSet().getName(), StringUtils.arrayToString(record.getKey(), "|"));
-            if (s.modified==null)
-            {
-                return; // not modified!
-            }
-            // copy
-            for (int i=0; i<fields.length; i++)
-            {
-                if (fields[i]!= s.fields[i])
-                    fields[i] = s.fields[i]; 
-                // not modified
-                if (modified==null)
-                    continue;
-                if (modified[i]==false && s.modified[i])
-                    modified[i] = s.modified[i]; 
-            }
-            // check modified
-            if (modified==null && s.modified!=null)
-                modified = copy(s.modified);
-        }
-
-        @Override
-        public void rollback()
-        {
-            // rollback
-            record.state = this.state;
-            record.fields = this.fields;
-            record.modified = this.modified;
-            record.rowsetData = rowsetData;
-            // done
-            if (log.isInfoEnabled())
-                log.info("Rollback for {} performed.", getObjectInfo());
-        }
-
-        @Override
-        public void discard()
-        {
-            /* nothing */
-        }
-        
-        private boolean[] copy(boolean[] other)
-        {
-            if (other==null)
-                return null;
-            boolean[] copy = new boolean[other.length];
-            for (int i=0; i<copy.length; i++)
-            {
-                copy[i] = other[i]; 
-            }
-            return copy;
-        }
-        
-        private Object[] copy(Object[] other)
-        {
-            if (other==null)
-                return null;
-            Object[] copy = new Object[other.length];
-            for (int i=0; i<copy.length; i++)
-            {
-                copy[i] = other[i]; 
-            }
-            return copy;
-        }
-    }
-  
-    /* Record state enum */
-    public enum State
-    {
-    	Invalid,
-    /*	Empty,  not used! */
-    	Valid,
-    	Modified,
-    	New;
-
-    	/* Accessors */
-    	boolean isLess(State other)
-    	{
-    		return this.ordinal()<other.ordinal();
-    	}
-    	boolean isEqualOrMore(State other)
-    	{
-    		return this.ordinal()>=other.ordinal();
-    	}
-    }
-
-    /**
      * varArgs to Array
      * @param values
      * @return
@@ -234,17 +70,9 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     // Context and RowSet
     protected final transient DBContext context;  /* transient for serialization */
     protected final transient DBRowSet  rowset;   /* transient for serialization */
-    
-    // This is the record data
-    private State           state;
-    private Object[]        fields;
-    private boolean[]       modified;
-    Object                  rowsetData; // Special Rowset Data (usually null)
 
     // options
     protected boolean       enableRollbackHandling;
-    protected boolean       validateFieldValues;
-    
     
     /**
      * Custom serialization for transient rowset.
@@ -312,14 +140,9 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
      * May be used by derived classes to provide special behaviour
      */
     protected DBRecord(DBContext context, DBRowSet rowset, boolean enableRollbackHandling)
-    {
-        // init
+    {   // init
         this.context = context;
         this.rowset = rowset;
-        this.state = State.Invalid;
-        this.fields = null;
-        this.modified = null;
-        this.rowsetData = null;
         // options
         this.enableRollbackHandling = enableRollbackHandling;
         this.validateFieldValues = true;
@@ -336,46 +159,6 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
              checkParamNull("rowset", rowset),
              context.isRollbackHandlingEnabled());
     }
-    
-    /**
-     * Closes the record by releasing all resources and resetting the record's state to invalid.
-     */
-    @Override
-    public void close()
-    {
-        // clear fields
-        fields = null;
-        modified = null;
-        rowsetData = null;
-        // change state
-        if (state!=State.Invalid)
-            changeState(State.Invalid);
-        // done
-        onRecordChanged();
-    }
-    
-    /** {@inheritDoc} */
-    @Override
-    public DBRecord clone()
-    {
-        try 
-        {
-            DBRecord rec = (DBRecord)super.clone();
-            rec.state = this.state;
-            if (rec.fields == fields && fields!=null)
-                rec.fields = fields.clone();
-            if (rec.modified == modified && modified!=null)
-                rec.modified = modified.clone();
-            rec.rowsetData = this.rowsetData;
-            rec.validateFieldValues = this.validateFieldValues;
-            return rec;
-            
-        } catch (CloneNotSupportedException e)
-        {
-            log.error("Unable to clone record.", e);
-            return null;
-        }
-    }
 
     /**
      * Returns the current Context
@@ -395,6 +178,7 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
      * 
      * @return the DBRowSet object
      */
+    @Override
     @SuppressWarnings("unchecked")
     public <T extends DBRowSet> T getRowSet()
     {
@@ -404,237 +188,36 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     }
 
     /**
-     * returns true if this record is a new record.
-     * @return true if this record is a new record
-     */
-    @Override
-    public Entity getEntity()
-    {
-        return getRowSet();
-    }
-
-    /**
-     * Returns the current DBDatabase object.
-     * 
-     * @return the current DBDatabase object
-     */
-    @Override
-    public <T extends DBDatabase> T getDatabase()
-    {
-        return getRowSet().getDatabase();
-    }
-
-    /**
-     * Returns the record state.
-     * 
-     * @return the record state
-     */
-    public State getState()
-    {
-        return state;
-    }
-
-    /**
-     * Returns true if the record is valid.
-     * 
-     * @return true if the record is valid
-     */
-    @Override
-    public boolean isValid()
-    {
-        return (state != State.Invalid);
-    }
-
-    /**
-     * Returns true if the record is valid.
-     * 
-     * @return true if the record is valid
-     */
-    @Override
-    public boolean isReadOnly()
-    {
-        if (!isValid())
-            return true;
-        DBRowSet rowset = getRowSet();
-        return (rowset==null || !rowset.isUpdateable());
-    }
-
-    /**
-     * Returns true if the record is modified.
-     * 
-     * @return true if the record is modified
-     */
-    @Override
-    public boolean isModified()
-    {
-        return (state.isEqualOrMore(State.Modified));
-    }
-
-    /**
-     * Returns true if this record is a new record.
-     * 
-     * @return true if this record is a new record
-     */
-    @Override
-    public boolean isNew()
-    {
-        return (state == State.New);
-    }
-
-    /**
-     * Returns true if this record is a existing record (valid but not new).
-     * This may be used from expression language instead of the not allowed property "new" 
-     * 
-     * @return true if this record is a existing record (valid but not new).
-     */
-    public boolean isExists()
-    {
-        return (state == State.Valid || state == State.Modified);
-    }
-
-    /**
-     * Returns the number of the columns.
-     * 
-     * @return the number of the columns
-     */
-    @Override
-    public int getFieldCount()
-    {
-        return (fields != null) ? fields.length : 0;
-    }
-
-    /**
-     * Returns the index value by a specified DBColumnExpr object.
-     * 
-     * @return the index value
-     */
-    @Override
-    public int getFieldIndex(ColumnExpr column)
-    {
-        return getRowSet().getColumnIndex(column);
-    }
-
-    /**
-     * Returns the index value by a specified column name.
-     * 
-     * @return the index value
+     * Returns whether or not RollbackHandling is enabled for this record
      */
     @Override
-    public int getFieldIndex(String column)
+    public boolean isRollbackHandlingEnabled() 
     {
-        List<DBColumn> columns = getRowSet().getColumns();
-        for (int i = 0; i < columns.size(); i++)
-        {
-            DBColumn col = columns.get(i);
-            if (col.getName().equalsIgnoreCase(column))
-                return i;
-        }
-        // not found
-        return -1;
+        return this.enableRollbackHandling;
     }
 
     /**
-     * Implements the Record Interface getColumn method.<BR>
-     * Internally calls getDBColumn()
-     * @return the Column at the specified index 
-     */
-    @Override
-    public DBColumn getColumn(int index)
-    {
-        return getRowSet().getColumn(index);
-    }
-    
-    /**
-     * Returns a DBColumnExpr object by a specified index value.
-     * @return the index value
-     */
-    @Override
-    public final ColumnExpr getColumnExpr(int index)
-    {
-        return getColumn(index);
-    }
-    
-    /**
-     * Returns true if the field was modified.
-     * 
-     * @param index the field index
-     *  
-     * @return true if the field was modified
+     * Set whether or not RollbackHandling will be performed for this record
+     * Since Rollback handling requires additional resources it should only be used if necessary
+     * Especially for bulk operations it should be disabled
+     * @param enabled flag whether to enable or disable RollbackHandling 
      */
-    public boolean wasModified(int index)
+    public void setRollbackHandlingEnabled(boolean enabled) 
     {
-        if (!isValid())
-            throw new ObjectNotValidException(this);
-        if (index < 0 || index >= fields.length)
-            throw new InvalidArgumentException("index", index);
-        // Check modified
-        if (modified == null)
-            return false;
-        return modified[index];
+        // check
+        if (enabled && !getContext().isRollbackHandlingEnabled())
+            throw new UnspecifiedErrorException("Rollback handling cannot be enabled for this record since it is not supported for this context!");
+        // enable now
+        this.enableRollbackHandling = enabled;
     }
     
     /**
-     * Returns true if the field was modified.
-     * 
-     * @return true if the field was modified
-     */
-    @Override
-    public final boolean wasModified(Column column)
-    {
-        return wasModified(getFieldIndex(column));
-    }
-
-    /**
-     * Returns true if any of the given fields was modified.
-     * 
-     * @return true if any of the given fields were modified or false otherwise
-     */
-    public final boolean wasAnyModified(Column... columns)
-    {
-        for (Column c : columns)
-        {
-            if (wasModified(getFieldIndex(c)))
-                return true;
-        }
-        return false;
-    }
-
-	/**
-     * returns an array of key columns which uniquely identify the record.
-     * @return the array of key columns if any
-     */
-    @Override
-    public Column[] getKeyColumns()
-    {
-        return getRowSet().getKeyColumns();
-    }
-
-    /**
-     * Returns a array of primary key columns by a specified DBRecord object.
-     * 
-     * @param rec the DBRecord object, contains all fields and the field properties
-     * @return a array of primary key columns
+     * Returns the record id for tables which have a single numeric primary key
+     * This method is provided for convenience in additon to the the getKey() method
+     * @return the record id
+     * @throws NoPrimaryKeyException if the table has no primary key
+     * @throws NotSupportedException if the primary key is not a single column of if the column is not numeric
      */
-    @Override
-    public Object[] getKey()
-    {
-        // Check Columns
-        Column[] keyColumns = getKeyColumns();
-        if (keyColumns == null || keyColumns.length==0)
-            throw new NoPrimaryKeyException(getRowSet());
-        // create the key
-        Object[] key = new Object[keyColumns.length];
-        for (int i = 0; i < keyColumns.length; i++)
-        {
-            key[i] = getValue(keyColumns[i]);
-            if (key[i] == null)
-            { // Primary Key not set
-                log.warn("DBRecord.getKey() failed: " + getRowSet().getName() + " primary key value is null!");
-            }
-        }
-        return key;
-    }
-    
     public long getId()
     {
         // Check Columns
@@ -649,277 +232,6 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     }
 
     /**
-     * Returns the value for the given column or null if either the index is out of range or the value is not valid (see {@link DBRecord#isValueValid(int)})
-     * @return the index value
-     */
-    @Override
-    public Object getValue(int index)
-    {   // Check state
-        if (fields == null)
-            throw new ObjectNotValidException(this);
-        // Check index
-        if (index < 0 || index>= fields.length)
-            throw new InvalidArgumentException("index", index);
-        // Special check for NO_VALUE 
-        if (fields[index] == ObjectUtils.NO_VALUE)
-            throw new FieldValueNotFetchedException(getColumn(index));
-        // Return field value
-        return fields[index];
-    }
-    
-    /**
-     * Returns whether a field value is provided i.e. the value is not DBRowSet.NO_VALUE<BR>
-     * This function is only useful in cases where records are partially loaded.<BR>
-     * 
-     * @param index the filed index
-     *  
-     * @return true if a valid value is supplied for the given field or false if value is {@link ObjectUtils#NO_VALUE}  
-     */
-    public boolean isValueValid(int index)
-    {   // Check state
-        if (fields == null)
-            throw new ObjectNotValidException(this);
-        // Check index
-        if (index < 0 || index>= fields.length)
-        {   // Index out of range
-            throw new InvalidArgumentException("index", index);
-        }
-        // Special check for NO_VALUE
-        return (fields[index] != ObjectUtils.NO_VALUE);
-    }
-
-    /**
-     * Gets the possbile Options for a field in the context of the current record.
-     * 
-     * @param column the database field column
-     *  
-     * @return the field options 
-     */
-    public Options getFieldOptions(DBColumn column)
-    {
-        // DBColumn col = ((colexpr instanceof DBColumn) ? ((DBColumn) colexpr) : colexpr.getSourceColumn());
-        return column.getOptions();
-    }
-
-    /**
-     * Gets the possbile Options for a field in the context of the current record.<BR>
-     * Same as getFieldOptions(DBColumn)
-     * @return the Option
-     */
-    @Override
-    public final Options getFieldOptions(Column column)
-    {
-        return getFieldOptions((DBColumn)column); 
-    }
-    
-    /**
-     * validates all modified values of a record
-     */
-    public void validateAllValues()
-    {
-        if (!this.isValid())
-            throw new ObjectNotValidException(this);
-        // Modified
-        if (modified == null)
-            return; // nothing to do
-        // check for field
-        for (int index=0; index<fields.length; index++)
-        {   // Modified or No value?
-            if (modified[index]==false || fields[index]==ObjectUtils.NO_VALUE)
-                continue;
-            // Auto-generated ?
-            DBColumn column = getColumn(index);
-            if (column.isAutoGenerated())
-                continue;
-            // validate this one
-            fields[index] = validateValue(column, fields[index]);
-        }
-    }
-
-    /**
-     * Sets the value of the column in the record.
-     * The functions checks if the column and the value are valid and whether the
-     * value has changed.
-     * 
-     * @param index the index of the column
-     * @param value the value
-     */
-    @Override
-    public void setValue(int index, Object value)
-    {
-        if (!isValid())
-            throw new ObjectNotValidException(this);
-        if (index < 0 || index >= fields.length)
-            throw new InvalidArgumentException("index", index);
-        // check updatable
-        checkUpdateable();
-        // Strings special
-        if ((value instanceof String) && ((String)value).length()==0)
-            value = null;
-        // Is value valid
-        Object current = fields[index]; 
-        if (current==ObjectUtils.NO_VALUE)
-            throw new FieldValueNotFetchedException(getColumn(index));
-        // convert
-        DBColumn column = getColumn(index);
-        // must convert enums
-        if (value instanceof Enum<?>)
-        {   // convert enum
-            Enum<?> enumVal = ((Enum<?>)value);
-            boolean numeric = column.getDataType().isNumeric();
-            value = ObjectUtils.getEnumValue(enumVal, numeric);
-        }
-        // Has Value changed?
-        if (ObjectUtils.compareEqual(current, value))
-        {   // value has not changed!
-            return; 
-        }
-        // Check whether we can change this field
-        if (!allowFieldChange(column))
-        {   // Read Only column may be set
-            throw new FieldReadOnlyException(column);
-        }
-        // Is Value valid?
-        if (this.validateFieldValues)
-        {   // validate
-            Object validated = validateValue(column, value);
-            if (value != validated)
-            {   // Value has been converted, check again
-                if (ObjectUtils.compareEqual(current, validated))
-                    return; 
-                // user converted value
-                value = validated;
-            }
-        }
-        // Init original values
-        modifyValue(index, value, true);
-    }
-
-    /**
-     * Sets the value of the column in the record.
-     * The functions checks if the column and the value are valid and whether the
-     * value has changed.
-     * 
-     * @param column a DBColumn object
-     * @param value the value
-     */
-    @Override
-    public final void setValue(Column column, Object value)
-    {   
-        setValue(getFieldIndex(column), value);
-    }
-
-    /**
-     * Validates a value before it is set in the record.
-     * By default, this method simply calls column.validate()
-     * @param column the column that needs to be changed
-     * @param value the new value
-     */
-    @Override
-    public Object validateValue(Column column, Object value)
-    {
-    	return column.validateValue(value);
-    }
-
-    /**
-     * Returns whether or not RollbackHandling is enabled for this record
-     */
-    public boolean isRollbackHandlingEnabled() 
-    {
-		return this.enableRollbackHandling;
-	}
-
-    /**
-     * Set whether or not RollbackHandling will be performed for this record
-     * Since Rollback handling requires additional resources it should only be used if necessary
-     * Especially for bulk operations it should be disabled
-     * @param enabled flag whether to enable or disable RollbackHandling 
-     */
-	public void setRollbackHandlingEnabled(boolean enabled) 
-	{
-	    // check
-	    if (enabled && !getContext().isRollbackHandlingEnabled())
-	        throw new UnspecifiedErrorException("Rollback handling cannot be enabled for this record since it is not supported for this context!");
-	    // enable now
-		this.enableRollbackHandling = enabled;
-	}
-
-    /**
-     * Returns whether or not values are checked for validity when calling setValue().
-     * If set to true validateValue() is called to check validity
-     * @return true if the validity of values is checked or false otherwise
-     */
-    public boolean isValidateFieldValues() 
-    {
-        return validateFieldValues;
-    }
-
-    /**
-     * Set whether or not values are checked for validity when calling setValue().
-     * If set to true validateValue() is called to check validity, otherwise not.
-     * @param validateFieldValues flag whether to check validity
-     */
-    public void setValidateFieldValues(boolean validateFieldValues) 
-    {
-        this.validateFieldValues = validateFieldValues;
-    }
-    
-    /**
-     * returns whether a field is visible to the client or not
-     * <P>
-     * May be overridden to implement context specific logic.
-     * @param column the column which to check for visibility
-     * @return true if the column is visible or false if not 
-     */
-    @Override
-    public boolean isFieldVisible(Column column)
-    {
-    	// Check value
-        int index = getRowSet().getColumnIndex(column);
-        if (index<0)
-        {   // Column not found
-            log.warn("Column {} does not exist for record of {}", column.getName(), getRowSet().getName());
-        }
-        return (index>=0 && isValueValid(index));
-    }
-    
-    /**
-     * returns whether a field is read only or not
-     * 
-     * @param column the database column 
-     * 
-     * @return true if the field is read only
-     */
-    @Override
-    public boolean isFieldReadOnly(Column column)
-    {
-        DBRowSet rowset = getRowSet();
-    	if (getFieldIndex(column)<0)
-            throw new InvalidArgumentException("column", column);
-    	// Check key column 
-        if (isValid() && !isNew() && rowset.isKeyColumn((DBColumn)column))
-        	return true;
-        // Ask RowSet
-        return (rowset.isColumnReadOnly((DBColumn)column));
-    }
-    
-    /**
-     * returns whether a field is required or not
-     * 
-     * @param column the database column 
-     * 
-     * @return true if the field is required
-     */
-    @Override
-    public boolean isFieldRequired(Column column)
-    {
-    	if (getRowSet().getColumnIndex(column)<0)
-            throw new InvalidArgumentException("column", column);
-        // from column definition
-        return (column.isRequired());
-    }
-
-    /**
      * Creates a new record
      */
     public void create(Object[] initalKey)
@@ -979,26 +291,6 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     }
 
     /**
-     * Updates the record and saves all changes in the database.
-     */
-    public void update()
-    {
-        if (!isValid())
-            throw new ObjectNotValidException(this);
-        if (!isModified())
-            return; /* Not modified. Nothing to do! */
-        if (isReadOnly())
-            throw new RecordReadOnlyException(this);
-        // check updatable
-        checkUpdateable();
-        // allow rollback
-        if (enableRollbackHandling)
-            getContext().appendRollbackHandler(createRollbackHandler());
-        // update
-        getRowSet().updateRecord(this);
-    }
-
-    /**
      * This helper function calls the DBRowset.deleteRecord method 
      * to delete the record.
      * 
@@ -1015,420 +307,16 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
         // check updatable
         checkUpdateable();
         // allow rollback
-        if (enableRollbackHandling)
+        if (isRollbackHandlingEnabled())
             getContext().appendRollbackHandler(createRollbackHandler());
         // Delete only if record is not new
         if (!isNew())
         {
             Object[] key = getKey();
+            log.info("Deleting record {}", StringUtils.arrayToString(key, "|"));
             getRowSet().deleteRecord(key, getContext());
         }
         close();
     }
-
-    /**
-     * This function set the field descriptions to the the XML tag.
-     * 
-     * @return the number of column descriptions added to the element
-     */
-    @Override
-    public int addXmlMeta(Element parent)
-    {
-        if (!isValid())
-            throw new ObjectNotValidException(this);
-        // Add Field Description
-        int count = 0;
-        List<DBColumn> columns = getRowSet().getColumns();
-        for (int i = 0; i < columns.size(); i++)
-        { // Add Field
-            DBColumn column = columns.get(i);
-            if (isFieldVisible(column)==false)
-                continue;
-            column.addXml(parent, 0);
-            count++;
-        }
-        return count;
-    }
-
-    /**
-     * Add the values of this record to the specified XML Element object.
-     * 
-     * @param parent the XML Element object
-     * @return the number of row values added to the element
-     */
-    @Override
-    public int addXmlData(Element parent)
-    {
-        if (!isValid())
-            throw new ObjectNotValidException(this);
-        // set row key
-        Column[] keyColumns = getKeyColumns();
-        if (keyColumns != null && keyColumns.length > 0)
-        { // key exits
-            if (keyColumns.length > 1)
-            { // multi-Column-id
-                StringBuilder buf = new StringBuilder();
-                for (int i = 0; i < keyColumns.length; i++)
-                { // add
-                    if (i > 0)
-                        buf.append("/");
-                    buf.append(getString(keyColumns[i]));
-                }
-                parent.setAttribute("id", buf.toString());
-            } 
-            else
-                parent.setAttribute("id", getString(keyColumns[0]));
-        }
-        // row attributes
-        if (isNew())
-            parent.setAttribute("new", "1");
-        // Add all children
-        int count = 0;
-        List<DBColumn> columns = getRowSet().getColumns();
-        for (int i = 0; i < fields.length; i++)
-        { // Read all
-            DBColumn column = columns.get(i);
-            if (isFieldVisible(column)==false)
-                continue;
-            // Add Field Value
-            String name = column.getName();
-            if (fields[i] != null)
-                XMLUtil.addElement(parent, name, getString(i));
-            else
-                XMLUtil.addElement(parent, name).setAttribute("null", "yes"); // Null-Value
-            // increase count
-            count++;
-        }
-        return count;
-    }
-
-    /**
-     * Returns a XML document with the field description an values of this record.
-     * 
-     * @return the new XML Document object
-     */
-    @Override
-    public Document getXmlDocument()
-    {
-        if (!isValid())
-            throw new ObjectNotValidException(this);
-        // Create Document
-        DBXmlDictionary xmlDic = getXmlDictionary();
-        Element root = XMLUtil.createDocument(xmlDic.getRowSetElementName());
-        DBRowSet rowset = getRowSet();
-        if (rowset.getName() != null)
-            root.setAttribute("name", rowset.getName());
-        // Add Field Description
-        if (addXmlMeta(root)>0)
-        {   // Add row Values
-            addXmlData(XMLUtil.addElement(root, xmlDic.getRowElementName()));
-        }
-        // return Document
-        return root.getOwnerDocument();
-    }
-    
-    /**
-     * Sets record values from the supplied java bean.
-     * 
-     * @return true if at least one value has been set successfully 
-     */
-    @Override
-    public int setRecordValues(Object bean, Collection<Column> ignoreList)
-    {
-        // Add all Columns
-        int count = 0;
-        for (int i = 0; i < getFieldCount(); i++)
-        { // Check Property
-            DBColumn column = getColumn(i);
-            if (column.isReadOnly())
-                continue;
-            if (ignoreList != null && ignoreList.contains(column))
-                continue; // ignore this property
-            // Get Property Name
-            String property = column.getBeanPropertyName();
-            setRecordValue(column, bean, property);
-            count++;
-        }
-        return count;
-    }
-
-    /**
-     * Sets record values from the suppied java bean.
-     * @return true if at least one value has been set sucessfully
-     */
-    @Override
-    public final int setRecordValues(Object bean)
-    {
-        return setRecordValues(bean, null);
-    }
-
-    /**
-     * Compares the record to another one
-     * @param otherObject
-     * @return true if it is the same record (but maybe a different instance)
-     */
-    public boolean isSame(DBRecord other)
-    {   // check valid
-        if (!isValid() || !other.isValid())
-            return false;
-        // compare table
-        if (!getRowSet().isSame(other.getRowSet()))
-            return false;
-        // compare key
-        Object[] key1 = getKey();
-        Object[] key2 = other.getKey();
-        return ObjectUtils.compareEqual(key1, key2);
-    }
-    
-    /**
-     * This function provides direct access to the record fields.<BR>
-     * This method is used internally be the RowSet to fill the data.<BR>
-     * @return an array of field values
-     */
-    protected Object[] getFields()
-    {
-        return fields;
-    }
-    
-    /**
-     * returns the DBXmlDictionary that should used to generate XMLDocuments<BR>
-     * @return the DBXmlDictionary
-     */
-    protected DBXmlDictionary getXmlDictionary()
-    {
-        return DBXmlDictionary.getInstance();
-    }
-    
-    /**
-     * changes the state of the record
-     * @param newState
-     */
-    protected void changeState(State newState)
-    {
-        this.state = newState;
-    }
-    
-    /**
-     * Factory function to create  createRollbackHandler();
-     * @return the DBRollbackHandler
-     */
-    protected DBRollbackHandler createRollbackHandler()
-    {
-        return new DBRecordRollbackHandler(this);
-    }
-    
-    /**
-     * This method is used internally by the RowSet to initialize the record's properties
-     * @param rowset the rowset to which to attach this record
-     * @param rowsetData any further RowSet specific data
-     * @param newRecord
-     */
-    protected void initData(boolean newRecord)
-    {
-        // Init rowset
-        DBRowSet rowset = getRowSet();
-        int colCount = rowset.getColumns().size();
-        if (fields==null || fields.length!=colCount)
-            fields = new Object[colCount];
-        else
-        {   // clear fields
-            for (int i=0; i<fields.length; i++)
-                if (fields[i]!=ObjectUtils.NO_VALUE)
-                    fields[i]=null;
-        }
-        // Set State
-        this.modified = null;
-        this.rowsetData = null;
-        changeState((rowset==null ? State.Invalid : (newRecord ? State.New : State.Valid)));
-    }
-    
-    /**
-     * This method is used internally to indicate that the record update has completed<BR>
-     * This will set change the record's state to Valid
-     * @param rowsetData additional data held by the rowset for this record (optional)
-     */
-    protected void updateComplete()
-    {
-        // Change state
-        this.modified = null;
-        changeState(State.Valid);
-    }
-    
-    /**
-     * Checks whether the record is updateable  
-     * If its read-only a RecordReadOnlyException is thrown 
-     */
-    protected void checkUpdateable()
-    {
-        if (this.isReadOnly())
-            throw new RecordReadOnlyException(this);
-    }
-    
-    /**
-     * Checks whether or not this field can be changed at all.
-     * Note: This is not equivalent to isFieldReadOnly() 
-     * @param column the column that needs to be changed
-     * @return true if it is possible to change this field for this record context
-     */
-    protected boolean allowFieldChange(DBColumn column)
-    {
-        // Check auto generated
-        if (column.isAutoGenerated() && (!isNew() || !isNull(column)))
-            return false;
-        // Check key Column
-        if (!isNew() && getRowSet().isKeyColumn(column))
-            return false;
-        // done
-        return true;
-    }
-
-    /**
-     * Modifies a column value bypassing all checks made by setValue.
-     * Use this to explicitly set invalid values i.e. for temporary storage.
-     * 
-     * @param index index of the column
-     * @param value the column value
-     */
-    protected void modifyValue(int index, Object value, boolean fireChangeEvent)
-    {   // Check valid
-        if (state == State.Invalid)
-            throw new ObjectNotValidException(this);
-        if (index < 0 || index >= fields.length)
-            throw new InvalidArgumentException("index", index);
-        // modified state array
-        if (modified == null)
-        {   modified = new boolean[fields.length];
-            for (int j = 0; j < fields.length; j++)
-                modified[j] = false;
-        }
-        // set value and modified
-        fields[index] = value;
-        modified[index] = true;
-        // set record state
-        if (state.isLess(State.Modified))
-            changeState(State.Modified);
-        // field changed event
-        if (fireChangeEvent)
-            onFieldChanged(index);
-    }
-
-    /*
-     * Sets the modified state of a column.<BR>
-     * This will force the field to be updated in the database, if set to TRUE.
-     * 
-     * @param column the column
-     * @param isModified modified or not
-     * 
-    protected void setModified(DBColumn column, boolean isModified)
-    {   // Check valid
-        if (state == State.Invalid)
-            throw new ObjectNotValidException(this);
-        // Check modified
-        if (modified == null)
-        {   // Init array
-            modified = new boolean[fields.length];
-            for (int j = 0; j < fields.length; j++)
-                modified[j] = false;
-        }
-        int index = getFieldIndex(column);
-        if (index >= 0)
-            modified[index] = isModified;
-        // Set State to modified, if not already at least modified and isModified is set to true
-        if (state.isLess(State.Modified) && isModified)
-            changeState(State.Modified);
-        // Reset state to unmodified, if currently modified and not modified anymore after the change
-        if (state == State.Modified && !isModified)
-        {
-            boolean recordNotModified = true;
-            for (int j = 0; j < fields.length; j++)
-            {
-                if (modified[j] == true)
-                {
-                    recordNotModified = false;
-                }
-            }
-            if (recordNotModified)
-            {
-                changeState(State.Valid);
-            }
-        }
-    }
-    */
-
-    /**
-     * set a record value from a particular bean property.
-     * <P>
-     * For a property called FOO this is equivalent of calling<BR>
-     *     setValue(column, bean.getFOO())
-     * <P>
-     * @param bean the Java Bean from which to read the value from
-     * @param property the name of the property
-     * @param column the column for which to set the record value
-     */
-    protected void setRecordValue(Column column, Object bean, String property)
-    {
-        if (StringUtils.isEmpty(property))
-            property = column.getBeanPropertyName();
-        try
-        {   // Get Property Value
-            PropertyUtilsBean pub = BeanUtilsBean.getInstance().getPropertyUtils();
-            Object value = pub.getSimpleProperty(bean, property);
-            // Now, set the record value
-            setValue( column, value ); 
-            // done
-        } catch (IllegalAccessException e)
-        {   log.error(bean.getClass().getName() + ": unable to get property '" + property + "'");
-            throw new BeanPropertyGetException(bean, property, e);
-        } catch (InvocationTargetException e)
-        {   log.error(bean.getClass().getName() + ": unable to get property '" + property + "'");
-            throw new BeanPropertyGetException(bean, property, e);
-        } catch (NoSuchMethodException e)
-        {   log.warn(bean.getClass().getName() + ": no getter available for property '" + property + "'");
-            throw new BeanPropertyGetException(bean, property, e);
-        }
-    }
-    
-    /**
-     * helper function to check if a given field index corresponds to one of the given columns
-     * @param index the field index
-     * @param column one or more columns to check
-     * @return true if the index is for one of the columns or false otherwise
-     */
-    protected boolean isColumn(int index, DBColumn... column)
-    {
-        if (index < 0 || index >= fields.length)
-            throw new InvalidArgumentException("index", index);
-        if (column==null)
-            throw new InvalidArgumentException("column", column);
-        Column col = getColumn(index);
-        for (int i=0; i<column.length; i++)
-        {   // compare
-            if (col==column[i])
-                return true;
-        }
-        // not found
-        return false; 
-    }
-    
-    /**
-     * Override this to do extra handling when the record changes
-     */
-    protected void onRecordChanged()
-    {
-        if (log.isTraceEnabled() && isValid())
-            log.trace("Record has been changed");
-        // Remove rollback (but not when close() is called!)
-        if (enableRollbackHandling && fields!=null)
-            getContext().removeRollbackHandler(this);
-    }
-    
-    /**
-     * Override this to get notified when a field value changes
-     */
-    protected void onFieldChanged(int i)
-    {
-        if (log.isDebugEnabled())
-            log.debug("Record field " + getColumn(i).getName() + " changed to " + String.valueOf(fields[i]));
-    }
     
 }
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java b/empire-db/src/main/java/org/apache/empire/db/DBRecordBase.java
similarity index 76%
copy from empire-db/src/main/java/org/apache/empire/db/DBRecord.java
copy to empire-db/src/main/java/org/apache/empire/db/DBRecordBase.java
index 135ff9c..ed3d09f 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRecord.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecordBase.java
@@ -18,18 +18,13 @@
  */
 package org.apache.empire.db;
 
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.lang.reflect.InvocationTargetException;
-import java.sql.Connection;
 import java.util.Collection;
 import java.util.List;
 
 import org.apache.commons.beanutils.BeanUtilsBean;
 import org.apache.commons.beanutils.PropertyUtilsBean;
-import org.apache.empire.commons.ClassUtils;
 import org.apache.empire.commons.ObjectUtils;
 import org.apache.empire.commons.Options;
 import org.apache.empire.commons.StringUtils;
@@ -37,19 +32,14 @@ import org.apache.empire.data.Column;
 import org.apache.empire.data.ColumnExpr;
 import org.apache.empire.data.Entity;
 import org.apache.empire.data.Record;
-import org.apache.empire.db.DBRowSet.PartialMode;
 import org.apache.empire.db.context.DBRollbackHandler;
 import org.apache.empire.db.exceptions.FieldReadOnlyException;
 import org.apache.empire.db.exceptions.FieldValueNotFetchedException;
 import org.apache.empire.db.exceptions.NoPrimaryKeyException;
 import org.apache.empire.db.exceptions.RecordReadOnlyException;
-import org.apache.empire.db.expr.compare.DBCompareExpr;
 import org.apache.empire.exceptions.BeanPropertyGetException;
 import org.apache.empire.exceptions.InvalidArgumentException;
-import org.apache.empire.exceptions.ItemNotFoundException;
-import org.apache.empire.exceptions.NotSupportedException;
 import org.apache.empire.exceptions.ObjectNotValidException;
-import org.apache.empire.exceptions.UnspecifiedErrorException;
 import org.apache.empire.xml.XMLUtil;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -57,15 +47,7 @@ import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 
 /**
- * This class represents a record from a database table, view or query
- * 
- * The class provides methods to create, read, update and delete records
- * The class provides methods to obtain as well as to modify its fields
- * 
- * If an Idendity-column (AUTOINC) is defined, the value will be set upon creation by the dbms to the next value
- * If a Timestamp-column is defined the value will be automatically set and concurrent changes of the record will be detected
- * 
- * If changes to the record are made, but a rollback on the connection is performed, the changes will be reverted (Rollback-Handling)
+ * This class provides write access to the fields of a record
  * 
  * The class provides methods that are useful for frontend-form development like
  *   - providing information about the allowed values for a field (field options)
@@ -77,14 +59,12 @@ import org.w3c.dom.Element;
  *   - providing information about whether the record was modified
  * 
  * Also, field value changes, can be handled using the onFieldChanged event.
- * 
- * The record is Serializable either if the provided DBContext is serializable, or if the Context is provided on deserialization in a derived class.
  */
-public class DBRecord extends DBRecordData implements Record, Cloneable, Serializable
+public abstract class DBRecordBase extends DBRecordData implements Record, Cloneable, Serializable
 {
     private static final long serialVersionUID = 1L;
     
-    private static final Logger log  = LoggerFactory.getLogger(DBRecord.class);
+    private static final Logger log  = LoggerFactory.getLogger(DBRecordBase.class);
     
     /**
      * DBRecordRollbackHandler
@@ -95,14 +75,14 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
         // Logger
         private static final Logger log = LoggerFactory.getLogger(DBRecordRollbackHandler.class);
         
-        public final DBRecord   record;
+        public final DBRecordBase   record;
         
         private final State     state;  /* the original state */
         private Object[]        fields;
         private boolean[]       modified;
         private Object          rowsetData;
-        
-        public DBRecordRollbackHandler(DBRecord record)
+    
+        public DBRecordRollbackHandler(DBRecordBase record)
         {
             this.record = record;
             // check
@@ -218,123 +198,25 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     		return this.ordinal()>=other.ordinal();
     	}
     }
-
-    /**
-     * varArgs to Array
-     * @param values
-     * @return
-     */
-    public static Object[] key(Object... values)
-    {
-        if (values.length==0)
-            throw new InvalidArgumentException("values", values);
-        return values;
-    }
-
-    // Context and RowSet
-    protected final transient DBContext context;  /* transient for serialization */
-    protected final transient DBRowSet  rowset;   /* transient for serialization */
     
     // This is the record data
     private State           state;
     private Object[]        fields;
     private boolean[]       modified;
     Object                  rowsetData; // Special Rowset Data (usually null)
-
-    // options
-    protected boolean       enableRollbackHandling;
     protected boolean       validateFieldValues;
     
-    
-    /**
-     * Custom serialization for transient rowset.
-     * 
-     */
-    private void writeObject(ObjectOutputStream strm) throws IOException 
-    {   // Context
-        writeContext(strm);
-        // RowSet
-        writeRowSet(strm);
-        // write object
-        strm.defaultWriteObject();
-    }
-    
-    protected void writeContext(ObjectOutputStream strm) throws IOException
-    {
-        strm.writeObject(context);
-    }
-    
-    protected void writeRowSet(ObjectOutputStream strm) throws IOException
-    {
-        String dbid = rowset.getDatabase().getIdentifier(); 
-        String rsid = rowset.getName(); 
-        strm.writeObject(dbid);
-        strm.writeObject(rsid);
-    }
-    
-    /**
-     * Custom deserialization for transient rowset.
-     */
-    private void readObject(ObjectInputStream strm) throws IOException, ClassNotFoundException 
-    {   // Context
-        DBContext ctx = readContext(strm);
-        ClassUtils.setPrivateFieldValue(DBRecord.class, this, "context", ctx);
-        // set final field
-        DBRowSet rowset = readRowSet(strm);
-        ClassUtils.setPrivateFieldValue(DBRecord.class, this, "rowset", rowset);
-        // read the rest
-        strm.defaultReadObject();
-    }
-    
-    protected DBContext readContext(ObjectInputStream strm)  throws IOException, ClassNotFoundException
-    {
-        return (DBContext)strm.readObject();
-    }
-    
-    protected DBRowSet readRowSet(ObjectInputStream strm)  throws IOException, ClassNotFoundException
-    {   // Rowset
-        String dbid = String.valueOf(strm.readObject());
-        String rsid = String.valueOf(strm.readObject());
-        // find database
-        DBDatabase dbo = DBDatabase.findByIdentifier(dbid);
-        if (dbo==null)
-            throw new ItemNotFoundException(dbid);
-        // find rowset
-        DBRowSet rso = dbo.getRowSet(rsid);
-        if (rso==null)
-            throw new ItemNotFoundException(dbid);
-        // done
-        return rso;
-    }
-    
     /**
      * Internal constructor for DBRecord
      * May be used by derived classes to provide special behaviour
      */
-    protected DBRecord(DBContext context, DBRowSet rowset, boolean enableRollbackHandling)
+    protected DBRecordBase()
     {
         // init
-        this.context = context;
-        this.rowset = rowset;
         this.state = State.Invalid;
         this.fields = null;
         this.modified = null;
         this.rowsetData = null;
-        // options
-        this.enableRollbackHandling = enableRollbackHandling;
-        this.validateFieldValues = true;
-    }
-
-    /**
-     * Constructs a new DBRecord.<BR>
-     * @param context the DBContext for this record
-     * @param rowset the corresponding RowSet(Table, View, Query, etc.)
-     */
-    public DBRecord(DBContext context, DBRowSet rowset)
-    {
-        this(checkParamNull("context", context),
-             checkParamNull("rowset", rowset),
-             context.isRollbackHandlingEnabled());
     }
     
     /**
@@ -356,18 +238,17 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     
     /** {@inheritDoc} */
     @Override
-    public DBRecord clone()
+    public DBRecordBase clone()
     {
         try 
         {
-            DBRecord rec = (DBRecord)super.clone();
+            DBRecordBase rec = (DBRecordBase)super.clone();
             rec.state = this.state;
             if (rec.fields == fields && fields!=null)
                 rec.fields = fields.clone();
             if (rec.modified == modified && modified!=null)
                 rec.modified = modified.clone();
             rec.rowsetData = this.rowsetData;
-            rec.validateFieldValues = this.validateFieldValues;
             return rec;
             
         } catch (CloneNotSupportedException e)
@@ -382,26 +263,18 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
      * @return
      */
     @Override
-    @SuppressWarnings("unchecked")
-    public <T extends DBContext> T  getContext()
-    {
-        if (this.context==null)
-            throw new ObjectNotValidException(this);
-        return ((T)context);
-    }
+    public abstract <T extends DBContext> T  getContext();
 
     /**
      * Returns the DBRowSet object.
-     * 
      * @return the DBRowSet object
      */
-    @SuppressWarnings("unchecked")
-    public <T extends DBRowSet> T getRowSet()
-    {
-        if (this.rowset==null)
-            throw new ObjectNotValidException(this);
-        return (T)this.rowset;
-    }
+    public abstract <T extends DBRowSet> T getRowSet();
+    
+    /**
+     * Returns whether or not RollbackHandling is enabled for this record
+     */
+    public abstract boolean isRollbackHandlingEnabled(); 
 
     /**
      * returns true if this record is a new record.
@@ -599,6 +472,26 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
         return false;
     }
 
+    /**
+     * Returns whether or not values are checked for validity when calling setValue().
+     * If set to true validateValue() is called to check validity
+     * @return true if the validity of values is checked or false otherwise
+     */
+    public boolean isValidateFieldValues() 
+    {
+        return validateFieldValues;
+    }
+
+    /**
+     * Set whether or not values are checked for validity when calling setValue().
+     * If set to true validateValue() is called to check validity, otherwise not.
+     * @param validateFieldValues flag whether to check validity
+     */
+    public void setValidateFieldValues(boolean validateFieldValues) 
+    {
+        this.validateFieldValues = validateFieldValues;
+    }
+
 	/**
      * returns an array of key columns which uniquely identify the record.
      * @return the array of key columns if any
@@ -634,22 +527,9 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
         }
         return key;
     }
-    
-    public long getId()
-    {
-        // Check Columns
-        Column[] keyColumns = getKeyColumns();
-        if (keyColumns == null || keyColumns.length==0)
-            throw new NoPrimaryKeyException(getRowSet());
-        // Check Columns
-        if (keyColumns.length!=1 || !keyColumns[0].getDataType().isNumeric())
-            throw new NotSupportedException(this, "getId");
-        // the numeric id
-        return getLong(keyColumns[0]);
-    }
 
     /**
-     * Returns the value for the given column or null if either the index is out of range or the value is not valid (see {@link DBRecord#isValueValid(int)})
+     * Returns the value for the given column or null if either the index is out of range or the value is not valid (see {@link DBRecordBase#isValueValid(int)})
      * @return the index value
      */
     @Override
@@ -780,7 +660,7 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
             throw new FieldReadOnlyException(column);
         }
         // Is Value valid?
-        if (this.validateFieldValues)
+        if (isValidateFieldValues())
         {   // validate
             Object validated = validateValue(column, value);
             if (value != validated)
@@ -820,49 +700,6 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     {
     	return column.validateValue(value);
     }
-
-    /**
-     * Returns whether or not RollbackHandling is enabled for this record
-     */
-    public boolean isRollbackHandlingEnabled() 
-    {
-		return this.enableRollbackHandling;
-	}
-
-    /**
-     * Set whether or not RollbackHandling will be performed for this record
-     * Since Rollback handling requires additional resources it should only be used if necessary
-     * Especially for bulk operations it should be disabled
-     * @param enabled flag whether to enable or disable RollbackHandling 
-     */
-	public void setRollbackHandlingEnabled(boolean enabled) 
-	{
-	    // check
-	    if (enabled && !getContext().isRollbackHandlingEnabled())
-	        throw new UnspecifiedErrorException("Rollback handling cannot be enabled for this record since it is not supported for this context!");
-	    // enable now
-		this.enableRollbackHandling = enabled;
-	}
-
-    /**
-     * Returns whether or not values are checked for validity when calling setValue().
-     * If set to true validateValue() is called to check validity
-     * @return true if the validity of values is checked or false otherwise
-     */
-    public boolean isValidateFieldValues() 
-    {
-        return validateFieldValues;
-    }
-
-    /**
-     * Set whether or not values are checked for validity when calling setValue().
-     * If set to true validateValue() is called to check validity, otherwise not.
-     * @param validateFieldValues flag whether to check validity
-     */
-    public void setValidateFieldValues(boolean validateFieldValues) 
-    {
-        this.validateFieldValues = validateFieldValues;
-    }
     
     /**
      * returns whether a field is visible to the client or not
@@ -918,64 +755,40 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
         // from column definition
         return (column.isRequired());
     }
-
-    /**
-     * Creates a new record
-     */
-    public void create(Object[] initalKey)
-    {
-        getRowSet().createRecord(this, initalKey, true);
-    }
-
-    /**
-     * Creates a new record
-     */
-    public void create()
-    {
-        getRowSet().createRecord(this, null, false);
-    }
     
     /**
-     * Reads a record from the database
-     * Hint: variable args param (Object...) caused problems with migration
-     * @param key an array of the primary key values
-     */
-    public void read(Object[] key)
-    {   // read
-        getRowSet().readRecord(this, key);
-    }
-
-    /**
-     * Reads a record from the database
-     * @param id the record id value
-     */
-    public final void read(long id)
-    {
-        read(new Object[] {id});
-    }
-    
-    /**
-     * Reads a record from the database
-     * @param key an array of the primary key values
+     * Sets record values from the supplied java bean.
+     * 
+     * @return true if at least one value has been set successfully 
      */
-    public void read(DBCompareExpr whereConstraints)
+    @Override
+    public int setRecordValues(Object bean, Collection<Column> ignoreList)
     {
-        getRowSet().readRecord(this, whereConstraints);
+        // Add all Columns
+        int count = 0;
+        for (int i = 0; i < getFieldCount(); i++)
+        { // Check Property
+            DBColumn column = getColumn(i);
+            if (column.isReadOnly())
+                continue;
+            if (ignoreList != null && ignoreList.contains(column))
+                continue; // ignore this property
+            // Get Property Name
+            String property = column.getBeanPropertyName();
+            setRecordValue(column, bean, property);
+            count++;
+        }
+        return count;
     }
-    
+
     /**
-     * Reads a record partially i.e. not with all but just some selected fields
-     * There are two modes:
-     *  1. PartialMode.INCLUDE reads only the fields provided with the column list
-     *  2. PartialMode.EXCLUDE reads all but the fields provided with the column list
-     * The primary key is always fetched implicitly
-     * @param key the primary key values
-     * @param mode flag whether to include only the given columns or whether to add all but the given columns
-     * @param columns the columns to include or exclude (depending on mode)
+     * Sets record values from the suppied java bean.
+     * @return true if at least one value has been set sucessfully
      */
-    public void read(Object[] key, PartialMode mode, DBColumn... columns)
+    @Override
+    public final int setRecordValues(Object bean)
     {
-        getRowSet().readRecord(this, key, mode, columns);
+        return setRecordValues(bean, null);
     }
 
     /**
@@ -987,43 +800,31 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
             throw new ObjectNotValidException(this);
         if (!isModified())
             return; /* Not modified. Nothing to do! */
-        if (isReadOnly())
-            throw new RecordReadOnlyException(this);
         // check updatable
         checkUpdateable();
         // allow rollback
-        if (enableRollbackHandling)
+        if (isRollbackHandlingEnabled())
             getContext().appendRollbackHandler(createRollbackHandler());
         // update
         getRowSet().updateRecord(this);
     }
 
     /**
-     * This helper function calls the DBRowset.deleteRecord method 
-     * to delete the record.
-     * 
-     * WARING: There is no guarantee that it ist called
-     * Implement delete logic in the table's deleteRecord method if possible
-     * 
-     * @see org.apache.empire.db.DBTable#deleteRecord(Object[], Connection)
-     * @param conn a valid connection to the database.
+     * Compares the record to another one
+     * @param otherObject
+     * @return true if it is the same record (but maybe a different instance)
      */
-    public void delete()
-    {
-        if (isValid()==false)
-            throw new ObjectNotValidException(this);
-        // check updatable
-        checkUpdateable();
-        // allow rollback
-        if (enableRollbackHandling)
-            getContext().appendRollbackHandler(createRollbackHandler());
-        // Delete only if record is not new
-        if (!isNew())
-        {
-            Object[] key = getKey();
-            getRowSet().deleteRecord(key, getContext());
-        }
-        close();
+    public boolean isSame(DBRecordBase other)
+    {   // check valid
+        if (!isValid() || !other.isValid())
+            return false;
+        // compare table
+        if (!getRowSet().isSame(other.getRowSet()))
+            return false;
+        // compare key
+        Object[] key1 = getKey();
+        Object[] key2 = other.getKey();
+        return ObjectUtils.compareEqual(key1, key2);
     }
 
     /**
@@ -1128,59 +929,6 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     }
     
     /**
-     * Sets record values from the supplied java bean.
-     * 
-     * @return true if at least one value has been set successfully 
-     */
-    @Override
-    public int setRecordValues(Object bean, Collection<Column> ignoreList)
-    {
-        // Add all Columns
-        int count = 0;
-        for (int i = 0; i < getFieldCount(); i++)
-        { // Check Property
-            DBColumn column = getColumn(i);
-            if (column.isReadOnly())
-                continue;
-            if (ignoreList != null && ignoreList.contains(column))
-                continue; // ignore this property
-            // Get Property Name
-            String property = column.getBeanPropertyName();
-            setRecordValue(column, bean, property);
-            count++;
-        }
-        return count;
-    }
-
-    /**
-     * Sets record values from the suppied java bean.
-     * @return true if at least one value has been set sucessfully
-     */
-    @Override
-    public final int setRecordValues(Object bean)
-    {
-        return setRecordValues(bean, null);
-    }
-
-    /**
-     * Compares the record to another one
-     * @param otherObject
-     * @return true if it is the same record (but maybe a different instance)
-     */
-    public boolean isSame(DBRecord other)
-    {   // check valid
-        if (!isValid() || !other.isValid())
-            return false;
-        // compare table
-        if (!getRowSet().isSame(other.getRowSet()))
-            return false;
-        // compare key
-        Object[] key1 = getKey();
-        Object[] key2 = other.getKey();
-        return ObjectUtils.compareEqual(key1, key2);
-    }
-    
-    /**
      * This function provides direct access to the record fields.<BR>
      * This method is used internally be the RowSet to fill the data.<BR>
      * @return an array of field values
@@ -1191,15 +939,6 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     }
     
     /**
-     * returns the DBXmlDictionary that should used to generate XMLDocuments<BR>
-     * @return the DBXmlDictionary
-     */
-    protected DBXmlDictionary getXmlDictionary()
-    {
-        return DBXmlDictionary.getInstance();
-    }
-    
-    /**
      * changes the state of the record
      * @param newState
      */
@@ -1311,49 +1050,27 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
         if (fireChangeEvent)
             onFieldChanged(index);
     }
-
-    /*
-     * Sets the modified state of a column.<BR>
-     * This will force the field to be updated in the database, if set to TRUE.
-     * 
-     * @param column the column
-     * @param isModified modified or not
-     * 
-    protected void setModified(DBColumn column, boolean isModified)
-    {   // Check valid
-        if (state == State.Invalid)
-            throw new ObjectNotValidException(this);
-        // Check modified
-        if (modified == null)
-        {   // Init array
-            modified = new boolean[fields.length];
-            for (int j = 0; j < fields.length; j++)
-                modified[j] = false;
-        }
-        int index = getFieldIndex(column);
-        if (index >= 0)
-            modified[index] = isModified;
-        // Set State to modified, if not already at least modified and isModified is set to true
-        if (state.isLess(State.Modified) && isModified)
-            changeState(State.Modified);
-        // Reset state to unmodified, if currently modified and not modified anymore after the change
-        if (state == State.Modified && !isModified)
-        {
-            boolean recordNotModified = true;
-            for (int j = 0; j < fields.length; j++)
-            {
-                if (modified[j] == true)
-                {
-                    recordNotModified = false;
-                }
-            }
-            if (recordNotModified)
-            {
-                changeState(State.Valid);
-            }
-        }
+    
+    /**
+     * Override this to do extra handling when the record changes
+     */
+    protected void onRecordChanged()
+    {
+        if (log.isTraceEnabled() && isValid())
+            log.trace("Record has been changed");
+        // Remove rollback (but not when close() is called!)
+        if (fields!=null && isRollbackHandlingEnabled())
+            getContext().removeRollbackHandler(this);
+    }
+    
+    /**
+     * Override this to get notified when a field value changes
+     */
+    protected void onFieldChanged(int i)
+    {
+        if (log.isDebugEnabled())
+            log.debug("Record field " + getColumn(i).getName() + " changed to " + String.valueOf(fields[i]));
     }
-    */
 
     /**
      * set a record value from a particular bean property.
@@ -1411,24 +1128,12 @@ public class DBRecord extends DBRecordData implements Record, Cloneable, Seriali
     }
     
     /**
-     * Override this to do extra handling when the record changes
-     */
-    protected void onRecordChanged()
-    {
-        if (log.isTraceEnabled() && isValid())
-            log.trace("Record has been changed");
-        // Remove rollback (but not when close() is called!)
-        if (enableRollbackHandling && fields!=null)
-            getContext().removeRollbackHandler(this);
-    }
-    
-    /**
-     * Override this to get notified when a field value changes
+     * returns the DBXmlDictionary that should used to generate XMLDocuments<BR>
+     * @return the DBXmlDictionary
      */
-    protected void onFieldChanged(int i)
+    protected DBXmlDictionary getXmlDictionary()
     {
-        if (log.isDebugEnabled())
-            log.debug("Record field " + getColumn(i).getName() + " changed to " + String.valueOf(fields[i]));
+        return DBXmlDictionary.getInstance();
     }
     
 }
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java b/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
index 201123c..2d58e1c 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRowSet.java
@@ -154,7 +154,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param record the record
      * @return the record
      */
-    protected void checkParamRecord(String name, DBRecord record, boolean checkValid)
+    protected void checkParamRecord(String name, DBRecordBase record, boolean checkValid)
     {
         if (record==null || record.getRowSet()!=this)
             throw new InvalidArgumentException(name, record);
@@ -289,7 +289,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
     
     public abstract boolean isUpdateable();
 
-    public abstract void createRecord(DBRecord record, Object[] initalKey, boolean deferredInit);
+    public abstract void createRecord(DBRecordBase record, Object[] initalKey, boolean deferredInit);
 
     public abstract void deleteRecord(Object[] key, DBContext context);
     
@@ -573,7 +573,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param fieldInitMode indicates how to initializes the record fields
      * @param newRecord true if the record is new or false if it is an existing record
      */
-    protected void initRecord(DBRecord record, Object[] key, FieldInitMode fieldInitMode, boolean newRecord)
+    protected void initRecord(DBRecordBase record, Object[] key, FieldInitMode fieldInitMode, boolean newRecord)
     {
         // check param
         checkParamRecord("record", record, false);
@@ -621,7 +621,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param record the record object
      * @param recData the record data from which to initialized the record
      */
-    public void initRecord(DBRecord record, DBRecordData recData)
+    public void initRecord(DBRecordBase record, DBRecordData recData)
     {
         // check param
         checkParamRecord("record", record, false);
@@ -662,7 +662,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param record the record
      * @param conn (optional) to allow the dbms handle autogenerated fields
      */
-    protected void initRecordDefaultValues(DBRecord record, FieldInitMode fieldInitMode)
+    protected void initRecordDefaultValues(DBRecordBase record, FieldInitMode fieldInitMode)
     {
         // check field init mode
         if (fieldInitMode==FieldInitMode.NONE)
@@ -690,7 +690,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param rowSetData any further RowSet specific data
      * @param insert
      */
-    protected void prepareInitRecord(DBRecord record, boolean newRecord)
+    protected void prepareInitRecord(DBRecordBase record, boolean newRecord)
     {
         if (record==null || record.getRowSet()!=this)
             throw new InvalidArgumentException("rec", record);
@@ -706,7 +706,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * <P>
      * @param record the DBRecord object to initialize
      */
-    protected void completeInitRecord(DBRecord record)
+    protected void completeInitRecord(DBRecordBase record)
     {
     	record.onRecordChanged();
     }
@@ -745,7 +745,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param cmd the SQL-Command used to query the record
      * @param rowSetData optional rowset specific data to be held on the record
      */
-    protected void readRecord(DBRecord record, DBCommand cmd)
+    protected void readRecord(DBRecordBase record, DBCommand cmd)
     {
         // check param
         checkParamRecord("record", record, false);
@@ -788,7 +788,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param record the DBRecord object which will hold the record data
      * @param key the primary key values
      */
-    public void readRecord(DBRecord record, Object[] key)
+    public void readRecord(DBRecordBase record, Object[] key)
     {
         // Check Arguments
         checkParamNull("key", key);
@@ -805,7 +805,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * Reads a record from the database
      * @param key an array of the primary key values
      */
-    public void readRecord(DBRecord record, DBCompareExpr whereConstraints)
+    public void readRecord(DBRecordBase record, DBCompareExpr whereConstraints)
     {
         // Check Arguments
         checkParamNull("whereConstraints", whereConstraints);
@@ -829,7 +829,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param mode flag whether to include only the given columns or whether to add all but the given columns
      * @param columns the columns to include or exclude (depending on mode)
      */
-    public void readRecord(DBRecord record, Object[] key, PartialMode mode, DBColumn... columns)
+    public void readRecord(DBRecordBase record, Object[] key, PartialMode mode, DBColumn... columns)
     {
         // Check Arguments
         checkParamNull("key", key);
@@ -907,7 +907,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * <P>
      * @param record the DBRecord object. contains all fields and the field properties
      */
-    public void updateRecord(DBRecord record)
+    public void updateRecord(DBRecordBase record)
     {
         // check updateable
         if (isUpdateable()==false)
@@ -929,8 +929,8 @@ public abstract class DBRowSet extends DBExpr implements Entity
         int setCount = 0;
         // Perform action
         DBColumn[] keyColumns =(DBColumn[])getKeyColumns();
-        DBRecord.State recordState = record.getState(); 
-        if (recordState==DBRecord.State.New)
+        DBRecordBase.State recordState = record.getState(); 
+        if (recordState==DBRecordBase.State.New)
         {	// Insert Record
             for (int i = 0; i < columns.size(); i++)
             {   // search for the column
@@ -975,7 +975,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
             }
             sql = cmd.getInsert();
         }
-        else if (recordState==DBRecord.State.Modified)
+        else if (recordState==DBRecordBase.State.Modified)
         {	// Update Record
             if (keyColumns == null)
             { // Requires a primary key
@@ -1163,7 +1163,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param record the record 
      * @return the rowset data
      */
-    protected final Object getRowsetData(DBRecord record)
+    protected final Object getRowsetData(DBRecordBase record)
     {
         return record.rowsetData;
     }
@@ -1173,7 +1173,7 @@ public abstract class DBRowSet extends DBExpr implements Entity
      * @param rec the record 
      * @return the rowset data
      */
-    protected final void setRowsetData(DBRecord record, Object rowsetData)
+    protected final void setRowsetData(DBRecordBase record, Object rowsetData)
     {
         record.rowsetData = rowsetData;
     }
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBTable.java b/empire-db/src/main/java/org/apache/empire/db/DBTable.java
index 7c67770..1dc70f2 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBTable.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBTable.java
@@ -578,7 +578,7 @@ public class DBTable extends DBRowSet implements Cloneable
      * @param conn a valid connection to the database.
      */
     @Override
-    public void createRecord(DBRecord record, Object[] initalKey, boolean deferredInit)
+    public void createRecord(DBRecordBase record, Object[] initalKey, boolean deferredInit)
     {
         FieldInitMode fieldInitMode = (deferredInit ? FieldInitMode.SET_DEFAULTS_DEFERRED : FieldInitMode.SET_DEFAULTS);
         super.initRecord(record, initalKey, fieldInitMode, true);
@@ -590,7 +590,7 @@ public class DBTable extends DBRowSet implements Cloneable
      * @param id the record's primary key
      * @param conn a valid JDBC connection
      */
-    public DBIndex checkUniqueConstraints(DBRecord rec)
+    public DBIndex checkUniqueConstraints(DBRecordBase rec)
     {
         for (DBIndex idx : getIndexes())
         {
@@ -720,7 +720,7 @@ public class DBTable extends DBRowSet implements Cloneable
      * @param conn (optional) to allow the dbms handle autogenerated fields
      */
     @Override
-    protected void initRecordDefaultValues(DBRecord record, FieldInitMode fieldInitMode)
+    protected void initRecordDefaultValues(DBRecordBase record, FieldInitMode fieldInitMode)
     {
         // check field init mode
         if (fieldInitMode==FieldInitMode.NONE)
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBUtils.java b/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
index 6220893..cd61d7a 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBUtils.java
@@ -816,9 +816,9 @@ public class DBUtils implements DBContextAware
      * @param recordClass the recordClass for which to create the list head 
      * @return
      */
-    protected <T extends DBRecord> DBRecordListFactory<T> createDefaultRecordListFactory(Class<T> recordClass, DBRowSet rowset) 
+    protected <R extends DBRecordBase> DBRecordListFactory<R> createDefaultRecordListFactory(Class<R> recordClass, DBRowSet rowset) 
     {
-        return new DBRecordListFactoryImpl<T>(recordClass, context.getClass(), rowset);
+        return new DBRecordListFactoryImpl<R>(recordClass, context.getClass(), rowset);
     }
     
     /**
@@ -829,9 +829,9 @@ public class DBUtils implements DBContextAware
      * @param pageSize the maximum number of items to add to the list or -1 (default) for all
      * @return the list 
      */
-    public <T extends DBRecord> List<T> queryRecordList(DBCommand cmd, DBRecordListFactory<T> factory, int first, int pageSize)
+    public <R extends DBRecordBase> List<R> queryRecordList(DBCommand cmd, DBRecordListFactory<R> factory, int first, int pageSize)
     {
-        List<T> list = null;
+        List<R> list = null;
         DBReader r = new DBReader(context);
         try
         {   // prepare
@@ -866,7 +866,7 @@ public class DBUtils implements DBContextAware
             int rownum = 0;
             while (r.moveNext() && maxCount != 0)
             {   // Create bean an init
-                T entry = factory.newRecord(rownum, r);
+                R entry = factory.newRecord(rownum, r);
                 if (entry==null)
                     continue;
                 // check
@@ -902,10 +902,10 @@ public class DBUtils implements DBContextAware
      * @param rowset the rowset for which to query the records
      * @return the list of DBRecord items
      */
-    public final <T extends DBRecord> List<T> queryRecordList(DBCommand cmd, DBRowSet rowset, Class<T> recordType)
+    public final <R extends DBRecordBase> List<R> queryRecordList(DBCommand cmd, DBRowSet rowset, Class<R> recordType)
     {
         @SuppressWarnings("cast")
-        DBRecordListFactory<T> factory = (DBRecordListFactory<T>)createDefaultRecordListFactory(recordType, rowset);
+        DBRecordListFactory<R> factory = (DBRecordListFactory<R>)createDefaultRecordListFactory(recordType, rowset);
         return queryRecordList(cmd, factory, 0, -1);
     }
 
diff --git a/empire-db/src/main/java/org/apache/empire/db/DBView.java b/empire-db/src/main/java/org/apache/empire/db/DBView.java
index 4e94986..9d5acd3 100644
--- a/empire-db/src/main/java/org/apache/empire/db/DBView.java
+++ b/empire-db/src/main/java/org/apache/empire/db/DBView.java
@@ -405,7 +405,7 @@ public abstract class DBView extends DBRowSet
     }
 
     @Override
-    public void updateRecord(DBRecord rec)
+    public void updateRecord(DBRecordBase rec)
     {
         if (updateable==false)
             throw new NotSupportedException(this, "updateRecord");
@@ -419,7 +419,7 @@ public abstract class DBView extends DBRowSet
      * @see org.apache.empire.db.DBRowSet#addRecord(org.apache.empire.db.DBRecord, java.sql.Connection)
      */
     @Override
-    public void createRecord(DBRecord record, Object[] initalKey, boolean deferredInit)
+    public void createRecord(DBRecordBase record, Object[] initalKey, boolean deferredInit)
     {
         throw new NotSupportedException(this, "createRecord");
     }
diff --git a/empire-db/src/main/java/org/apache/empire/db/exceptions/RecordReadOnlyException.java b/empire-db/src/main/java/org/apache/empire/db/exceptions/RecordReadOnlyException.java
index 49046a6..6c27652 100644
--- a/empire-db/src/main/java/org/apache/empire/db/exceptions/RecordReadOnlyException.java
+++ b/empire-db/src/main/java/org/apache/empire/db/exceptions/RecordReadOnlyException.java
@@ -19,7 +19,7 @@
 package org.apache.empire.db.exceptions;
 
 import org.apache.empire.commons.ErrorType;
-import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordBase;
 
 public class RecordReadOnlyException extends RecordException
 {
@@ -27,7 +27,7 @@ public class RecordReadOnlyException extends RecordException
     
     public static final ErrorType errorType = new ErrorType("error.db.recordIsReadOnly",    "The record {0} of {1} is read only.");
     
-    public RecordReadOnlyException(DBRecord record)
+    public RecordReadOnlyException(DBRecordBase record)
     {
         super(record, errorType, new String[] { keyToString(getKey(record)), entityName(getEntity(record)) });
     }
diff --git a/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactory.java b/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactory.java
index a74838a..a92d6a4 100644
--- a/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactory.java
+++ b/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactory.java
@@ -22,10 +22,10 @@ import java.util.List;
 
 import org.apache.empire.db.DBCommand;
 import org.apache.empire.db.DBContext;
-import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordBase;
 import org.apache.empire.db.DBRecordData;
 
-public interface DBRecordListFactory<T extends DBRecord>
+public interface DBRecordListFactory<T extends DBRecordBase>
 {
     void prepareQuery(DBCommand cmd, DBContext context);
     
diff --git a/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactoryImpl.java b/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactoryImpl.java
index fae7866..3617ced 100644
--- a/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactoryImpl.java
+++ b/empire-db/src/main/java/org/apache/empire/db/list/DBRecordListFactoryImpl.java
@@ -26,7 +26,7 @@ import java.util.List;
 import org.apache.empire.commons.ClassUtils;
 import org.apache.empire.db.DBCommand;
 import org.apache.empire.db.DBContext;
-import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordBase;
 import org.apache.empire.db.DBRecordData;
 import org.apache.empire.db.DBRowSet;
 import org.apache.empire.exceptions.InternalException;
@@ -40,7 +40,7 @@ import org.slf4j.LoggerFactory;
  * Implements the DBRecordListFactory interface
  * @author rainer
  */
-public class DBRecordListFactoryImpl<T extends DBRecord> implements DBRecordListFactory<T>
+public class DBRecordListFactoryImpl<T extends DBRecordBase> implements DBRecordListFactory<T>
 {
     // Logger
     protected static final Logger log = LoggerFactory.getLogger(DBRecordListFactoryImpl.class);
@@ -53,7 +53,7 @@ public class DBRecordListFactoryImpl<T extends DBRecord> implements DBRecordList
      * @return the constructor
      */
     @SuppressWarnings("unchecked")
-    protected static <T extends DBRecord> Constructor<T> findRecordConstructor(Class<T> recordClass, Class<? extends DBContext> contextClass, Class<? extends DBRowSet> rowsetClass)
+    protected static <T extends DBRecordBase> Constructor<T> findRecordConstructor(Class<T> recordClass, Class<? extends DBContext> contextClass, Class<? extends DBRowSet> rowsetClass)
     {
         // try (context+rowset or just context)
         Constructor<?> constructor = ClassUtils.findMatchingAccessibleConstructor(recordClass, 1, contextClass, rowsetClass);