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

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


The following commit(s) were added to refs/heads/version3 by this push:
     new f32080b  EMPIREDB-370 Split DBRecord with new class DBRecordBase, 
DBRecordBean as alternative implementation
f32080b is described below

commit f32080bf478bf7349f92a1d575efdcd332f445bc
Author: Rainer Döbele <[email protected]>
AuthorDate: Tue Feb 8 13:15:33 2022 +0100

    EMPIREDB-370 Split DBRecord with new class DBRecordBase, DBRecordBean as 
alternative implementation
---
 .../org/apache/empire/samples/db/SampleApp.java    |   16 +-
 .../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   | 1137 +-------------------
 .../empire/db/{DBRecord.java => DBRecordBase.java} |  520 ++-------
 .../java/org/apache/empire/db/DBRecordBean.java    |  299 +++++
 .../main/java/org/apache/empire/db/DBRowSet.java   |   51 +-
 .../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    |   26 +-
 18 files changed, 523 insertions(+), 1614 deletions(-)

diff --git 
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
 
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
index 778a0fc..52bc2ae 100644
--- 
a/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
+++ 
b/empire-db-examples/empire-db-example-basic/src/main/java/org/apache/empire/samples/db/SampleApp.java
@@ -33,6 +33,7 @@ import org.apache.empire.db.DBContext;
 import org.apache.empire.db.DBQuery;
 import org.apache.empire.db.DBReader;
 import org.apache.empire.db.DBRecord;
+import org.apache.empire.db.DBRecordBean;
 import org.apache.empire.db.DBRowSet.PartialMode;
 import org.apache.empire.db.DBSQLScript;
 import org.apache.empire.db.context.DBContextStatic;
@@ -413,12 +414,21 @@ public class SampleApp
         */
        private static void updateEmployee(long idEmp, String phoneNumber)
     {
+           /*
                // Update an Employee
                DBRecord rec = new DBRecord(context, db.EMPLOYEES);
                rec.read(idEmp);
                // Set
                rec.setValue(db.EMPLOYEES.PHONE_NUMBER, phoneNumber);
                rec.update();
+               */
+           
+        DBRecordBean rec = new DBRecordBean();
+        rec.read(context, db.EMPLOYEES, idEmp);
+        // Set
+        rec.setValue(db.EMPLOYEES.PHONE_NUMBER, phoneNumber);
+        rec.update(context);
+           
        }
 
     /**
@@ -831,9 +841,9 @@ public class SampleApp
         cmd.join(EMP.DEPARTMENT_ID, DEP.ID);
         cmd.where(DEP.NAME.is("Development"));
         // query now
-        List<DBRecord> list = context.getUtils().queryRecordList(cmd, EMP);
+        List<DBRecordBean> list = context.getUtils().queryRecordList(cmd, EMP, 
DBRecordBean.class);
         log.info("RecordList query found {} employees in Development 
department", list.size());
-        for (DBRecord record : list)
+        for (DBRecordBean record : list)
         {
             Object[] key = record.getKey();
             // print info
@@ -850,7 +860,7 @@ public class SampleApp
                 log.info("Salary was modified for {}. New salary is {}", 
empName, record.getDecimal(EMP.SALARY));
             }
             // udpate the record
-            record.update();
+            record.update(context);
             
             // convert to bean
             Employee employee = new Employee();
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 20696de..7f2ba0a 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,235 +188,27 @@ 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
-     */
-    @Override
-    public int getFieldIndex(String column)
-    {
-        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;
-    }
-
-    /**
-     * 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
-     */
-    public boolean wasModified(int index)
-    {
-        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];
-    }
-    
-    /**
-     * 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
+     * Returns whether or not RollbackHandling is enabled for this record
      */
     @Override
-    public Column[] getKeyColumns()
+    public boolean isRollbackHandlingEnabled() 
     {
-        return getRowSet().getKeyColumns();
+        return this.enableRollbackHandling;
     }
 
     /**
-     * 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
+     * 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 
      */
-    @Override
-    public Object[] getKey()
+    public void setRollbackHandlingEnabled(boolean enabled) 
     {
-        // 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;
+        // 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 or disable
+        this.enableRollbackHandling = enabled;
     }
     
     /**
@@ -656,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)
@@ -997,7 +302,7 @@ public class DBRecord extends DBRecordData implements 
Record, Cloneable, Seriali
         // check updatable
         checkUpdateable();
         // allow rollback
-        if (enableRollbackHandling)
+        if (isRollbackHandlingEnabled())
             getContext().appendRollbackHandler(createRollbackHandler());
         // update
         getRowSet().updateRecord(this);
@@ -1020,420 +325,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 74%
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 20696de..17828ea 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 abstract 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,29 +527,9 @@ public class DBRecord extends DBRecordData implements 
Record, Cloneable, Seriali
         }
         return key;
     }
-    
-    /**
-     * 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
-     */
-    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
@@ -787,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)
@@ -827,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
@@ -925,110 +755,58 @@ 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
-     */
-    public void read(DBCompareExpr whereConstraints)
-    {
-        getRowSet().readRecord(this, whereConstraints);
-    }
     
     /**
-     * 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 supplied java bean.
+     * 
+     * @return true if at least one value has been set successfully 
      */
-    public void read(Object[] key, PartialMode mode, DBColumn... columns)
+    @Override
+    public int setRecordValues(Object bean, Collection<Column> ignoreList)
     {
-        getRowSet().readRecord(this, key, mode, columns);
+        // 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;
     }
 
     /**
-     * Updates the record and saves all changes in the database.
+     * Sets record values from the suppied java bean.
+     * @return true if at least one value has been set sucessfully
      */
-    public void update()
+    @Override
+    public final int setRecordValues(Object bean)
     {
-        if (!isValid())
-            throw new ObjectNotValidException(this);
-        if (!isModified())
-            return; /* Not modified. Nothing to do! */
-        // check updatable
-        checkUpdateable();
-        // allow rollback
-        if (enableRollbackHandling)
-            getContext().appendRollbackHandler(createRollbackHandler());
-        // update
-        getRowSet().updateRecord(this);
+        return setRecordValues(bean, null);
     }
 
     /**
-     * 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);
     }
 
     /**
@@ -1133,59 +911,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
@@ -1196,15 +921,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
      */
@@ -1316,49 +1032,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.
@@ -1416,24 +1110,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/DBRecordBean.java 
b/empire-db/src/main/java/org/apache/empire/db/DBRecordBean.java
new file mode 100644
index 0000000..89a4c6e
--- /dev/null
+++ b/empire-db/src/main/java/org/apache/empire/db/DBRecordBean.java
@@ -0,0 +1,299 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.empire.db;
+
+import java.sql.Connection;
+
+import org.apache.empire.commons.StringUtils;
+import org.apache.empire.data.Column;
+import org.apache.empire.db.DBRowSet.PartialMode;
+import org.apache.empire.db.exceptions.NoPrimaryKeyException;
+import org.apache.empire.db.expr.compare.DBCompareExpr;
+import org.apache.empire.exceptions.InvalidArgumentException;
+import org.apache.empire.exceptions.NotSupportedException;
+import org.apache.empire.exceptions.ObjectNotValidException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This class represents a record from a database table, view or query
+ * 
+ * Other than DBRecord it is not permanently attached to a context or rowset
+ * 
+ * Thus it has a Default constructor and is essentially a dynamic bean
+ * 
+ */
+public class DBRecordBean extends DBRecordBase
+{
+    private static final long serialVersionUID = 1L;
+    
+    private static final Logger log  = 
LoggerFactory.getLogger(DBRecordBean.class);
+    
+    /**
+     * 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 transient DBContext tempContext;
+    protected transient DBRowSet  rowset;   /* will be injected by DBRowset */
+
+    // options
+    protected boolean enableRollbackHandling;
+
+    /**
+     * Constructs a new DBRecordBean.<BR>
+     * @param enableRollbackHandling flag whether to enable rollback handing
+     */
+    public DBRecordBean(boolean enableRollbackHandling)
+    {
+        this.enableRollbackHandling = enableRollbackHandling;
+    }
+
+    /**
+     * Constructs a new DBRecordBean.<BR>
+     * @param context the DBContext for this record
+     * @param rowset the corresponding RowSet(Table, View, Query, etc.)
+     */
+    public DBRecordBean()
+    {
+        this(false);
+    }
+
+    /**
+     * Returns the current Context
+     * @return
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T extends DBContext> T  getContext()
+    {
+        if (this.tempContext==null)
+            throw new ObjectNotValidException(this);
+        return ((T)tempContext);
+    }
+
+    /**
+     * Returns the DBRowSet object.
+     * 
+     * @return the DBRowSet object
+     */
+    @Override
+    @SuppressWarnings("unchecked")
+    public <T extends DBRowSet> T getRowSet()
+    {
+        if (this.rowset==null)
+            throw new ObjectNotValidException(this);
+        return (T)this.rowset;
+    }
+
+    /**
+     * Returns whether or not RollbackHandling is enabled for this record
+     */
+    @Override
+    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) 
+    {
+        // enable or disable
+        this.enableRollbackHandling = enabled;
+    }
+    
+    /**
+     * 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
+     */
+    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]);
+    }
+    
+    @Override
+    public void close()
+    {
+        super.close();
+        // clear
+        this.rowset = null;
+    }
+
+    /**
+     * Creates a new record
+     */
+    public void create(DBContext context, DBRowSet rowset, Object[] initalKey)
+    {
+        try {
+            this.tempContext = context;
+            rowset.createRecord(this, initalKey, true);
+        } finally {
+            this.tempContext = null;
+        }
+    }
+
+    /**
+     * Creates a new record
+     */
+    public void create(DBContext context, DBRowSet rowset)
+    {
+        try {
+            this.tempContext = context;
+            rowset.createRecord(this, null, false);
+        } finally {
+            this.tempContext = null;
+        }
+    }
+    
+    /**
+     * 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(DBContext context, DBRowSet rowset, Object[] key)
+    {   // read
+        try {
+            this.tempContext = context;
+            rowset.readRecord(this, key);
+        } finally {
+            this.tempContext = null;
+        }
+    }
+
+    /**
+     * Reads a record from the database
+     * @param id the record id value
+     */
+    public final void read(DBContext context, DBRowSet rowset, long id)
+    {
+        read(context, rowset, new Object[] {id});
+    }
+    
+    /**
+     * Reads a record from the database
+     * @param key an array of the primary key values
+     */
+    public void read(DBContext context, DBRowSet rowset, DBCompareExpr 
whereConstraints)
+    {   // read
+        try {
+            this.tempContext = context;
+            rowset.readRecord(this, whereConstraints);
+        } finally {
+            this.tempContext = null;
+        }
+    }
+    
+    /**
+     * 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)
+     */
+    public void read(DBContext context, DBRowSet rowset, Object[] key, 
PartialMode mode, DBColumn... columns)
+    {   // read
+        try {
+            this.tempContext = context;
+            rowset.readRecord(this, key, mode, columns);
+        } finally {
+            this.tempContext = null;
+        }
+    }
+    
+    /**
+     * Updates the record in the database
+     * @param context the current context
+     */
+    public void update(DBContext context)
+    {   // update
+        if (isValid()==false)
+            throw new ObjectNotValidException(this);
+        if (!isModified())
+            return; /* Not modified. Nothing to do! */
+        try {
+            this.tempContext = context;
+            // check updatable
+            checkUpdateable();
+            // allow rollback
+            if (isRollbackHandlingEnabled())
+                context.appendRollbackHandler(createRollbackHandler());
+            // update
+            getRowSet().updateRecord(this);
+        } finally {
+            this.tempContext = null;
+        }
+    }
+
+    /**
+     * 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 context the current context
+     */
+    public void delete(DBContext context)
+    {
+        if (isValid()==false)
+            throw new ObjectNotValidException(this);
+        // check updatable
+        checkUpdateable();
+        // allow rollback
+        if (isRollbackHandlingEnabled())
+            context.appendRollbackHandler(createRollbackHandler());
+        // Delete only if record is not new
+        if (!isNew())
+        {
+            Object[] key = getKey();
+            log.info("Deleting record {}", StringUtils.arrayToString(key, 
"|"));
+            getRowSet().deleteRecord(key, context);
+        }
+        close();
+    }
+    
+}
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..3d7af28 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,10 +154,17 @@ 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(DBRecordBase record, boolean checkValid)
     {
+        // special
+        if ((record instanceof DBRecordBean) && !checkValid)
+        {   // set rowset of DBRecordBean
+            ((DBRecordBean)record).rowset = this;
+        }
+        // check param
         if (record==null || record.getRowSet()!=this)
-            throw new InvalidArgumentException(name, record);
+            throw new InvalidArgumentException("record", record);
+        // check valid
         if (checkValid && !record.isValid())
             throw new ObjectNotValidException(record);
     }
@@ -289,7 +296,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,10 +580,10 @@ 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);
+        checkParamRecord(record, false);
         // Prepare
         prepareInitRecord(record, newRecord);
         // Initialize all Fields
@@ -621,10 +628,10 @@ 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);
+        checkParamRecord(record, false);
         // Initialize the record
         prepareInitRecord(record, false);
         // Get Record Field Values
@@ -662,7 +669,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 +697,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 +713,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,10 +752,10 @@ 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 <R extends DBRecordBase> void readRecord(R record, DBCommand cmd)
     {
         // check param
-        checkParamRecord("record", record, false);
+        checkParamRecord(record, false);
         // read now
         DBReader reader = null;
         try
@@ -788,7 +795,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 <R extends DBRecordBase> void readRecord(R record, Object[] key)
     {
         // Check Arguments
         checkParamNull("key", key);
@@ -805,7 +812,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 +836,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,13 +914,13 @@ 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 <R extends DBRecordBase> void updateRecord(R record)
     {
         // check updateable
         if (isUpdateable()==false)
             throw new NotSupportedException(this, "updateRecord");
         // Check Arguments
-        checkParamRecord("record", record, true);
+        checkParamRecord(record, true);
         // the connection
         DBContext context = record.getContext();
         Connection conn = context.getConnection();
@@ -929,8 +936,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 +982,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 +1170,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 +1180,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..e520053 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
@@ -27,6 +27,8 @@ 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.DBRecordBean;
 import org.apache.empire.db.DBRecordData;
 import org.apache.empire.db.DBRowSet;
 import org.apache.empire.exceptions.InternalException;
@@ -40,7 +42,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,13 +55,20 @@ 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);
-        if (constructor==null)
-        {   // nothing suitable
-            throw new UnsupportedTypeException(recordClass);
+        Constructor<?> constructor;
+        if (DBRecordBean.class.isAssignableFrom(recordClass))
+        {   // find standard constructor 
+            constructor = 
ClassUtils.findMatchingAccessibleConstructor(recordClass, 0);
+        }
+        else
+        {   // try (context+rowset or just context)
+            constructor = 
ClassUtils.findMatchingAccessibleConstructor(recordClass, 1, contextClass, 
rowsetClass);
+            if (constructor==null)
+            {   // nothing suitable
+                throw new UnsupportedTypeException(recordClass);
+            }
         }
         // found
         return (Constructor<T>)constructor;
@@ -122,11 +131,12 @@ public class DBRecordListFactoryImpl<T extends DBRecord> 
implements DBRecordList
             {
                 case 2: record = constructor.newInstance(recData.getContext(), 
rowset);break;
                 case 1: record = 
constructor.newInstance(recData.getContext());break;
+                case 0: record = constructor.newInstance();break; 
                 default:
                     throw new 
UnsupportedTypeException(constructor.getClass()); 
             }
             // check
-            if (rowset.isSame(record.getRowSet())==false)
+            if ((record instanceof DBRecord) && 
!rowset.isSame(record.getRowSet()))
             {   // log warning
                 log.warn("DBRecordListFactoryImpl rowset ({}) and actual 
record rowset ({}) don't match!", rowset.getName(), 
record.getRowSet().getName());
                 throw new InvalidPropertyException("rowset", 
record.getRowSet());

Reply via email to