diff --git a/framework/yii/classes.php b/framework/yii/classes.php
index 1469910..78cce95 100644
--- a/framework/yii/classes.php
+++ b/framework/yii/classes.php
@@ -85,7 +85,7 @@ return array(
 	'yii\captcha\CaptchaValidator' => YII_PATH . '/captcha/CaptchaValidator.php',
 	'yii\data\ActiveDataProvider' => YII_PATH . '/data/ActiveDataProvider.php',
 	'yii\data\ArrayDataProvider' => YII_PATH . '/data/ArrayDataProvider.php',
-	'yii\data\DataProvider' => YII_PATH . '/data/DataProvider.php',
+	'yii\data\BaseDataProvider' => YII_PATH . '/data/BaseDataProvider.php',
 	'yii\data\DataProviderInterface' => YII_PATH . '/data/DataProviderInterface.php',
 	'yii\data\Pagination' => YII_PATH . '/data/Pagination.php',
 	'yii\data\Sort' => YII_PATH . '/data/Sort.php',
@@ -118,6 +118,7 @@ return array(
 	'yii\db\pgsql\Schema' => YII_PATH . '/db/pgsql/Schema.php',
 	'yii\db\sqlite\QueryBuilder' => YII_PATH . '/db/sqlite/QueryBuilder.php',
 	'yii\db\sqlite\Schema' => YII_PATH . '/db/sqlite/Schema.php',
+	'yii\grid\ActionColumn' => YII_PATH . '/grid/ActionColumn.php',
 	'yii\grid\CheckboxColumn' => YII_PATH . '/grid/CheckboxColumn.php',
 	'yii\grid\Column' => YII_PATH . '/grid/Column.php',
 	'yii\grid\DataColumn' => YII_PATH . '/grid/DataColumn.php',
@@ -126,26 +127,26 @@ return array(
 	'yii\grid\SerialColumn' => YII_PATH . '/grid/SerialColumn.php',
 	'yii\helpers\ArrayHelper' => YII_PATH . '/helpers/ArrayHelper.php',
 	'yii\helpers\BaseArrayHelper' => YII_PATH . '/helpers/BaseArrayHelper.php',
-	'yii\helpers\Console' => YII_PATH . '/helpers/Console.php',
 	'yii\helpers\BaseConsole' => YII_PATH . '/helpers/BaseConsole.php',
-	'yii\helpers\FileHelper' => YII_PATH . '/helpers/FileHelper.php',
 	'yii\helpers\BaseFileHelper' => YII_PATH . '/helpers/BaseFileHelper.php',
-	'yii\helpers\Html' => YII_PATH . '/helpers/Html.php',
 	'yii\helpers\BaseHtml' => YII_PATH . '/helpers/BaseHtml.php',
-	'yii\helpers\HtmlPurifier' => YII_PATH . '/helpers/HtmlPurifier.php',
 	'yii\helpers\BaseHtmlPurifier' => YII_PATH . '/helpers/BaseHtmlPurifier.php',
-	'yii\helpers\Inflector' => YII_PATH . '/helpers/Inflector.php',
 	'yii\helpers\BaseInflector' => YII_PATH . '/helpers/BaseInflector.php',
-	'yii\helpers\Json' => YII_PATH . '/helpers/Json.php',
 	'yii\helpers\BaseJson' => YII_PATH . '/helpers/BaseJson.php',
-	'yii\helpers\Markdown' => YII_PATH . '/helpers/Markdown.php',
 	'yii\helpers\BaseMarkdown' => YII_PATH . '/helpers/BaseMarkdown.php',
-	'yii\helpers\Security' => YII_PATH . '/helpers/Security.php',
 	'yii\helpers\BaseSecurity' => YII_PATH . '/helpers/BaseSecurity.php',
-	'yii\helpers\StringHelper' => YII_PATH . '/helpers/StringHelper.php',
 	'yii\helpers\BaseStringHelper' => YII_PATH . '/helpers/BaseStringHelper.php',
-	'yii\helpers\VarDumper' => YII_PATH . '/helpers/VarDumper.php',
 	'yii\helpers\BaseVarDumper' => YII_PATH . '/helpers/BaseVarDumper.php',
+	'yii\helpers\Console' => YII_PATH . '/helpers/Console.php',
+	'yii\helpers\FileHelper' => YII_PATH . '/helpers/FileHelper.php',
+	'yii\helpers\Html' => YII_PATH . '/helpers/Html.php',
+	'yii\helpers\HtmlPurifier' => YII_PATH . '/helpers/HtmlPurifier.php',
+	'yii\helpers\Inflector' => YII_PATH . '/helpers/Inflector.php',
+	'yii\helpers\Json' => YII_PATH . '/helpers/Json.php',
+	'yii\helpers\Markdown' => YII_PATH . '/helpers/Markdown.php',
+	'yii\helpers\Security' => YII_PATH . '/helpers/Security.php',
+	'yii\helpers\StringHelper' => YII_PATH . '/helpers/StringHelper.php',
+	'yii\helpers\VarDumper' => YII_PATH . '/helpers/VarDumper.php',
 	'yii\i18n\DbMessageSource' => YII_PATH . '/i18n/DbMessageSource.php',
 	'yii\i18n\Formatter' => YII_PATH . '/i18n/Formatter.php',
 	'yii\i18n\GettextFile' => YII_PATH . '/i18n/GettextFile.php',
@@ -194,6 +195,7 @@ return array(
 	'yii\web\Application' => YII_PATH . '/web/Application.php',
 	'yii\web\AssetBundle' => YII_PATH . '/web/AssetBundle.php',
 	'yii\web\AssetConverter' => YII_PATH . '/web/AssetConverter.php',
+	'yii\web\AssetConverterInterface' => YII_PATH . '/web/AssetConverterInterface.php',
 	'yii\web\AssetManager' => YII_PATH . '/web/AssetManager.php',
 	'yii\web\CacheSession' => YII_PATH . '/web/CacheSession.php',
 	'yii\web\Controller' => YII_PATH . '/web/Controller.php',
@@ -204,7 +206,6 @@ return array(
 	'yii\web\HeaderCollection' => YII_PATH . '/web/HeaderCollection.php',
 	'yii\web\HttpCache' => YII_PATH . '/web/HttpCache.php',
 	'yii\web\HttpException' => YII_PATH . '/web/HttpException.php',
-	'yii\web\AssetConverterInterface' => YII_PATH . '/web/AssetConverterInterface.php',
 	'yii\web\IdentityInterface' => YII_PATH . '/web/IdentityInterface.php',
 	'yii\web\JqueryAsset' => YII_PATH . '/web/JqueryAsset.php',
 	'yii\web\JsExpression' => YII_PATH . '/web/JsExpression.php',
@@ -226,6 +227,7 @@ return array(
 	'yii\widgets\ActiveField' => YII_PATH . '/widgets/ActiveField.php',
 	'yii\widgets\ActiveForm' => YII_PATH . '/widgets/ActiveForm.php',
 	'yii\widgets\ActiveFormAsset' => YII_PATH . '/widgets/ActiveFormAsset.php',
+	'yii\widgets\BaseListView' => YII_PATH . '/widgets/BaseListView.php',
 	'yii\widgets\Block' => YII_PATH . '/widgets/Block.php',
 	'yii\widgets\Breadcrumbs' => YII_PATH . '/widgets/Breadcrumbs.php',
 	'yii\widgets\ContentDecorator' => YII_PATH . '/widgets/ContentDecorator.php',
@@ -235,7 +237,6 @@ return array(
 	'yii\widgets\LinkPager' => YII_PATH . '/widgets/LinkPager.php',
 	'yii\widgets\LinkSorter' => YII_PATH . '/widgets/LinkSorter.php',
 	'yii\widgets\ListView' => YII_PATH . '/widgets/ListView.php',
-	'yii\widgets\BaseListView' => YII_PATH . '/widgets/BaseListView.php',
 	'yii\widgets\MaskedInput' => YII_PATH . '/widgets/MaskedInput.php',
 	'yii\widgets\MaskedInputAsset' => YII_PATH . '/widgets/MaskedInputAsset.php',
 	'yii\widgets\Menu' => YII_PATH . '/widgets/Menu.php',
diff --git a/framework/yii/data/ActiveDataProvider.php b/framework/yii/data/ActiveDataProvider.php
index 2fe0efb..c5f1bcd 100644
--- a/framework/yii/data/ActiveDataProvider.php
+++ b/framework/yii/data/ActiveDataProvider.php
@@ -48,16 +48,10 @@ use yii\db\Connection;
  * $posts = $provider->getModels();
  * ~~~
  *
- * @property integer $count The number of data models in the current page. This property is read-only.
- * @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is
- * uniquely identified by the corresponding key value in this array. This property is read-only.
- * @property array $models The list of data models in the current page. This property is read-only.
- * @property integer $totalCount Total number of possible data models.
- *
  * @author Qiang Xue <qiang.xue@gmail.com>
  * @since 2.0
  */
-class ActiveDataProvider extends DataProvider
+class ActiveDataProvider extends BaseDataProvider
 {
 	/**
 	 * @var Query the query that is used to fetch data models and [[totalCount]]
@@ -82,10 +76,6 @@ class ActiveDataProvider extends DataProvider
 	 */
 	public $db;
 
-	private $_models;
-	private $_keys;
-	private $_totalCount;
-
 	/**
 	 * Initializes the DbCache component.
 	 * This method will initialize the [[db]] property to make sure it refers to a valid DB connection.
@@ -103,122 +93,72 @@ class ActiveDataProvider extends DataProvider
 	}
 
 	/**
-	 * Returns the number of data models in the current page.
-	 * This is equivalent to `count($provider->models)`.
-	 * When [[pagination]] is false, this is the same as [[totalCount]].
-	 * @return integer the number of data models in the current page.
-	 */
-	public function getCount()
-	{
-		return count($this->getModels());
-	}
-
-	/**
-	 * Returns the total number of data models.
-	 * When [[pagination]] is false, this returns the same value as [[count]].
-	 * If [[totalCount]] is not explicitly set, it will be calculated
-	 * using [[query]] with a COUNT query.
-	 * @return integer total number of possible data models.
-	 * @throws InvalidConfigException
+	 * @inheritdoc
 	 */
-	public function getTotalCount()
+	protected function prepareModels()
 	{
-		if ($this->getPagination() === false) {
-			return $this->getCount();
-		} elseif ($this->_totalCount === null) {
-			if (!$this->query instanceof Query) {
-				throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
-			}
-			$query = clone $this->query;
-			$this->_totalCount = $query->limit(-1)->offset(-1)->count('*', $this->db);
+		if (!$this->query instanceof Query) {
+			throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
 		}
-		return $this->_totalCount;
-	}
-
-	/**
-	 * Sets the total number of data models.
-	 * @param integer $value the total number of data models.
-	 */
-	public function setTotalCount($value)
-	{
-		$this->_totalCount = $value;
-	}
-
-	/**
-	 * Returns the data models in the current page.
-	 * @return array the list of data models in the current page.
-	 * @throws InvalidConfigException if [[query]] is not set or invalid.
-	 */
-	public function getModels()
-	{
-		if ($this->_models === null) {
-			if (!$this->query instanceof Query) {
-				throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
-			}
-			if (($pagination = $this->getPagination()) !== false) {
-				$this->query->limit($pagination->getLimit())->offset($pagination->getOffset());
-			}
-			if (($sort = $this->getSort()) !== false) {
-				$this->query->addOrderBy($sort->getOrders());
-			}
-			$this->_models = $this->query->all($this->db);
+		if (($pagination = $this->getPagination()) !== false) {
+			$pagination->totalCount = $this->getTotalCount();
+			$this->query->limit($pagination->getLimit())->offset($pagination->getOffset());
+		}
+		if (($sort = $this->getSort()) !== false) {
+			$this->query->addOrderBy($sort->getOrders());
 		}
-		return $this->_models;
+		return $this->query->all($this->db);
 	}
 
 	/**
-	 * Returns the key values associated with the data models.
-	 * @return array the list of key values corresponding to [[models]]. Each data model in [[models]]
-	 * is uniquely identified by the corresponding key value in this array.
+	 * @inheritdoc
 	 */
-	public function getKeys()
+	protected function prepareKeys($models)
 	{
-		if ($this->_keys === null) {
-			$this->_keys = array();
-			$models = $this->getModels();
-			if ($this->key !== null) {
+		$keys = array();
+		if ($this->key !== null) {
+			foreach ($models as $model) {
+				if (is_string($this->key)) {
+					$keys[] = $model[$this->key];
+				} else {
+					$keys[] = call_user_func($this->key, $model);
+				}
+			}
+			return $keys;
+		} elseif ($this->query instanceof ActiveQuery) {
+			/** @var \yii\db\ActiveRecord $class */
+			$class = $this->query->modelClass;
+			$pks = $class::primaryKey();
+			if (count($pks) === 1) {
+				$pk = $pks[0];
 				foreach ($models as $model) {
-					if (is_string($this->key)) {
-						$this->_keys[] = $model[$this->key];
-					} else {
-						$this->_keys[] = call_user_func($this->key, $model);
-					}
+					$keys[] = $model[$pk];
 				}
-			} elseif ($this->query instanceof ActiveQuery) {
-				/** @var \yii\db\ActiveRecord $class */
-				$class = $this->query->modelClass;
-				$pks = $class::primaryKey();
-				if (count($pks) === 1) {
-					$pk = $pks[0];
-					foreach ($models as $model) {
-						$this->_keys[] = $model[$pk];
-					}
-				} else {
-					foreach ($models as $model) {
-						$keys = array();
-						foreach ($pks as $pk) {
-							$keys[] = $model[$pk];
-						}
-						$this->_keys[] = json_encode($keys);
+			} else {
+				foreach ($models as $model) {
+					$kk = array();
+					foreach ($pks as $pk) {
+						$kk[] = $model[$pk];
 					}
+					$keys[] = json_encode($kk);
 				}
-			} else {
-				$this->_keys = array_keys($models);
 			}
+			return $keys;
+		} else {
+			return array_keys($models);
 		}
-		return $this->_keys;
 	}
 
 	/**
-	 * Refreshes the data provider.
-	 * After calling this method, if [[getModels()]], [[getKeys()]] or [[getTotalCount()]] is called again,
-	 * they will re-execute the query and return the latest data available.
+	 * @inheritdoc
 	 */
-	public function refresh()
+	protected function prepareTotalCount()
 	{
-		$this->_models = null;
-		$this->_totalCount = null;
-		$this->_keys = null;
+		if (!$this->query instanceof Query) {
+			throw new InvalidConfigException('The "query" property must be an instance of Query or its subclass.');
+		}
+		$query = clone $this->query;
+		return $query->limit(-1)->offset(-1)->count('*', $this->db);
 	}
 
 	/**
@@ -227,9 +167,7 @@ class ActiveDataProvider extends DataProvider
 	public function setSort($value)
 	{
 		parent::setSort($value);
-		if (($sort = $this->getSort()) !== false && empty($sort->attributes) &&
-			$this->query instanceof ActiveQuery) {
-
+		if (($sort = $this->getSort()) !== false && empty($sort->attributes) && $this->query instanceof ActiveQuery) {
 			/** @var Model $model */
 			$model = new $this->query->modelClass;
 			foreach($model->attributes() as $attribute) {
diff --git a/framework/yii/data/ArrayDataProvider.php b/framework/yii/data/ArrayDataProvider.php
index 9534803..925c18e 100644
--- a/framework/yii/data/ArrayDataProvider.php
+++ b/framework/yii/data/ArrayDataProvider.php
@@ -47,15 +47,10 @@ use yii\helpers\ArrayHelper;
  * Note: if you want to use the sorting feature, you must configure the [[sort]] property
  * so that the provider knows which columns can be sorted.
  *
- * @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is
- * uniquely identified by the corresponding key value in this array.
- * @property array $models The list of data models in the current page.
- * @property integer $totalCount Total number of possible data models.
- *
  * @author Qiang Xue <qiang.xue@gmail.com>
  * @since 2.0
  */
-class ArrayDataProvider extends DataProvider
+class ArrayDataProvider extends BaseDataProvider
 {
 	/**
 	 * @var string|callable the column that is used as the key of the data models.
@@ -71,100 +66,53 @@ class ArrayDataProvider extends DataProvider
 	 */
 	public $allModels;
 
-	private $_totalCount;
 
 	/**
-	 * Returns the total number of data models.
-	 * @return integer total number of possible data models.
+	 * @inheritdoc
 	 */
-	public function getTotalCount()
+	protected function prepareModels()
 	{
-		if ($this->getPagination() === false) {
-			return $this->getCount();
-		} elseif ($this->_totalCount === null) {
-			$this->_totalCount = count($this->allModels);
+		if (($models = $this->allModels) === null) {
+			return array();
 		}
-		return $this->_totalCount;
-	}
-
-	/**
-	 * Sets the total number of data models.
-	 * @param integer $value the total number of data models.
-	 */
-	public function setTotalCount($value)
-	{
-		$this->_totalCount = $value;
-	}
-
-	private $_models;
 
-	/**
-	 * Returns the data models in the current page.
-	 * @return array the list of data models in the current page.
-	 */
-	public function getModels()
-	{
-		if ($this->_models === null) {
-			if (($models = $this->allModels) === null) {
-				return array();
-			}
-
-			if (($sort = $this->getSort()) !== false) {
-				$models = $this->sortModels($models, $sort);
-			}
-
-			if (($pagination = $this->getPagination()) !== false) {
-				$models = array_slice($models, $pagination->getOffset(), $pagination->getLimit());
-			}
+		if (($sort = $this->getSort()) !== false) {
+			$models = $this->sortModels($models, $sort);
+		}
 
-			$this->_models = $models;
+		if (($pagination = $this->getPagination()) !== false) {
+			$models = array_slice($models, $pagination->getOffset(), $pagination->getLimit());
 		}
-		return $this->_models;
-	}
 
-	/**
-	 * Sets the data models in the current page.
-	 * @param array $models the models in the current page
-	 */
-	public function setModels($models)
-	{
-		$this->_models = $models;
+		return $models;
 	}
 
-	private $_keys;
-
 	/**
-	 * Returns the key values associated with the data models.
-	 * @return array the list of key values corresponding to [[models]]. Each data model in [[models]]
-	 * is uniquely identified by the corresponding key value in this array.
+	 * @inheritdoc
 	 */
-	public function getKeys()
+	protected function prepareKeys($models)
 	{
-		if ($this->_keys === null) {
-			$this->_keys = array();
-			$models = $this->getModels();
-			if ($this->key !== null) {
-				foreach ($models as $model) {
-					if (is_string($this->key)) {
-						$this->_keys[] = $model[$this->key];
-					} else {
-						$this->_keys[] = call_user_func($this->key, $model);
-					}
+		if ($this->key !== null) {
+			$keys = array();
+			foreach ($models as $model) {
+				if (is_string($this->key)) {
+					$keys[] = $model[$this->key];
+				} else {
+					$keys[] = call_user_func($this->key, $model);
 				}
-			} else {
-				$this->_keys = array_keys($models);
 			}
+			return $keys;
+		} else {
+			return array_keys($models);
 		}
-		return $this->_keys;
 	}
 
 	/**
-	 * Sets the key values associated with the data models.
-	 * @param array $keys the list of key values corresponding to [[models]].
+	 * @inheritdoc
 	 */
-	public function setKeys($keys)
+	protected function prepareTotalCount()
 	{
-		$this->_keys = $keys;
+		return count($this->allModels);
 	}
 
 	/**
diff --git a/framework/yii/data/DataProvider.php b/framework/yii/data/BaseDataProvider.php
similarity index 51%
rename from framework/yii/data/DataProvider.php
rename to framework/yii/data/BaseDataProvider.php
index d75be6f..15705b7 100644
--- a/framework/yii/data/DataProvider.php
+++ b/framework/yii/data/BaseDataProvider.php
@@ -12,21 +12,23 @@ use yii\base\Component;
 use yii\base\InvalidParamException;
 
 /**
- * DataProvider is the base class of data provider classes.
- *
- * It implements the [[getPagination()]] and [[getSort()]] methods as specified by the [[DataProviderInterface]].
+ * BaseDataProvider provides a base class that implements the [[DataProviderInterface]].
  *
  * @property integer $count The number of data models in the current page. This property is read-only.
+ * @property array $keys The list of key values corresponding to [[models]]. Each data model in [[models]] is
+ * uniquely identified by the corresponding key value in this array.
+ * @property array $models The list of data models in the current page.
  * @property Pagination|boolean $pagination The pagination object. If this is false, it means the pagination
  * is disabled. Note that the type of this property differs in getter and setter. See [[getPagination()]] and
  * [[setPagination()]] for details.
  * @property Sort|boolean $sort The sorting object. If this is false, it means the sorting is disabled. Note
  * that the type of this property differs in getter and setter. See [[getSort()]] and [[setSort()]] for details.
+ * @property integer $totalCount Total number of possible data models.
  *
  * @author Qiang Xue <qiang.xue@gmail.com>
  * @since 2.0
  */
-abstract class DataProvider extends Component implements DataProviderInterface
+abstract class BaseDataProvider extends Component implements DataProviderInterface
 {
 	/**
 	 * @var string an ID that uniquely identifies the data provider among all data providers.
@@ -37,6 +39,122 @@ abstract class DataProvider extends Component implements DataProviderInterface
 
 	private $_sort;
 	private $_pagination;
+	private $_keys;
+	private $_models;
+	private $_totalCount;
+
+
+	/**
+	 * Prepares the data models that will be made available in the current page.
+	 * @return array the available data models
+	 */
+	abstract protected function prepareModels();
+
+	/**
+	 * Prepares the keys associated with the currently available data models.
+	 * @param array $models the available data models
+	 * @return array the keys
+	 */
+	abstract protected function prepareKeys($models);
+
+	/**
+	 * Returns a value indicating the total number of data models in this data provider.
+	 * @return integer total number of data models in this data provider.
+	 */
+	abstract protected function prepareTotalCount();
+
+	/**
+	 * Prepares the data models and keys.
+	 *
+	 * This method will prepare the data models and keys that can be retrieved via
+	 * [[getModels()]] and [[getKeys()]].
+	 *
+	 * This method will be implicitly called by [[getModels()]] and [[getKeys()]] if it has not been called before.
+	 *
+	 * @param boolean $forcePrepare whether to force data preparation even if it has been done before.
+	 */
+	public function prepare($forcePrepare = false)
+	{
+		if ($forcePrepare || $this->_models === null) {
+			$this->_models = $this->prepareModels();
+		}
+		if ($forcePrepare || $this->_keys === null) {
+			$this->_keys = $this->prepareKeys($this->_models);
+		}
+	}
+
+	/**
+	 * Returns the data models in the current page.
+	 * @return array the list of data models in the current page.
+	 */
+	public function getModels()
+	{
+		$this->prepare();
+		return $this->_models;
+	}
+
+	/**
+	 * Sets the data models in the current page.
+	 * @param array $models the models in the current page
+	 */
+	public function setModels($models)
+	{
+		$this->_models = $models;
+	}
+
+	/**
+	 * Returns the key values associated with the data models.
+	 * @return array the list of key values corresponding to [[models]]. Each data model in [[models]]
+	 * is uniquely identified by the corresponding key value in this array.
+	 */
+	public function getKeys()
+	{
+		$this->prepare();
+		return $this->_keys;
+	}
+
+	/**
+	 * Sets the key values associated with the data models.
+	 * @param array $keys the list of key values corresponding to [[models]].
+	 */
+	public function setKeys($keys)
+	{
+		$this->_keys = $keys;
+	}
+
+	/**
+	 * Returns the number of data models in the current page.
+	 * @return integer the number of data models in the current page.
+	 */
+	public function getCount()
+	{
+		return count($this->getModels());
+	}
+
+	/**
+	 * Returns the total number of data models.
+	 * When [[pagination]] is false, this returns the same value as [[count]].
+	 * Otherwise, it will call [[prepareTotalCount()]] to get the count.
+	 * @return integer total number of possible data models.
+	 */
+	public function getTotalCount()
+	{
+		if ($this->getPagination() === false) {
+			return $this->getCount();
+		} elseif ($this->_totalCount === null) {
+			$this->_totalCount = $this->prepareTotalCount();
+		}
+		return $this->_totalCount;
+	}
+
+	/**
+	 * Sets the total number of data models.
+	 * @param integer $value the total number of data models.
+	 */
+	public function setTotalCount($value)
+	{
+		$this->_totalCount = $value;
+	}
 
 	/**
 	 * @return Pagination|boolean the pagination object. If this is false, it means the pagination is disabled.
@@ -48,7 +166,6 @@ abstract class DataProvider extends Component implements DataProviderInterface
 			if ($this->id !== null) {
 				$this->_pagination->pageVar = $this->id . '-page';
 			}
-			$this->_pagination->totalCount = $this->getTotalCount();
 		}
 		return $this->_pagination;
 	}
@@ -123,11 +240,14 @@ abstract class DataProvider extends Component implements DataProviderInterface
 	}
 
 	/**
-	 * Returns the number of data models in the current page.
-	 * @return integer the number of data models in the current page.
+	 * Refreshes the data provider.
+	 * After calling this method, if [[getModels()]], [[getKeys()]] or [[getTotalCount()]] is called again,
+	 * they will re-execute the query and return the latest data available.
 	 */
-	public function getCount()
+	public function refresh()
 	{
-		return count($this->getModels());
+		$this->_totalCount = null;
+		$this->_models = null;
+		$this->_keys = null;
 	}
 }
diff --git a/framework/yii/data/DataProviderInterface.php b/framework/yii/data/DataProviderInterface.php
index f0bc39d..1dea1e6 100644
--- a/framework/yii/data/DataProviderInterface.php
+++ b/framework/yii/data/DataProviderInterface.php
@@ -19,6 +19,18 @@ namespace yii\data;
 interface DataProviderInterface
 {
 	/**
+	 * Prepares the data models and keys.
+	 *
+	 * This method will prepare the data models and keys that can be retrieved via
+	 * [[getModels()]] and [[getKeys()]].
+	 *
+	 * This method will be implicitly called by [[getModels()]] and [[getKeys()]] if it has not been called before.
+	 *
+	 * @param boolean $forcePrepare whether to force data preparation even if it has been done before.
+	 */
+	public function prepare($forcePrepare = false);
+
+	/**
 	 * Returns the number of data models in the current page.
 	 * This is equivalent to `count($provider->getModels())`.
 	 * When [[pagination]] is false, this is the same as [[totalCount]].
diff --git a/framework/yii/widgets/BaseListView.php b/framework/yii/widgets/BaseListView.php
index 7268fbc..d4647ff 100644
--- a/framework/yii/widgets/BaseListView.php
+++ b/framework/yii/widgets/BaseListView.php
@@ -83,6 +83,7 @@ abstract class BaseListView extends Widget
 		if ($this->dataProvider === null) {
 			throw new InvalidConfigException('The "dataProvider" property must be set.');
 		}
+		$this->dataProvider->prepare();
 	}
 
 	/**
diff --git a/tests/unit/framework/data/ActiveDataProviderTest.php b/tests/unit/framework/data/ActiveDataProviderTest.php
index 79c0a39..276c525 100644
--- a/tests/unit/framework/data/ActiveDataProviderTest.php
+++ b/tests/unit/framework/data/ActiveDataProviderTest.php
@@ -94,9 +94,10 @@ class ActiveDataProviderTest extends DatabaseTestCase
 			'query' => $query->from('tbl_order')->orderBy('id'),
 		));
 		$pagination = $provider->getPagination();
-		$this->assertEquals(1, $pagination->getPageCount());
+		$this->assertEquals(0, $pagination->getPageCount());
 		$this->assertCount(3, $provider->getModels());
-		
+		$this->assertEquals(1, $pagination->getPageCount());
+
 		$provider->getPagination()->pageSize = 2;
 		$this->assertEquals(3, count($provider->getModels()));
 		$provider->refresh();