diff --git a/include/class.orm.php b/include/class.orm.php
index ef04e3d3e9bb7bb2412c074e9c73e2c57d3d9157..16bdad71130867cf7a31a4c61e2921f38a59e2bd 100644
--- a/include/class.orm.php
+++ b/include/class.orm.php
@@ -17,6 +17,7 @@
 **********************************************************************/
 
 class OrmException extends Exception {}
+class OrmConfigurationException extends Exception {}
 
 class VerySimpleModel {
     static $meta = array(
@@ -45,7 +46,8 @@ class VerySimpleModel {
             // TODO: Support instrumented lists and such
             $j = static::$meta['joins'][$field];
             $class = $j['fkey'][0];
-            $v = $this->ht[$field] = $class::lookup($this->ht[$j['local']]);
+            $v = $this->ht[$field] = $class::lookup(
+                array($j['fkey'][1] => $this->ht[$j['local']]));
             return $v;
         }
         throw new OrmException(sprintf('%s: %s: Field not defined',
@@ -56,11 +58,19 @@ class VerySimpleModel {
         return array_key_exists($field, $this->ht)
             || isset(static::$meta['joins'][$field]);
     }
+    function __unset($field) {
+        unset($this->ht[$field]);
+    }
 
     function set($field, $value) {
         // Update of foreign-key by assignment to model instance
         if (isset(static::$meta['joins'][$field])) {
             $j = static::$meta['joins'][$field];
+            if ($j['list'] && ($value instanceof InstrumentedList)) {
+                // Magic list property
+                $this->ht[$field] = $value;
+                return;
+            }
             // XXX: Ensure $value instanceof $j['fkey'][0]
             if ($value->__new__)
                 $value->save();
@@ -95,12 +105,12 @@ class VerySimpleModel {
         // Construct related lists
         if (isset(static::$meta['joins'])) {
             foreach (static::$meta['joins'] as $name => $j) {
-                if (isset($this->{$j['local']})
+                if (isset($this->ht[$j['local']])
                         && isset($j['list']) && $j['list']) {
                     $fkey = $j['fkey'];
-                    $this->{$name} = new InstrumentedList(
+                    $this->set($name, new InstrumentedList(
                         // Send Model, Foriegn-Field, Local-Id
-                        array($fkey[0], $fkey[1], $this->{$j['local']})
+                        array($fkey[0], $fkey[1], $this->get($j['local'])))
                     );
                 }
             }
@@ -111,7 +121,7 @@ class VerySimpleModel {
 
     static function _inspect() {
         if (!static::$meta['table'])
-            throw new OrmConfigurationError(
+            throw new OrmConfigurationException(
                 'Model does not define meta.table', get_called_class());
 
         // Break down foreign-key metadata
@@ -120,6 +130,9 @@ class VerySimpleModel {
                 list($model, $key) = explode('.', $j['reverse']);
                 $info = $model::$meta['joins'][$key];
                 $constraint = array();
+                if (!is_array($info['constraint']))
+                    throw new OrmConfigurationException(
+                        $j['reverse'].': Reverse does not specify any constraints');
                 foreach ($info['constraint'] as $foreign => $local) {
                     list(,$field) = explode('.', $local);
                     $constraint[$field] = "$model.$foreign";
@@ -235,7 +248,7 @@ class SqlFunction {
         $this->args = array_slice(func_get_args(), 1);
     }
 
-    function toSql() {
+    function toSql($compiler=false) {
         $args = (count($this->args)) ? implode(',', db_input($this->args)) : "";
         return sprintf('%s(%s)', $this->func, $args);
     }
@@ -322,11 +335,24 @@ class QuerySet implements IteratorAggregate, ArrayAccess {
     function delete() {
         $class = $this->compiler;
         $compiler = new $class();
-        $ex = $compiler->compileDelete($this);
+        $ex = $compiler->compileBulkDelete($this);
         $ex->execute();
         return $ex->affected_rows();
     }
 
+    function update(array $what) {
+        $class = $this->compiler;
+        $compiler = new $class;
+        $ex = $compiler->compileBulkUpdate($this, $what);
+        $ex->execute();
+        return $ex->affected_rows();
+    }
+
+    function __clone() {
+        unset($this->_iterator);
+        unset($this->query);
+    }
+
     // IteratorAggregate interface
     function getIterator() {
         $class = $this->iterator;
@@ -350,7 +376,7 @@ class QuerySet implements IteratorAggregate, ArrayAccess {
     }
 
     function __toString() {
-        return (string)$this->getQuery();
+        return (string) $this->getQuery();
     }
 
     function getQuery($options=array()) {
@@ -378,6 +404,7 @@ class ModelInstanceIterator implements Iterator, ArrayAccess {
     var $queryset;
 
     function __construct($queryset=false) {
+        $this->queryset = $queryset;
         if ($queryset) {
             $this->model = $queryset->model;
             $this->resource = $queryset->getQuery();
@@ -476,18 +503,45 @@ class InstrumentedList extends ModelInstanceIterator {
             $this->resource = null;
     }
 
-    function add($object) {
+    function add($object, $at=false) {
         if (!$object || !$object instanceof $this->model)
             throw new Exception('Attempting to add invalid object to list');
 
-        $object->{$this->key} = $this->id;
+        $object->set($this->key, $this->id);
         $object->save();
-        $this->list[] = $object;
+
+        if ($at !== false)
+            $this->cache[$at] = $object;
+        else
+            $this->cache[] = $object;
     }
     function remove($object) {
         $object->delete();
     }
 
+    function reset() {
+        $this->cache = array();
+    }
+
+    // QuerySet delegates
+    function count() {
+        return $this->queryset->count();
+    }
+    function exists() {
+        return $this->queryset->exists();
+    }
+    function expunge() {
+        return $this->queryset->delete();
+    }
+    function update(array $what) {
+        return $this->queryset->update($what);
+    }
+
+    // Fetch a new QuerySet
+    function objects() {
+        return clone $this->queryset;
+    }
+
     function offsetUnset($a) {
         $this->fillTo($a);
         $this->cache[$a]->delete();
@@ -495,7 +549,7 @@ class InstrumentedList extends ModelInstanceIterator {
     function offsetSet($a, $b) {
         $this->fillTo($a);
         $this->cache[$a]->delete();
-        $this->add($b);
+        $this->add($b, $a);
     }
 }
 
@@ -651,7 +705,7 @@ class SqlCompiler {
         return $alias;
     }
 
-    function compileWhere($where, $model) {
+    function compileConstraints($where, $model) {
         $constraints = array();
         foreach ($where as $constraint) {
             $filter = array();
@@ -760,12 +814,15 @@ class MySqlCompiler extends SqlCompiler {
             .' '.$alias.' ON ('.implode(' AND ', $constraints).')';
     }
 
-    function input($what) {
+    function input(&$what) {
         if ($what instanceof QuerySet) {
             $q = $what->getQuery(array('nosort'=>true));
             $this->params += $q->params;
             return (string)$q;
         }
+        elseif ($what instanceof SqlFunction) {
+            return $val->toSql($this);
+        }
         else {
             $this->params[] = $what;
             return '?';
@@ -776,17 +833,22 @@ class MySqlCompiler extends SqlCompiler {
         return "`$what`";
     }
 
-    function compileCount($queryset) {
+    /**
+     * getWhereClause
+     *
+     * This builds the WHERE ... part of a DML statement. This should be
+     * called before ::getJoins(), because it may add joins into the
+     * statement based on the relationships used in the where clause
+     */
+    protected function getWhereClause($queryset) {
         $model = $queryset->model;
-        $table = $model::$meta['table'];
         $where_pos = array();
         $where_neg = array();
-        $joins = array();
         foreach ($queryset->constraints as $where) {
-            $where_pos[] = $this->compileWhere($where, $model);
+            $where_pos[] = $this->compileConstraints($where, $model);
         }
         foreach ($queryset->exclusions as $where) {
-            $where_neg[] = $this->compileWhere($where, $model);
+            $where_neg[] = $this->compileConstraints($where, $model);
         }
 
         $where = '';
@@ -794,6 +856,13 @@ class MySqlCompiler extends SqlCompiler {
             $where = ' WHERE '.implode(' AND ', $where_pos)
                 .implode(' AND NOT ', $where_neg);
         }
+        return $where;
+    }
+
+    function compileCount($queryset) {
+        $model = $queryset->model;
+        $table = $model::$meta['table'];
+        $where = $this->getWhereClause($queryset);
         $joins = $this->getJoins();
         $sql = 'SELECT COUNT(*) AS count FROM '.$this->quote($table).$joins.$where;
         $exec = new MysqlExecutor($sql, $this->params);
@@ -803,21 +872,7 @@ class MySqlCompiler extends SqlCompiler {
 
     function compileSelect($queryset) {
         $model = $queryset->model;
-        $where_pos = array();
-        $where_neg = array();
-        $joins = array();
-        foreach ($queryset->constraints as $where) {
-            $where_pos[] = $this->compileWhere($where, $model);
-        }
-        foreach ($queryset->exclusions as $where) {
-            $where_neg[] = $this->compileWhere($where, $model);
-        }
-
-        $where = '';
-        if ($where_pos || $where_neg) {
-            $where = ' WHERE '.implode(' AND ', $where_pos)
-                .implode(' AND NOT ', $where_neg);
-        }
+        $where = $this->getWhereClause($queryset);
 
         $sort = '';
         if ($queryset->ordering && !isset($this->options['nosort'])) {
@@ -871,30 +926,29 @@ class MySqlCompiler extends SqlCompiler {
     function compileInsert() {
     }
 
-    function compileDelete($queryset) {
+    function compileBulkDelete($queryset) {
         $model = $queryset->model;
         $table = $model::$meta['table'];
-        $where_pos = array();
-        $where_neg = array();
-        $joins = array();
-        foreach ($queryset->constraints as $where) {
-            $where_pos[] = $this->compileWhere($where, $model);
-        }
-        foreach ($queryset->exclusions as $where) {
-            $where_neg[] = $this->compileWhere($where, $model);
-        }
-
-        $where = '';
-        if ($where_pos || $where_neg) {
-            $where = ' WHERE '.implode(' AND ', $where_pos)
-                .implode(' AND NOT ', $where_neg);
-        }
+        $where = $this->getWhereClause($queryset);
         $joins = $this->getJoins();
         $sql = 'DELETE '.$this->quote($table).'.* FROM '
             .$this->quote($table).$joins.$where;
         return new MysqlExecutor($sql, $this->params);
     }
 
+    function compileBulkUpdate($queryset, array $what) {
+        $model = $queryset->model;
+        $table = $model::$meta['table'];
+        $set = array();
+        foreach ($what as $field=>$value)
+            $set[] = sprintf('%s = %s', $this->quote($field), $this->input($value));
+        $set = implode(', ', $set);
+        $where = $this->getWhereClause($queryset);
+        $joins = $this->getJoins();
+        $sql = 'UPDATE '.$this->quote($table).' SET '.$set.$joins.$where;
+        return new MysqlExecutor($sql, $this->params);
+    }
+
     // Returns meta data about the table used to build queries
     function inspectTable($table) {
     }