diff --git a/bootstrap.php b/bootstrap.php
index 3d7b6a4e9a5ad9c70b3512c63d67fc218e69969c..e70c79a6bb9801b06c49e4aaa5349a93e84b6de6 100644
--- a/bootstrap.php
+++ b/bootstrap.php
@@ -69,11 +69,15 @@ class Bootstrap {
         define('FILE_CHUNK_TABLE',$prefix.'file_chunk');
 
         define('ATTACHMENT_TABLE',$prefix.'attachment');
+
         define('USER_TABLE',$prefix.'user');
+        define('USER_CDATA_TABLE', $prefix.'user__cdata');
         define('USER_EMAIL_TABLE',$prefix.'user_email');
         define('USER_ACCOUNT_TABLE',$prefix.'user_account');
 
         define('ORGANIZATION_TABLE', $prefix.'organization');
+        define('ORGANIZATION_CDATA_TABLE', $prefix.'organization__cdata');
+
         define('NOTE_TABLE', $prefix.'note');
 
         define('STAFF_TABLE',$prefix.'staff');
diff --git a/include/class.dynamic_forms.php b/include/class.dynamic_forms.php
index 2b258688612e668c1c968da89d2a64fddaf49312..2b112078d8f92d037cbdef4107395b9ff5f05cb8 100644
--- a/include/class.dynamic_forms.php
+++ b/include/class.dynamic_forms.php
@@ -198,7 +198,7 @@ class DynamicForm extends VerySimpleModel {
         return $this->save();
     }
 
-    function getExportableFields($exclude=array()) {
+    function getExportableFields($exclude=array(), $prefix='__') {
         $fields = array();
         foreach ($this->getFields() as $f) {
             // Ignore core fields
@@ -209,7 +209,8 @@ class DynamicForm extends VerySimpleModel {
             elseif (!$f->hasData() || $f->isPresentationOnly())
                 continue;
 
-            $fields['__field_'.$f->get('id')] = $f;
+            $name = $f->get('name') ?: ('field_'.$f->get('id'));
+            $fields[$prefix.$name] = $f;
         }
         return $fields;
     }
@@ -342,6 +343,10 @@ class DynamicForm extends VerySimpleModel {
             return TicketForm::updateDynamicDataView($answer, $data);
         case 'A':
             return TaskForm::updateDynamicDataView($answer, $data);
+        case 'U':
+            return UserForm::updateDynamicDataView($answer, $data);
+        case 'O':
+            return OrganizationForm::updateDynamicDataView($answer, $data);
         }
 
     }
@@ -355,6 +360,10 @@ class DynamicForm extends VerySimpleModel {
             return TicketForm::dropDynamicDataView(TicketForm::$cdata['table']);
         case 'A':
             return TaskForm::dropDynamicDataView(TaskForm::$cdata['table']);
+        case 'U':
+            return UserForm::dropDynamicDataView(UserForm::$cdata['table']);
+        case 'O':
+            return OrganizationForm::dropDynamicDataView(OrganizationForm::$cdata['table']);
         }
 
     }
@@ -407,6 +416,12 @@ class UserForm extends DynamicForm {
     static $instance;
     static $form;
 
+    static $cdata = array(
+            'table' => USER_CDATA_TABLE,
+            'object_id' => 'user_id',
+            'object_type' => ObjectModel::OBJECT_TYPE_USER,
+        );
+
     static function objects() {
         $os = parent::objects();
         return $os->filter(array('type'=>'U'));
diff --git a/include/class.export.php b/include/class.export.php
index 72b66967adde73f9d2e912017292d0b85dd6d151..ee2c6a8ec8e2b3029c08602136aa3ee452442dcc 100644
--- a/include/class.export.php
+++ b/include/class.export.php
@@ -178,32 +178,21 @@ class Export {
 
         $exclude = array('name', 'email');
         $form = UserForm::getUserForm();
-        $fields = $form->getExportableFields($exclude);
-
-        // Field selection callback
-        $fname = function ($f) {
-            return 'cdata.`'.$f->getSelectName().'` AS __field_'.$f->get('id');
-        };
-
-        $sql = substr_replace($sql,
-                ','.implode(',', array_map($fname, $fields)).' ',
-                strpos($sql, 'FROM '), 0);
-
-        $sql = substr_replace($sql,
-                'LEFT JOIN ('.$form->getCrossTabQuery($form->type, 'user_id', $exclude).') cdata
-                    ON (cdata.user_id = user.id) ',
-                strpos($sql, 'WHERE '), 0);
+        $fields = $form->getExportableFields($exclude, 'cdata.');
 
         $cdata = array_combine(array_keys($fields),
                 array_values(array_map(
-                        function ($f) { return $f->get('label'); }, $fields)));
+                        function ($f) { return $f->getLocal('label'); }, $fields)));
+
+        $users = $sql->models()
+            ->select_related('org', 'cdata');
 
         ob_start();
-        echo self::dumpQuery($sql,
+        echo self::dumpQuery($users,
                 array(
                     'name'  =>          __('Name'),
-                    'organization' =>   __('Organization'),
-                    'email' =>          __('Email'),
+                    'org' =>   __('Organization'),
+                    '::getEmail' =>          __('Email'),
                     ) + $cdata,
                 $how,
                 array('modify' => function(&$record, $keys) use ($fields) {
@@ -228,30 +217,19 @@ class Export {
 
         $exclude = array('name');
         $form = OrganizationForm::getDefaultForm();
-        $fields = $form->getExportableFields($exclude);
-
-        // Field selection callback
-        $fname = function ($f) {
-            return 'cdata.`'.$f->getSelectName().'` AS __field_'.$f->get('id');
-        };
-
-        $sql = substr_replace($sql,
-                ','.implode(',', array_map($fname, $fields)).' ',
-                strpos($sql, 'FROM '), 0);
-
-        $sql = substr_replace($sql,
-                'LEFT JOIN ('.$form->getCrossTabQuery($form->type, '_org_id', $exclude).') cdata
-                    ON (cdata._org_id = org.id) ',
-                strpos($sql, 'WHERE '), 0);
-
+        $fields = $form->getExportableFields($exclude, 'cdata.');
         $cdata = array_combine(array_keys($fields),
                 array_values(array_map(
-                        function ($f) { return $f->get('label'); }, $fields)));
+                        function ($f) { return $f->getLocal('label'); }, $fields)));
 
-        $cdata += array('account_manager' => 'Account Manager', 'users' => 'Users');
+        $cdata += array(
+                '::getNumUsers' => 'Users',
+                '::getAccountManager' => 'Account Manager',
+                );
 
+        $orgs = $sql->models();
         ob_start();
-        echo self::dumpQuery($sql,
+        echo self::dumpQuery($orgs,
                 array(
                     'name'  =>  'Name',
                     ) + $cdata,
diff --git a/include/class.organization.php b/include/class.organization.php
index e870667b1f10e2132b9bdc51a2fa7c18e65f02aa..aa3690beea32fc41ef237d23e6e26ef1895d9dda 100644
--- a/include/class.organization.php
+++ b/include/class.organization.php
@@ -70,6 +70,10 @@ class OrganizationModel extends VerySimpleModel {
         return $this->name;
     }
 
+    function getNumUsers() {
+        return $this->users->count();
+    }
+
     function getAccountManager() {
         if (!isset($this->_manager)) {
             if ($this->manager[0] == 't')
@@ -145,19 +149,16 @@ RolePermission::register(/* @trans */ 'Organizations',
 
 class OrganizationCdata extends VerySimpleModel {
     static $meta = array(
-        'table' => 'org__cdata',
-        'view' => true,
+        'table' => ORGANIZATION_CDATA_TABLE,
         'pk' => array('org_id'),
+        'joins' => array(
+            'org' => array(
+                'constraint' => array('ord_id' => 'OrganizationModel.id'),
+            ),
+        ),
     );
-
-    function getQuery($compiler) {
-        $form = OrganizationForm::getDefaultForm();
-        $exclude = array('name');
-        return '('.$form->getCrossTabQuery($form->type, 'org_id', $exclude).')';
-    }
 }
 
-
 class Organization extends OrganizationModel
 implements TemplateVariable {
     var $_entries;
@@ -507,6 +508,12 @@ class OrganizationForm extends DynamicForm {
     static $instance;
     static $form;
 
+    static $cdata = array(
+            'table' => ORGANIZATION_CDATA_TABLE,
+            'object_id' => 'org_id',
+            'object_type' => ObjectModel::OBJECT_TYPE_ORG,
+        );
+
     static function objects() {
         $os = parent::objects();
         return $os->filter(array('type'=>'O'));
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 8e0871df0160a787dbe1c8d26550d25d9c199f5e..6d68aae893ee823da44fbedf9638f4d75cf0d394 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -219,6 +219,7 @@ RolePermission::register(/* @trans */ 'Tickets', TicketModel::getPermissions(),
 
 class TicketCData extends VerySimpleModel {
     static $meta = array(
+        'table' => TICKET_CDATA_TABLE,
         'pk' => array('ticket_id'),
         'joins' => array(
             'ticket' => array(
@@ -231,7 +232,6 @@ class TicketCData extends VerySimpleModel {
         ),
     );
 }
-TicketCData::$meta['table'] = TABLE_PREFIX . 'ticket__cdata';
 
 class Ticket extends TicketModel
 implements RestrictedAccess, Threadable {
diff --git a/include/class.user.php b/include/class.user.php
index cc64e736298c436b6398ece1700380728fb469d1..b4feed8283c3a9bdf50d21861c209ee88714926d 100644
--- a/include/class.user.php
+++ b/include/class.user.php
@@ -180,20 +180,14 @@ RolePermission::register(/* @trans */ 'Users', UserModel::getPermissions());
 
 class UserCdata extends VerySimpleModel {
     static $meta = array(
-        'table' => 'user__cdata',
-        'view' => true,
+        'table' => USER_CDATA_TABLE,
         'pk' => array('user_id'),
+        'joins' => array(
+            'user' => array(
+                'constraint' => array('user_id' => 'UserModel.id'),
+            ),
+        ),
     );
-
-    static function getQuery($compiler) {
-        $form = UserForm::getUserForm();
-        $exclude = array('name', 'email');
-        return '('.$form->getCrossTabQuery($form->type, 'user_id', $exclude).')';
-    }
-
-    static function getSqlAddParams($compiler) {
-        return static::getQuery($compiler);
-    }
 }
 
 class User extends UserModel
diff --git a/include/staff/orgs.inc.php b/include/staff/orgs.inc.php
index aba6ed30869ee4c56f2fe3b4399324c406135ae3..feb53acb399b5e934cd49bf9c1eedb5420f3e856 100644
--- a/include/staff/orgs.inc.php
+++ b/include/staff/orgs.inc.php
@@ -1,75 +1,61 @@
 <?php
 if(!defined('OSTSCPINC') || !$thisstaff) die('Access Denied');
 
-$qs = array();
-
-$select = 'SELECT org.*
-            ,COALESCE(team.name,
-                    IF(staff.staff_id, CONCAT_WS(" ", staff.firstname, staff.lastname), NULL)
-                    ) as account_manager ';
-$from = 'FROM '.ORGANIZATION_TABLE.' org '
-       .'LEFT JOIN '.STAFF_TABLE.' staff ON (
-           LEFT(org.manager, 1) = "s" AND staff.staff_id = SUBSTR(org.manager, 2)) '
-       .'LEFT JOIN '.TEAM_TABLE.' team ON (
-           LEFT(org.manager, 1) = "t" AND team.team_id = SUBSTR(org.manager, 2)) ';
+OrganizationForm::ensureDynamicDataView();
 
-$where = ' WHERE 1 ';
+$qs = array();
+$orgs = Organization::objects()
+    ->annotate(array('user_count'=>SqlAggregate::COUNT('users')));
 
 if ($_REQUEST['query']) {
-
-    $from .=' LEFT JOIN '.FORM_ENTRY_TABLE.' entry
-                ON (entry.object_type=\'O\' AND entry.object_id = org.id)
-              LEFT JOIN '.FORM_ANSWER_TABLE.' value
-                ON (value.entry_id=entry.id) ';
-
-    $search = db_input(strtolower($_REQUEST['query']), false);
-    $where .= ' AND (
-                    org.name LIKE \'%'.$search.'%\' OR value.value LIKE \'%'.$search.'%\'
-                )';
-
+    $search = $_REQUEST['query'];
+    $orgs->filter(Q::any(array(
+        'name__contains' => $search,
+        // TODO: Add search for cdata
+    )));
     $qs += array('query' => $_REQUEST['query']);
 }
 
-$sortOptions = array('name' => 'org.name',
-                     'users' => 'users',
-                     'create' => 'org.created',
-                     'update' => 'org.updated');
-$orderWays = array('DESC'=>'DESC','ASC'=>'ASC');
+$sortOptions = array(
+        'name' => 'name',
+        'users' => 'users',
+        'create' => 'created',
+        'update' => 'updated'
+        );
+
+$orderWays = array('DESC' => '-', 'ASC' => '');
 $sort= ($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])]) ? strtolower($_REQUEST['sort']) : 'name';
 //Sorting options...
 if ($sort && $sortOptions[$sort])
-    $order_column =$sortOptions[$sort];
+    $order_column = $sortOptions[$sort];
 
-$order_column = $order_column ?: 'org.name';
+$order_column = $order_column ?: 'name';
 
 if ($_REQUEST['order'] && $orderWays[strtoupper($_REQUEST['order'])])
     $order = $orderWays[strtoupper($_REQUEST['order'])];
 
-$order=$order ?: 'ASC';
 if ($order_column && strpos($order_column,','))
     $order_column = str_replace(','," $order,",$order_column);
 
 $x=$sort.'_sort';
-$$x=' class="'.strtolower($order).'" ';
+$$x=' class="'.($order == '' ? 'asc' : 'desc').'" ';
 $order_by="$order_column $order ";
 
-$total=db_count('SELECT count(DISTINCT org.id) '.$from.' '.$where);
-$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1;
-$pageNav=new Pagenate($total,$page,PAGE_LIMIT);
+$total = $orgs->count();
+$page=($_GET['p'] && is_numeric($_GET['p']))? $_GET['p'] : 1;
+$pageNav=new Pagenate($total, $page, PAGE_LIMIT);
+$pageNav->paginate($orgs);
+
 $qstr = '&amp;'. Http::build_query($qs);
 $qs += array('sort' => $_REQUEST['sort'], 'order' => $_REQUEST['order']);
 $pageNav->setURL('orgs.php', $qs);
-$qstr.='&amp;order='.($order=='DESC' ? 'ASC' : 'DESC');
-
-$select .= ', count(DISTINCT user.id) as users ';
-
-$from .= ' LEFT JOIN '.USER_TABLE.' user ON (user.org_id = org.id) ';
-
+$qstr.='&amp;order='.($order=='-' ? 'ASC' : 'DESC');
 
-$query="$select $from $where GROUP BY org.id ORDER BY $order_by LIMIT ".$pageNav->getStart().",".$pageNav->getLimit();
 //echo $query;
-$qhash = md5($query);
-$_SESSION['orgs_qs_'.$qhash] = $query;
+$_SESSION[':Q:orgs'] = $orgs;
+
+$orgs->values('id', 'name', 'created', 'updated');
+$orgs->order_by($order . $order_column);
 ?>
 <div id="basic_search">
     <div style="min-height:25px;">
@@ -120,11 +106,11 @@ $_SESSION['orgs_qs_'.$qhash] = $query;
 <div class="clear"></div>
 <?php
 $showing = $search ? __('Search Results').': ' : '';
-$res = db_query($query);
-if($res && ($num=db_num_rows($res)))
+if ($orgs->exists(true))
     $showing .= $pageNav->showing();
 else
     $showing .= __('No organizations found!');
+
 ?>
 <form id="orgs-list" action="orgs.php" method="POST" name="staff" >
  <?php csrf_token(); ?>
@@ -143,31 +129,31 @@ else
     </thead>
     <tbody>
     <?php
-        if($res && db_num_rows($res)):
-            $ids=($errors && is_array($_POST['ids']))?$_POST['ids']:null;
-            while ($row = db_fetch_array($res)) {
-
-                $sel=false;
-                if($ids && in_array($row['id'], $ids))
-                    $sel=true;
-                ?>
-               <tr id="<?php echo $row['id']; ?>">
-                <td nowrap align="center">
-                    <input type="checkbox" value="<?php echo $row['id']; ?>" class="ckb mass nowarn"/>
-                </td>
-                <td>&nbsp; <a href="orgs.php?id=<?php echo $row['id']; ?>"><?php echo $row['name']; ?></a> </td>
-                <td>&nbsp;<?php echo $row['users']; ?></td>
-                <td><?php echo Format::date($row['created']); ?></td>
-                <td><?php echo Format::datetime($row['updated']); ?>&nbsp;</td>
-               </tr>
-            <?php
-            } //end of while.
-        endif; ?>
+        $ids=($errors && is_array($_POST['ids']))?$_POST['ids']:null;
+        foreach ($orgs as $org) {
+
+            $sel=false;
+            if($ids && in_array($org['id'], $ids))
+                $sel=true;
+            ?>
+           <tr id="<?php echo $org['id']; ?>">
+            <td nowrap align="center">
+                <input type="checkbox" value="<?php echo $org['id']; ?>" class="ckb mass nowarn"/>
+            </td>
+            <td>&nbsp; <a href="orgs.php?id=<?php echo $org['id']; ?>"><?php
+            echo $org['name']; ?></a> </td>
+            <td>&nbsp;<?php echo $org['user_count']; ?></td>
+            <td><?php echo Format::date($org['created']); ?></td>
+            <td><?php echo Format::datetime($org['updated']); ?>&nbsp;</td>
+           </tr>
+        <?php
+        }
+        ?>
     </tbody>
     <tfoot>
      <tr>
         <td colspan="7">
-            <?php if ($res && $num) { ?>
+            <?php if ($total) { ?>
             <?php echo __('Select');?>:&nbsp;
             <a id="selectAll" href="#ckb"><?php echo __('All');?></a>&nbsp;&nbsp;
             <a id="selectNone" href="#ckb"><?php echo __('None');?></a>&nbsp;&nbsp;
@@ -182,12 +168,11 @@ else
     </tfoot>
 </table>
 <?php
-if($res && $num): //Show options..
+if ($total): //Show options..
     echo sprintf('<div>&nbsp;%s: %s &nbsp; <a class="no-pjax"
-            href="orgs.php?a=export&qh=%s">%s</a></div>',
+            href="orgs.php?a=export">%s</a></div>',
             __('Page'),
             $pageNav->getPageLinks(),
-            $qhash,
             __('Export'));
 endif;
 ?>
diff --git a/include/staff/users.inc.php b/include/staff/users.inc.php
index f948114d0fca412bae344b9410df3a235a92088c..afb54e57b51daeb501d6340d22e5052a3ff193f7 100644
--- a/include/staff/users.inc.php
+++ b/include/staff/users.inc.php
@@ -1,8 +1,10 @@
 <?php
 if(!defined('OSTSCPINC') || !$thisstaff) die('Access Denied');
 
-$qs = array();
+// Ensure cdata
+UserForm::ensureDynamicDataView();
 
+$qs = array();
 $users = User::objects()
     ->annotate(array('ticket_count'=>SqlAggregate::COUNT('tickets')));
 
@@ -50,7 +52,7 @@ $pageNav->setURL('users.php', $qs);
 $qstr.='&amp;order='.($order=='-' ? 'ASC' : 'DESC');
 
 //echo $query;
-$_SESSION[':Q:users'] = clone $users;
+$_SESSION[':Q:users'] = $users;
 
 $users->values('id', 'name', 'default_email__address', 'account__id',
     'account__status', 'created', 'updated');
@@ -205,7 +207,7 @@ else
     <tfoot>
      <tr>
         <td colspan="7">
-            <?php if ($res && $num) { ?>
+            <?php if ($total) { ?>
             <?php echo __('Select');?>:&nbsp;
             <a id="selectAll" href="#ckb"><?php echo __('All');?></a>&nbsp;&nbsp;
             <a id="selectNone" href="#ckb"><?php echo __('None');?></a>&nbsp;&nbsp;
diff --git a/scp/orgs.php b/scp/orgs.php
index ad9624b9492a1ece928c29e43cc8032a47c21deb..bfd2210abf39db4d913398669c7c0418fc7fb02e 100644
--- a/scp/orgs.php
+++ b/scp/orgs.php
@@ -98,9 +98,7 @@ if ($_POST) {
 } elseif (!$org && $_REQUEST['a'] == 'export') {
     require_once(INCLUDE_DIR.'class.export.php');
     $ts = strftime('%Y%m%d');
-    if (!($token=$_REQUEST['qh']))
-        $errors['err'] = __('Query token required');
-    elseif (!($query=$_SESSION['orgs_qs_'.$token]))
+    if (!($query=$_SESSION[':Q:orgs']))
         $errors['err'] = __('Query token not found');
     elseif (!Export::saveOrganizations($query, __('organizations')."-$ts.csv", 'csv'))
         $errors['err'] = __('Internal error: Unable to export results');
diff --git a/scp/users.php b/scp/users.php
index edc6b52fb7a1289670e6f782280f1fb6d91a0ba8..f665050384c88854bd93b6ae310ef91f11eb9cbb 100644
--- a/scp/users.php
+++ b/scp/users.php
@@ -162,9 +162,7 @@ if ($_POST) {
 } elseif(!$user && $_REQUEST['a'] == 'export') {
     require_once(INCLUDE_DIR.'class.export.php');
     $ts = strftime('%Y%m%d');
-    if (!($token=$_REQUEST['qh']))
-        $errors['err'] = __('Query token required');
-    elseif (!($query=$_SESSION['users_qs_'.$token]))
+    if (!($query=$_SESSION[':Q:users']))
         $errors['err'] = __('Query token not found');
     elseif (!Export::saveUsers($query, __("users")."-$ts.csv", 'csv'))
         $errors['err'] = __('Internal error: Unable to dump query results');