diff --git a/app/code/Magento/Checkout/Block/Onepage/Success.php b/app/code/Magento/Checkout/Block/Onepage/Success.php
index 3f128226841f42e6526add15cb828d448359c047..46f85df2019ef53debf6b5583bffb9c7c264e6b0 100644
--- a/app/code/Magento/Checkout/Block/Onepage/Success.php
+++ b/app/code/Magento/Checkout/Block/Onepage/Success.php
@@ -104,9 +104,10 @@ class Success extends \Magento\Framework\View\Element\Template
     {
         $orderId = $this->_checkoutSession->getLastOrderId();
         if ($orderId) {
-            $order = $this->_orderFactory->create()->load($orderId);
-            if ($order->getId()) {
-                $isVisible = !in_array($order->getStatus(), $this->_orderConfig->getInvisibleOnFrontStatuses());
+            $incrementId = $this->_checkoutSession->getLastRealOrderId();
+            $status = $this->_checkoutSession->getLastOrderStatus();
+            if ($status && $incrementId) {
+                $isVisible = !in_array($status, $this->_orderConfig->getInvisibleOnFrontStatuses());
                 $canView = $this->httpContext->getValue(Context::CONTEXT_AUTH) && $isVisible;
                 $this->addData(
                     [
@@ -115,7 +116,7 @@ class Success extends \Magento\Framework\View\Element\Template
                         'print_url' => $this->getUrl('sales/order/print', ['order_id' => $orderId]),
                         'can_print_order' => $isVisible,
                         'can_view_order'  => $canView,
-                        'order_id'  => $order->getIncrementId(),
+                        'order_id'  => $incrementId,
                     ]
                 );
             }
diff --git a/app/code/Magento/Checkout/Model/Type/Onepage.php b/app/code/Magento/Checkout/Model/Type/Onepage.php
index dae0433f518ad6d159a555a88a883ec78dc516cf..2f7b71dc698be94e4bb8a17ef81815e8611381d7 100644
--- a/app/code/Magento/Checkout/Model/Type/Onepage.php
+++ b/app/code/Magento/Checkout/Model/Type/Onepage.php
@@ -983,14 +983,18 @@ class Onepage
                 $redirectUrl
             )->setLastRealOrderId(
                 $order->getIncrementId()
+            )->setLastOrderStatus(
+                $order->getStatus()
             );
         }
 
         $this->_eventManager->dispatch(
             'checkout_submit_all_after',
-            ['order' => $order, 'quote' => $this->getQuote()]
+            [
+                'order' => $order,
+                'quote' => $this->getQuote()
+            ]
         );
-
         return $this;
     }
 
diff --git a/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php b/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php
index 919a4de1157f216db27acd8aa1b6f25520c3f956..54c8fee91f2c411fd470716906dc89087d403914 100644
--- a/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php
+++ b/app/code/Magento/Checkout/Test/Unit/Block/Onepage/SuccessTest.php
@@ -21,11 +21,6 @@ class SuccessTest extends \PHPUnit_Framework_TestCase
      */
     protected $orderConfig;
 
-    /**
-     * @var \Magento\Sales\Model\OrderFactory | \PHPUnit_Framework_MockObject_MockObject
-     */
-    protected $orderFactory;
-
     /**
      * @var \Magento\Checkout\Model\Session | \PHPUnit_Framework_MockObject_MockObject
      */
@@ -36,14 +31,19 @@ class SuccessTest extends \PHPUnit_Framework_TestCase
         $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
 
         $this->orderConfig = $this->getMock('Magento\Sales\Model\Order\Config', [], [], '', false);
-        $this->orderFactory = $this->getMock('Magento\Sales\Model\OrderFactory', ['create'], [], '', false);
-        $this->checkoutSession = $this->getMock('Magento\Checkout\Model\Session', ['getLastOrderId'], [], '', false);
+
+        $this->checkoutSession = $this->getMock(
+            'Magento\Checkout\Model\Session',
+            ['getLastOrderId', 'getLastRealOrderId', 'getLastOrderStatus'],
+            [],
+            '',
+            false
+        );
 
         $this->block = $objectManager->getObject(
             'Magento\Checkout\Block\Onepage\Success',
             [
                 'orderConfig' => $this->orderConfig,
-                'orderFactory' => $this->orderFactory,
                 'checkoutSession' => $this->checkoutSession
             ]
         );
@@ -74,28 +74,21 @@ class SuccessTest extends \PHPUnit_Framework_TestCase
     public function testToHtmlOrderVisibleOnFront(array $invisibleStatuses, $orderStatus, $expectedResult)
     {
         $orderId = 5;
-        $order = $this->getMock('Magento\Sales\Model\Order', ['getId', '__wakeup', 'load', 'getStatus'], [], '', false);
-
-        $order->expects($this->any())
-            ->method('load')
-            ->with($orderId)
-            ->will($this->returnValue($order));
-        $order->expects($this->any())
-            ->method('getId')
-            ->will($this->returnValue($orderId));
-        $order->expects($this->any())
-            ->method('getStatus')
-            ->will($this->returnValue($orderStatus));
+        $realOrderId = 100003332;
 
         $this->checkoutSession->expects($this->once())
             ->method('getLastOrderId')
             ->will($this->returnValue($orderId));
+        $this->checkoutSession->expects($this->once())
+            ->method('getLastRealOrderId')
+            ->will($this->returnValue($realOrderId));
+        $this->checkoutSession->expects($this->once())
+            ->method('getLastOrderStatus')
+            ->will($this->returnValue($orderStatus));
+
         $this->orderConfig->expects($this->any())
             ->method('getInvisibleOnFrontStatuses')
             ->will($this->returnValue($invisibleStatuses));
-        $this->orderFactory->expects($this->once())
-            ->method('create')
-            ->will($this->returnValue($order));
 
         $this->block->toHtml();
 
diff --git a/app/code/Magento/Customer/Model/Resource/Address.php b/app/code/Magento/Customer/Model/Resource/Address.php
index 3b6ae0a28c8f9e812e762b72dbfe45d35681ebe9..d45f79f9a662574a3ca5c5db2cefadfe299c1274 100644
--- a/app/code/Magento/Customer/Model/Resource/Address.php
+++ b/app/code/Magento/Customer/Model/Resource/Address.php
@@ -9,7 +9,7 @@ namespace Magento\Customer\Model\Resource;
 
 use Magento\Framework\Exception\InputException;
 
-class Address extends \Magento\Eav\Model\Entity\AbstractEntity
+class Address extends \Magento\Eav\Model\Entity\VersionControl\AbstractEntity
 {
     /**
      * @var \Magento\Framework\Validator\Factory
@@ -23,19 +23,23 @@ class Address extends \Magento\Eav\Model\Entity\AbstractEntity
 
     /**
      * @param \Magento\Eav\Model\Entity\Context $context
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
      * @param \Magento\Framework\Validator\Factory $validatorFactory
      * @param \Magento\Customer\Model\CustomerFactory $customerFactory
      * @param array $data
      */
     public function __construct(
         \Magento\Eav\Model\Entity\Context $context,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
         \Magento\Framework\Validator\Factory $validatorFactory,
         \Magento\Customer\Model\CustomerFactory $customerFactory,
         $data = []
     ) {
         $this->_validatorFactory = $validatorFactory;
         $this->_customerFactory = $customerFactory;
-        parent::__construct($context, $data);
+        parent::__construct($context, $entitySnapshot, $entityRelationComposite, $data);
     }
 
     /**
@@ -63,31 +67,6 @@ class Address extends \Magento\Eav\Model\Entity\AbstractEntity
         return parent::getEntityType();
     }
 
-    /**
-     * Set default shipping to address
-     *
-     * @param \Magento\Framework\Object $address
-     * @return $this
-     */
-    protected function _afterSave(\Magento\Framework\Object $address)
-    {
-        if ($address->getIsCustomerSaveTransaction()) {
-            return $this;
-        }
-        if ($address->getId() && ($address->getIsDefaultBilling() || $address->getIsDefaultShipping())) {
-            $customer = $this->_createCustomer()->load($address->getCustomerId());
-
-            if ($address->getIsDefaultBilling()) {
-                $customer->setDefaultBilling($address->getId());
-            }
-            if ($address->getIsDefaultShipping()) {
-                $customer->setDefaultShipping($address->getId());
-            }
-            $customer->save();
-        }
-        return $this;
-    }
-
     /**
      * Check customer address before saving
      *
diff --git a/app/code/Magento/Customer/Model/Resource/Address/Collection.php b/app/code/Magento/Customer/Model/Resource/Address/Collection.php
index 83018cb25c448d481bebc476493876d476ed9478..771db1c598ca9d09e88de1444bdcd30a27c57adc 100644
--- a/app/code/Magento/Customer/Model/Resource/Address/Collection.php
+++ b/app/code/Magento/Customer/Model/Resource/Address/Collection.php
@@ -10,7 +10,7 @@ namespace Magento\Customer\Model\Resource\Address;
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection
+class Collection extends \Magento\Eav\Model\Entity\Collection\VersionControl\AbstractCollection
 {
     /**
      * Resource initialization
diff --git a/app/code/Magento/Customer/Model/Resource/Address/Relation.php b/app/code/Magento/Customer/Model/Resource/Address/Relation.php
new file mode 100644
index 0000000000000000000000000000000000000000..0e10e2bb4612b3f55f4f9640264442608e6d9a41
--- /dev/null
+++ b/app/code/Magento/Customer/Model/Resource/Address/Relation.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * Customer address entity resource model
+ *
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Model\Resource\Address;
+
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface;
+
+/**
+ * Class represents save operations for customer address relations
+ */
+class Relation implements RelationInterface
+{
+    /**
+     * @var \Magento\Customer\Model\CustomerFactory
+     */
+    protected $customerFactory;
+
+    /**
+     * @param \Magento\Customer\Model\CustomerFactory $customerFactory
+     */
+    public function __construct(\Magento\Customer\Model\CustomerFactory $customerFactory)
+    {
+        $this->customerFactory = $customerFactory;
+    }
+
+    /**
+     * Process object relations
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return void
+     */
+    public function processRelation(\Magento\Framework\Model\AbstractModel $object)
+    {
+        /**
+         * @var $object \Magento\Customer\Model\Address
+         */
+        if (!$object->getIsCustomerSaveTransaction() && $this->isAddressDefault($object)) {
+            $customer = $this->customerFactory->create()->load($object->getCustomerId());
+            $changedAddresses = [];
+
+            if ($object->getIsDefaultBilling()) {
+                $changedAddresses['default_billing'] = $object->getId();
+            }
+
+            if ($object->getIsDefaultShipping()) {
+                $changedAddresses['default_shipping'] = $object->getId();
+            }
+
+            if ($changedAddresses) {
+                $customer->getResource()->getWriteConnection()->update(
+                    $customer->getResource()->getTable('customer_entity'),
+                    $changedAddresses,
+                    $customer->getResource()->getWriteConnection()->quoteInto('entity_id = ?', $customer->getId())
+                );
+            }
+        }
+    }
+
+    /**
+     * Checks if address has chosen as default and has had an id
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return bool
+     */
+    protected function isAddressDefault(\Magento\Framework\Model\AbstractModel $object)
+    {
+        return $object->getId() && ($object->getIsDefaultBilling() || $object->getIsDefaultShipping());
+    }
+}
diff --git a/app/code/Magento/Customer/Model/Resource/Customer.php b/app/code/Magento/Customer/Model/Resource/Customer.php
index 682e429411b7806b6c4695fcacaaecade20a7c88..16666b61689da0ccd4a50124c4128410b3bea0db 100644
--- a/app/code/Magento/Customer/Model/Resource/Customer.php
+++ b/app/code/Magento/Customer/Model/Resource/Customer.php
@@ -12,7 +12,7 @@ use Magento\Framework\Exception\AlreadyExistsException;
  * Customer entity resource model
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-class Customer extends \Magento\Eav\Model\Entity\AbstractEntity
+class Customer extends \Magento\Eav\Model\Entity\VersionControl\AbstractEntity
 {
     /**
      * @var \Magento\Framework\Validator\Factory
@@ -33,6 +33,8 @@ class Customer extends \Magento\Eav\Model\Entity\AbstractEntity
 
     /**
      * @param \Magento\Eav\Model\Entity\Context $context
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Framework\Validator\Factory $validatorFactory
      * @param \Magento\Framework\Stdlib\DateTime $dateTime
@@ -40,12 +42,14 @@ class Customer extends \Magento\Eav\Model\Entity\AbstractEntity
      */
     public function __construct(
         \Magento\Eav\Model\Entity\Context $context,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\Framework\Validator\Factory $validatorFactory,
         \Magento\Framework\Stdlib\DateTime $dateTime,
         $data = []
     ) {
-        parent::__construct($context, $data);
+        parent::__construct($context, $entitySnapshot, $entityRelationComposite, $data);
         $this->_scopeConfig = $scopeConfig;
         $this->_validatorFactory = $validatorFactory;
         $this->dateTime = $dateTime;
@@ -149,72 +153,14 @@ class Customer extends \Magento\Eav\Model\Entity\AbstractEntity
     /**
      * Save customer addresses and set default addresses in attributes backend
      *
-     * @param \Magento\Customer\Model\Customer $customer
+     * @param \Magento\Framework\Object $customer
      * @return $this
      */
     protected function _afterSave(\Magento\Framework\Object $customer)
     {
-        $this->_saveAddresses($customer);
         return parent::_afterSave($customer);
     }
 
-    /**
-     * Save/delete customer address
-     *
-     * @param \Magento\Customer\Model\Customer $customer
-     * @return $this
-     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
-     */
-    protected function _saveAddresses(\Magento\Customer\Model\Customer $customer)
-    {
-        $defaultBillingId = $customer->getData('default_billing');
-        $defaultShippingId = $customer->getData('default_shipping');
-        /** @var \Magento\Customer\Model\Address $address */
-        foreach ($customer->getAddresses() as $address) {
-            if ($address->getData('_deleted')) {
-                if ($address->getId() == $defaultBillingId) {
-                    $customer->setData('default_billing', null);
-                }
-                if ($address->getId() == $defaultShippingId) {
-                    $customer->setData('default_shipping', null);
-                }
-                $removedAddressId = $address->getId();
-                $address->delete();
-                // Remove deleted address from customer address collection
-                $customer->getAddressesCollection()->removeItemByKey($removedAddressId);
-            } else {
-                $address->setParentId(
-                    $customer->getId()
-                )->setStoreId(
-                    $customer->getStoreId()
-                )->setIsCustomerSaveTransaction(
-                    true
-                )->save();
-                if (($address->getIsPrimaryBilling() ||
-                    $address->getIsDefaultBilling()) && $address->getId() != $defaultBillingId
-                ) {
-                    $customer->setData('default_billing', $address->getId());
-                }
-                if (($address->getIsPrimaryShipping() ||
-                    $address->getIsDefaultShipping()) && $address->getId() != $defaultShippingId
-                ) {
-                    $customer->setData('default_shipping', $address->getId());
-                }
-            }
-        }
-        $changedAddresses = [];
-
-        $changedAddresses['default_billing'] = $customer->getData('default_billing');
-        $changedAddresses['default_shipping'] = $customer->getData('default_shipping');
-        $this->_getWriteAdapter()->update(
-            $this->getTable('customer_entity'),
-            $changedAddresses,
-            $this->_getWriteAdapter()->quoteInto('entity_id = ?', $customer->getId())
-        );
-
-        return $this;
-    }
-
     /**
      * Retrieve select object for loading base entity row
      *
diff --git a/app/code/Magento/Customer/Model/Resource/Customer/Collection.php b/app/code/Magento/Customer/Model/Resource/Customer/Collection.php
index 6e0cdd7780452fed7563bd6df4de70d75ceb84f1..2353c59e91c5556f340720af805bbd512658d081 100644
--- a/app/code/Magento/Customer/Model/Resource/Customer/Collection.php
+++ b/app/code/Magento/Customer/Model/Resource/Customer/Collection.php
@@ -9,8 +9,9 @@ namespace Magento\Customer\Model\Resource\Customer;
  * Customers collection
  *
  * @author      Magento Core Team <core@magentocommerce.com>
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection
+class Collection extends \Magento\Eav\Model\Entity\Collection\VersionControl\AbstractCollection
 {
     /**
      * Name of collection model
@@ -37,6 +38,7 @@ class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection
      * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory
      * @param \Magento\Eav\Model\Resource\Helper $resourceHelper
      * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Framework\Object\Copy\Config $fieldsetConfig
      * @param \Zend_Db_Adapter_Abstract $connection
      * @param string $modelName
@@ -53,6 +55,7 @@ class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection
         \Magento\Eav\Model\EntityFactory $eavEntityFactory,
         \Magento\Eav\Model\Resource\Helper $resourceHelper,
         \Magento\Framework\Validator\UniversalFactory $universalFactory,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Framework\Object\Copy\Config $fieldsetConfig,
         $connection = null,
         $modelName = self::CUSTOMER_MODEL_NAME
@@ -69,6 +72,7 @@ class Collection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection
             $eavEntityFactory,
             $resourceHelper,
             $universalFactory,
+            $entitySnapshot,
             $connection
         );
     }
diff --git a/app/code/Magento/Customer/Model/Resource/Customer/Relation.php b/app/code/Magento/Customer/Model/Resource/Customer/Relation.php
new file mode 100644
index 0000000000000000000000000000000000000000..3967a981b6e95cfb610febd4d5019f4c3ace74a8
--- /dev/null
+++ b/app/code/Magento/Customer/Model/Resource/Customer/Relation.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+
+namespace Magento\Customer\Model\Resource\Customer;
+
+/**
+ * Class Relation
+ */
+class Relation implements \Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface
+{
+    /**
+     * Save relations for Customer
+     *
+     * @param \Magento\Framework\Model\AbstractModel $customer
+     * @return void
+     * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     */
+    public function processRelation(\Magento\Framework\Model\AbstractModel $customer)
+    {
+        $defaultBillingId = $customer->getData('default_billing');
+        $defaultShippingId = $customer->getData('default_shipping');
+
+        /** @var \Magento\Customer\Model\Address $address */
+        foreach ($customer->getAddresses() as $address) {
+            if ($address->getData('_deleted')) {
+                if ($address->getId() == $defaultBillingId) {
+                    $customer->setData('default_billing', null);
+                }
+
+                if ($address->getId() == $defaultShippingId) {
+                    $customer->setData('default_shipping', null);
+                }
+
+                $removedAddressId = $address->getId();
+                $address->delete();
+
+                // Remove deleted address from customer address collection
+                $customer->getAddressesCollection()->removeItemByKey($removedAddressId);
+            } else {
+                $address->setParentId(
+                    $customer->getId()
+                )->setStoreId(
+                    $customer->getStoreId()
+                )->setIsCustomerSaveTransaction(
+                    true
+                )->save();
+
+                if (($address->getIsPrimaryBilling() ||
+                        $address->getIsDefaultBilling()) && $address->getId() != $defaultBillingId
+                ) {
+                    $customer->setData('default_billing', $address->getId());
+                }
+
+                if (($address->getIsPrimaryShipping() ||
+                        $address->getIsDefaultShipping()) && $address->getId() != $defaultShippingId
+                ) {
+                    $customer->setData('default_shipping', $address->getId());
+                }
+            }
+        }
+
+        $changedAddresses = [];
+
+        $changedAddresses['default_billing'] = $customer->getData('default_billing');
+        $changedAddresses['default_shipping'] = $customer->getData('default_shipping');
+
+        $customer->getResource()->getWriteConnection()->update(
+            $customer->getResource()->getTable('customer_entity'),
+            $changedAddresses,
+            $customer->getResource()->getWriteConnection()->quoteInto('entity_id = ?', $customer->getId())
+        );
+    }
+}
diff --git a/app/code/Magento/Customer/Model/Resource/Group.php b/app/code/Magento/Customer/Model/Resource/Group.php
index 6dc9888d7715024c2edb1d84158b0407df5a79c5..145ec38181b851afea01714368c2dbbb48a4e1f3 100644
--- a/app/code/Magento/Customer/Model/Resource/Group.php
+++ b/app/code/Magento/Customer/Model/Resource/Group.php
@@ -5,12 +5,15 @@
  */
 namespace Magento\Customer\Model\Resource;
 
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
+
 /**
  * Customer group resource model
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Group extends \Magento\Framework\Model\Resource\Db\AbstractDb
+class Group extends \Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb
 {
     /**
      * Group Management
@@ -26,19 +29,23 @@ class Group extends \Magento\Framework\Model\Resource\Db\AbstractDb
 
     /**
      * @param \Magento\Framework\Model\Resource\Db\Context $context
+     * @param Snapshot $entitySnapshot,
+     * @param RelationComposite $entityRelationComposite,
      * @param \Magento\Customer\Api\GroupManagementInterface $groupManagement
      * @param Customer\CollectionFactory $customersFactory
      * @param string|null $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        RelationComposite $entityRelationComposite,
         \Magento\Customer\Api\GroupManagementInterface $groupManagement,
         \Magento\Customer\Model\Resource\Customer\CollectionFactory $customersFactory,
         $resourcePrefix = null
     ) {
         $this->_groupManagement = $groupManagement;
         $this->_customersFactory = $customersFactory;
-        parent::__construct($context, $resourcePrefix);
+        parent::__construct($context, $entitySnapshot, $entityRelationComposite, $resourcePrefix);
     }
 
     /**
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Resource/Address/RelationTest.php b/app/code/Magento/Customer/Test/Unit/Model/Resource/Address/RelationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..0d72b965ace153289868b83e6ff6bc507d936fe9
--- /dev/null
+++ b/app/code/Magento/Customer/Test/Unit/Model/Resource/Address/RelationTest.php
@@ -0,0 +1,144 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Customer\Test\Unit\Model\Resource\Address;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+/**
+ * Class AddressTest
+ */
+class RelationTest extends \PHPUnit_Framework_TestCase
+{
+    /** @var  \Magento\Customer\Model\CustomerFactory | \PHPUnit_Framework_MockObject_MockObject */
+    protected $customerFactoryMock;
+
+    /** @var  \Magento\Customer\Model\Resource\Address\Relation */
+    protected $relation;
+
+    protected function setUp()
+    {
+        $this->customerFactoryMock = $this->getMock(
+            'Magento\Customer\Model\CustomerFactory',
+            ['create'],
+            [],
+            '',
+            false
+        );
+        $this->relation = (new ObjectManagerHelper($this))->getObject(
+            'Magento\Customer\Model\Resource\Address\Relation',
+            [
+                'customerFactory' => $this->customerFactoryMock
+            ]
+        );
+    }
+
+    /**
+     * @param $addressId
+     * @param $isDefaultBilling
+     * @param $isDefaultShipping
+     * @dataProvider getRelationDataProvider
+     */
+    public function testProcessRelation($addressId, $isDefaultBilling, $isDefaultShipping)
+    {
+        $addressModel = $this->getMock(
+            'Magento\Framework\Model\AbstractModel',
+            [
+                '__wakeup',
+                'getId',
+                'getEntityTypeId',
+                'getIsDefaultBilling',
+                'getIsDefaultShipping',
+                'hasDataChanges',
+                'validateBeforeSave',
+                'beforeSave',
+                'afterSave',
+                'isSaveAllowed'
+            ],
+            [],
+            '',
+            false
+        );
+        $customerModel = $this->getMock(
+            'Magento\Customer\Model\Customer',
+            ['__wakeup', 'setDefaultBilling', 'setDefaultShipping', 'save', 'load', 'getResource', 'getId'],
+            [],
+            '',
+            false
+        );
+        $customerResource = $this->getMockForAbstractClass(
+            'Magento\Framework\Model\Resource\Db\AbstractDb',
+            [],
+            '',
+            false,
+            false,
+            true,
+            ['getWriteConnection', 'getTable']
+        );
+        $adapter = $this->getMockForAbstractClass(
+            'Magento\Framework\DB\Adapter\AdapterInterface',
+            [],
+            '',
+            false,
+            false,
+            true,
+            ['update', 'quoteInto']
+        );
+        $customerModel->expects($this->any())->method('getResource')->willReturn($customerResource);
+        $addressModel->expects($this->any())->method('getId')->willReturn($addressId);
+        $addressModel->expects($this->any())->method('getIsDefaultShipping')->willReturn($isDefaultShipping);
+        $addressModel->expects($this->any())->method('getIsDefaultBilling')->willReturn($isDefaultBilling);
+        $addressModel->expects($this->any())->method('getIsCustomerSaveTransaction')->willReturn(false);
+
+        $customerModel->expects($this->any())
+             ->method('load')
+             ->willReturnSelf();
+
+        $this->customerFactoryMock->expects($this->any())
+            ->method('create')
+            ->willReturn($customerModel);
+        if ($addressId && ($isDefaultBilling || $isDefaultShipping)) {
+            $customerId = 1;
+            $customerResource->expects($this->exactly(2))->method('getWriteConnection')->willReturn($adapter);
+            $customerModel->expects($this->any())->method('getId')->willReturn(1);
+            $conditionSql = "entity_id = $customerId";
+            $adapter->expects($this->once())->method('quoteInto')
+                ->with('entity_id = ?', $customerId)
+                ->willReturn($conditionSql);
+            $customerResource->expects($this->once())->method('getTable')
+                ->with('customer_entity')
+                ->willReturn('customer_entity');
+            $toUpdate = [];
+            if ($isDefaultBilling) {
+                $toUpdate['default_billing'] = $addressId;
+            }
+            if ($isDefaultShipping) {
+                $toUpdate['default_shipping'] = $addressId;
+            }
+            $adapter->expects($this->once())->method('update')->with(
+                'customer_entity',
+                $toUpdate,
+                $conditionSql
+            );
+        }
+        $this->relation->processRelation($addressModel);
+    }
+
+    /**
+     * Data provider for processRelation method
+     *
+     * @return array
+     */
+    public function getRelationDataProvider()
+    {
+        return [
+            [null, true, true],
+            [1, true, true],
+            [1, true, false],
+            [1, false, true],
+            [1, false, false],
+        ];
+    }
+}
diff --git a/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php b/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php
index c15cf1596c8245fb30d8a79ba097923d545c26b0..11c8a8378e134a4eb9747d88c261421d9c8d41c1 100644
--- a/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php
+++ b/app/code/Magento/Customer/Test/Unit/Model/Resource/AddressTest.php
@@ -8,6 +8,8 @@
 
 namespace Magento\Customer\Test\Unit\Model\Resource;
 
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
 
 class AddressTest extends \PHPUnit_Framework_TestCase
@@ -21,12 +23,37 @@ class AddressTest extends \PHPUnit_Framework_TestCase
     /** @var \Magento\Eav\Model\Entity\Type */
     protected $eavConfigType;
 
+    /** @var  Snapshot|\PHPUnit_Framework_MockObject_MockObject */
+    protected $entitySnapshotMock;
+
+    /** @var  RelationComposite|\PHPUnit_Framework_MockObject_MockObject */
+    protected $entityRelationCompositeMock;
+
     protected function setUp()
     {
+        $this->entitySnapshotMock = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
+            [],
+            [],
+            '',
+            false
+        );
+
+
+        $this->entityRelationCompositeMock = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite',
+            [],
+            [],
+            '',
+            false
+        );
+
         $this->addressResource = (new ObjectManagerHelper($this))->getObject(
             'Magento\Customer\Model\Resource\Address',
             [
                 'resource' => $this->prepareResource(),
+                'entitySnapshot' => $this->entitySnapshotMock,
+                'entityRelationComposite' => $this->entityRelationCompositeMock,
                 'eavConfig' => $this->prepareEavConfig(),
                 'validatorFactory' => $this->prepareValidatorFactory(),
                 'customerFactory' => $this->prepareCustomerFactory()
@@ -43,22 +70,6 @@ class AddressTest extends \PHPUnit_Framework_TestCase
      */
     public function testSave($addressId, $isDefaultBilling, $isDefaultShipping)
     {
-        /** @var $customer \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject */
-        $customer = $this->getMock(
-            'Magento\Customer\Model\Customer',
-            ['__wakeup', 'setDefaultBilling', 'setDefaultShipping', 'save', 'load'],
-            [],
-            '',
-            false
-        );
-        $customer->expects($this->any())
-            ->method('load')
-            ->willReturnSelf();
-
-        $this->customerFactory->expects($this->any())
-            ->method('create')
-            ->willReturn($customer);
-
         /** @var $address \Magento\Customer\Model\Address|\PHPUnit_Framework_MockObject_MockObject */
         $address = $this->getMock(
             'Magento\Customer\Model\Address',
@@ -78,7 +89,8 @@ class AddressTest extends \PHPUnit_Framework_TestCase
             '',
             false
         );
-        $address->expects($this->once())->method('hasDataChanges')->willReturn(true);
+        $this->entitySnapshotMock->expects($this->once())->method('isModified')->willReturn(true);
+        $this->entityRelationCompositeMock->expects($this->once())->method('processRelations');
         $address->expects($this->once())->method('isSaveAllowed')->willReturn(true);
         $address->expects($this->once())->method('validateBeforeSave');
         $address->expects($this->once())->method('beforeSave');
@@ -87,19 +99,6 @@ class AddressTest extends \PHPUnit_Framework_TestCase
         $address->expects($this->any())->method('getId')->willReturn($addressId);
         $address->expects($this->any())->method('getIsDefaultShipping')->willReturn($isDefaultShipping);
         $address->expects($this->any())->method('getIsDefaultBilling')->willReturn($isDefaultBilling);
-        if ($addressId && ($isDefaultBilling || $isDefaultShipping)) {
-            if ($isDefaultBilling) {
-                $customer->expects($this->once())->method('setDefaultBilling')->with($addressId);
-            }
-            if ($isDefaultShipping) {
-                $customer->expects($this->once())->method('setDefaultShipping')->with($addressId);
-            }
-            $customer->expects($this->once())->method('save');
-        } else {
-            $customer->expects($this->never())->method('setDefaultBilling');
-            $customer->expects($this->never())->method('setDefaultShipping');
-            $customer->expects($this->never())->method('save');
-        }
         $this->addressResource->setType('customer_address');
         $this->addressResource->save($address);
     }
diff --git a/app/code/Magento/Customer/etc/di.xml b/app/code/Magento/Customer/etc/di.xml
index 692eba9dc08461d96d0c449b7ef3e158c31f0c66..cc98e7676b3fa9f7825da52d2d647966661a0978 100644
--- a/app/code/Magento/Customer/etc/di.xml
+++ b/app/code/Magento/Customer/etc/di.xml
@@ -126,4 +126,45 @@
             </argument>
         </arguments>
     </type>
+    <virtualType name="EavVersionControlSnapshot" type="Magento\Framework\Model\Resource\Db\VersionControl\Snapshot">
+        <arguments>
+            <argument name="metadata" xsi:type="object">Magento\Eav\Model\Entity\VersionControl\Metadata</argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="CustomerRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite">
+        <arguments>
+            <argument name="relationProcessors" xsi:type="array">
+                <item name="default" xsi:type="object">Magento\Customer\Model\Resource\Customer\Relation</item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <virtualType name="CustomerAddressRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite">
+        <arguments>
+            <argument name="relationProcessors" xsi:type="array">
+                <item name="default" xsi:type="object">Magento\Customer\Model\Resource\Address\Relation</item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <type name="Magento\Customer\Model\Resource\Customer">
+        <arguments>
+            <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument>
+            <argument name="entityRelationComposite" xsi:type="object">CustomerRelationsComposite</argument>
+        </arguments>
+    </type>
+    <type name="Magento\Customer\Model\Resource\Customer\Collection">
+        <arguments>
+            <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument>
+        </arguments>
+    </type>
+    <type name="Magento\Customer\Model\Resource\Address">
+        <arguments>
+            <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument>
+            <argument name="entityRelationComposite" xsi:type="object">CustomerAddressRelationsComposite</argument>
+        </arguments>
+    </type>
+    <type name="Magento\Customer\Model\Resource\Address\Collection">
+        <arguments>
+            <argument name="entitySnapshot" xsi:type="object">EavVersionControlSnapshot</argument>
+        </arguments>
+    </type>
 </config>
diff --git a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
index 96465ce1dfb580896dec931e5ee40ea2c7fec76a..0c36e420156d691b5a2cd7f1db7691117bc9ff7e 100755
--- a/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
+++ b/app/code/Magento/Eav/Model/Entity/Collection/AbstractCollection.php
@@ -896,6 +896,7 @@ abstract class AbstractCollection extends \Magento\Framework\Data\Collection\Abs
         \Magento\Framework\Profiler::start('set_orig_data');
         foreach ($this->_items as $item) {
             $item->setOrigData();
+            $this->beforeAddLoadedItem($item);
         }
         \Magento\Framework\Profiler::stop('set_orig_data');
 
diff --git a/app/code/Magento/Eav/Model/Entity/Collection/VersionControl/AbstractCollection.php b/app/code/Magento/Eav/Model/Entity/Collection/VersionControl/AbstractCollection.php
new file mode 100644
index 0000000000000000000000000000000000000000..57e071e2f846dbfd51e1de43ba6c49ebdf0eb2b8
--- /dev/null
+++ b/app/code/Magento/Eav/Model/Entity/Collection/VersionControl/AbstractCollection.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Eav\Model\Entity\Collection\VersionControl;
+
+/**
+ * Class Abstract Collection
+ */
+abstract class AbstractCollection extends \Magento\Eav\Model\Entity\Collection\AbstractCollection
+{
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot
+     */
+    protected $entitySnapshot;
+
+    /**
+     * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
+     * @param \Psr\Log\LoggerInterface $logger
+     * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
+     * @param \Magento\Framework\Event\ManagerInterface $eventManager
+     * @param \Magento\Eav\Model\Config $eavConfig
+     * @param \Magento\Framework\App\Resource $resource
+     * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory
+     * @param \Magento\Eav\Model\Resource\Helper $resourceHelper
+     * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
+     * @param mixed $connection
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
+     */
+    public function __construct(
+        \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
+        \Psr\Log\LoggerInterface $logger,
+        \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
+        \Magento\Framework\Event\ManagerInterface $eventManager,
+        \Magento\Eav\Model\Config $eavConfig,
+        \Magento\Framework\App\Resource $resource,
+        \Magento\Eav\Model\EntityFactory $eavEntityFactory,
+        \Magento\Eav\Model\Resource\Helper $resourceHelper,
+        \Magento\Framework\Validator\UniversalFactory $universalFactory,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
+        $connection = null
+    ) {
+        $this->entitySnapshot = $entitySnapshot;
+
+        parent::__construct(
+            $entityFactory,
+            $logger,
+            $fetchStrategy,
+            $eventManager,
+            $eavConfig,
+            $resource,
+            $eavEntityFactory,
+            $resourceHelper,
+            $universalFactory,
+            $connection
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function fetchItem()
+    {
+        $item = parent::fetchItem();
+        if ($item) {
+            $this->entitySnapshot->registerSnapshot($item);
+        }
+        return $item;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    protected function beforeAddLoadedItem(\Magento\Framework\Object $item)
+    {
+        $this->entitySnapshot->registerSnapshot($item);
+        return $item;
+    }
+}
diff --git a/app/code/Magento/Eav/Model/Entity/VersionControl/AbstractEntity.php b/app/code/Magento/Eav/Model/Entity/VersionControl/AbstractEntity.php
new file mode 100644
index 0000000000000000000000000000000000000000..781c1baae9a6e564cdad284fe5d6e175489bb8f0
--- /dev/null
+++ b/app/code/Magento/Eav/Model/Entity/VersionControl/AbstractEntity.php
@@ -0,0 +1,118 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Eav\Model\Entity\VersionControl;
+
+/**
+ * Class AbstractEntity
+ */
+abstract class AbstractEntity extends \Magento\Eav\Model\Entity\AbstractEntity
+{
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot
+     */
+    protected $entitySnapshot;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite
+     */
+    protected $entityRelationComposite;
+
+    /**
+     * @param \Magento\Eav\Model\Entity\Context $context
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite
+     * @param array $data
+     */
+    public function __construct(
+        \Magento\Eav\Model\Entity\Context $context,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
+        $data = []
+    ) {
+        $this->entitySnapshot = $entitySnapshot;
+        $this->entityRelationComposite = $entityRelationComposite;
+
+        parent::__construct($context, $data);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    protected function _afterLoad(\Magento\Framework\Object $object)
+    {
+        $this->entitySnapshot->registerSnapshot($object);
+        return parent::_afterLoad($object);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function save(\Magento\Framework\Model\AbstractModel $object)
+    {
+        /**
+         * Direct deleted items to delete method
+         */
+        if ($object->isDeleted()) {
+            return $this->delete($object);
+        }
+
+        $this->beginTransaction();
+
+        try {
+            if (!$this->isModified($object)) {
+                $this->entityRelationComposite->processRelations($object);
+                $this->commit();
+                return $this;
+            }
+
+            $object->validateBeforeSave();
+            $object->beforeSave();
+
+            if ($object->isSaveAllowed()) {
+                if (!$this->isPartialSave()) {
+                    $this->loadAllAttributes($object);
+                }
+
+                if ($this->getEntityTable() ==  \Magento\Eav\Model\Entity::DEFAULT_ENTITY_TABLE
+                    && !$object->getEntityTypeId()
+                ) {
+                    $object->setEntityTypeId($this->getTypeId());
+                }
+
+                $object->setParentId((int)$object->getParentId());
+
+                $this->objectRelationProcessor->validateDataIntegrity($this->getEntityTable(), $object->getData());
+
+                $this->_beforeSave($object);
+                $this->_processSaveData($this->_collectSaveData($object));
+                $this->_afterSave($object);
+                $this->entitySnapshot->registerSnapshot($object);
+                $object->afterSave();
+                $this->entityRelationComposite->processRelations($object);
+            }
+
+            $this->addCommitCallback([$object, 'afterCommitCallback'])->commit();
+            $object->setHasDataChanges(false);
+        } catch (\Exception $e) {
+            $this->rollBack();
+            $object->setHasDataChanges(true);
+            throw $e;
+        }
+
+        return $this;
+    }
+
+    /**
+     * Checks if entity was modified
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return bool
+     */
+    protected function isModified(\Magento\Framework\Model\AbstractModel $object)
+    {
+        return $this->entitySnapshot->isModified($object);
+    }
+}
diff --git a/app/code/Magento/Eav/Model/Entity/VersionControl/Metadata.php b/app/code/Magento/Eav/Model/Entity/VersionControl/Metadata.php
new file mode 100644
index 0000000000000000000000000000000000000000..c628f450b7a18a2197c24756bec82c0a6801e8c0
--- /dev/null
+++ b/app/code/Magento/Eav/Model/Entity/VersionControl/Metadata.php
@@ -0,0 +1,39 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Eav\Model\Entity\VersionControl;
+
+/**
+ * Class Metadata represents a list of entity fields that are applicable for persistence operations
+ */
+class Metadata extends \Magento\Framework\Model\Resource\Db\VersionControl\Metadata
+{
+    /**
+     * Returns list of entity fields that are applicable for persistence operations
+     *
+     * @param \Magento\Framework\Object $entity
+     * @return array
+     */
+    public function getFields(\Magento\Framework\Object $entity)
+    {
+        $entityClass = get_class($entity);
+        if (!isset($this->metadataInfo[$entityClass])) {
+            $fields = $entity->getResource()->getReadConnection()->describeTable(
+                $entity->getResource()->getEntityTable()
+            );
+
+            $fields = array_merge($fields, $entity->getAttributes());
+
+            $fields = array_fill_keys(
+                array_keys($fields),
+                null
+            );
+
+            $this->metadataInfo[$entityClass] = $fields;
+        }
+
+        return $this->metadataInfo[$entityClass];
+    }
+}
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php
similarity index 99%
rename from app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractTest.php
rename to app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php
index 3034b99b8714fa00a525568147f29c554be3db85..cce1b9d07a087bc140f09acb27b5c43b86570c0e 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/AbstractEntityTest.php
@@ -7,7 +7,7 @@ namespace Magento\Eav\Test\Unit\Model\Entity;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
-class AbstractTest extends \PHPUnit_Framework_TestCase
+class AbstractEntityTest extends \PHPUnit_Framework_TestCase
 {
     /**
      * Entity model to be tested
@@ -115,7 +115,7 @@ class AbstractTest extends \PHPUnit_Framework_TestCase
      *
      * @return \PHPUnit_Framework_MockObject_MockObject|\Magento\Framework\DB\Adapter\Pdo\Mysql
      */
-    private function _getAdapterMock()
+    protected function _getAdapterMock()
     {
         $adapter = $this->getMock(
             'Magento\Framework\DB\Adapter\Pdo\Mysql',
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/AbstractCollectionTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/AbstractCollectionTest.php
index cd7b8d2bc528bc197164bbecd83e58920dfe76b8..4d89903528b32dafe7beebaf68028b6f62eb848a 100644
--- a/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/AbstractCollectionTest.php
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/AbstractCollectionTest.php
@@ -5,10 +5,17 @@
  */
 namespace Magento\Eav\Test\Unit\Model\Entity\Collection;
 
+use Magento\Eav\Test\Unit\Model\Entity\Collection\AbstractCollectionStub;
+
+/**
+ * AbstractCollection test
+ *
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
 class AbstractCollectionTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Eav\Test\Unit\Model\Entity\Collection\AbstractCollectionStub|\PHPUnit_Framework_MockObject_MockObject
+     * @var AbstractCollectionStub|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $model;
 
@@ -57,6 +64,11 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase
      */
     protected $validatorFactoryMock;
 
+    /**
+     * @var \Magento\Framework\DB\Statement\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $statementMock;
+
     public function setUp()
     {
         $this->coreEntityFactoryMock = $this->getMock(
@@ -100,6 +112,7 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase
         $this->entityFactoryMock = $this->getMock('Magento\Eav\Model\EntityFactory', [], [], '', false);
         /** @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject */
         $connectionMock = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false);
+        $this->statementMock = $this->getMock('Magento\Framework\DB\Statement\Pdo\Mysql', ['fetch'], [], '', false);
         /** @var $selectMock \Zend_Db_Select|\PHPUnit_Framework_MockObject_MockObject */
         $selectMock = $this->getMock('Zend_Db_Select', [], [], '', false);
         $this->coreEntityFactoryMock->expects(
@@ -110,6 +123,7 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase
             $this->returnCallback([$this, 'getMagentoObject'])
         );
         $connectionMock->expects($this->any())->method('select')->will($this->returnValue($selectMock));
+        $connectionMock->expects($this->any())->method('query')->willReturn($this->statementMock);
 
         $this->coreResourceMock->expects(
             $this->any()
@@ -119,11 +133,11 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase
             $this->returnValue($connectionMock)
         );
         $entityMock = $this->getMock('Magento\Eav\Model\Entity\AbstractEntity', [], [], '', false);
-        $entityMock->expects($this->once())->method('getReadConnection')->will($this->returnValue($connectionMock));
-        $entityMock->expects($this->once())->method('getDefaultAttributes')->will($this->returnValue([]));
+        $entityMock->expects($this->any())->method('getReadConnection')->will($this->returnValue($connectionMock));
+        $entityMock->expects($this->any())->method('getDefaultAttributes')->will($this->returnValue([]));
 
         $this->validatorFactoryMock->expects(
-            $this->once()
+            $this->any()
         )->method(
             'create'
         )->with(
@@ -132,7 +146,7 @@ class AbstractCollectionTest extends \PHPUnit_Framework_TestCase
             $this->returnValue($entityMock)
         );
 
-        $this->model = new \Magento\Eav\Test\Unit\Model\Entity\Collection\AbstractCollectionStub(
+        $this->model = new AbstractCollectionStub(
             $this->coreEntityFactoryMock,
             $this->loggerMock,
             $this->fetchStrategyMock,
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionStub.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionStub.php
new file mode 100644
index 0000000000000000000000000000000000000000..ab2aa4dacd95e3f15d879205d09bf31dbd52bf9d
--- /dev/null
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionStub.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Eav\Test\Unit\Model\Entity\Collection\VersionControl;
+
+/**
+ * Stub for version control abstract collection model.
+ */
+class AbstractCollectionStub extends \Magento\Eav\Model\Entity\Collection\VersionControl\AbstractCollection
+{
+    /**
+     * Retrieve item by id
+     *
+     * @param   mixed $id
+     * @return  \Magento\Framework\Object
+     */
+    public function getItemById($id)
+    {
+        if (isset($this->_itemsById[$id])) {
+            return $this->_itemsById[$id];
+        }
+        return null;
+    }
+
+    /**
+     * Initialize collection
+     *
+     * @return void
+     */
+    protected function _construct()
+    {
+        return $this->_init('Magento\Framework\Object', 'test_entity_model');
+    }
+}
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..f3c890c71a1c0aed698a56ce0ff652c23a9f5c2f
--- /dev/null
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/Collection/VersionControl/AbstractCollectionTest.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Eav\Test\Unit\Model\Entity\Collection\VersionControl;
+
+use Magento\Eav\Test\Unit\Model\Entity\Collection\VersionControl\AbstractCollectionStub;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+/**
+ * Test for version control abstract collection model.
+ */
+class AbstractCollectionTest extends \Magento\Eav\Test\Unit\Model\Entity\Collection\AbstractCollectionTest
+{
+    /**
+     * Subject of testing.
+     *
+     * @var AbstractCollectionStub|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $subject;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entitySnapshot;
+
+    public function setUp()
+    {
+        parent::setUp();
+
+        $objectManager = new ObjectManager($this);
+
+        $this->entitySnapshot = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
+            ['registerSnapshot'],
+            [],
+            '',
+            false
+        );
+
+        $this->subject = $objectManager->getObject(
+            'Magento\Eav\Test\Unit\Model\Entity\Collection\VersionControl\AbstractCollectionStub',
+            [
+                'entityFactory' => $this->coreEntityFactoryMock,
+                'universalFactory' => $this->validatorFactoryMock,
+                'entitySnapshot' => $this->entitySnapshot
+            ]
+        );
+    }
+
+    /**
+     * @param array $data
+     * @dataProvider fetchItemDataProvider
+     */
+    public function testFetchItem(array $data)
+    {
+        $item = $this->getMagentoObject()->setData($data);
+
+        $this->statementMock->expects($this->once())
+            ->method('fetch')
+            ->willReturn($data);
+
+        if (!$data) {
+            $this->entitySnapshot->expects($this->never())->method('registerSnapshot');
+
+            $this->assertEquals(false, $this->subject->fetchItem());
+        } else {
+            $this->entitySnapshot->expects($this->once())->method('registerSnapshot')->with($item);
+
+            $this->assertEquals($item, $this->subject->fetchItem());
+        }
+    }
+
+    public static function fetchItemDataProvider()
+    {
+        return [
+            [[]],
+            [['attribute' => 'test']]
+        ];
+    }
+}
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/AbstractEntityTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/AbstractEntityTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..9c1865c483f8f3e048b6e7815fe919fdbed82ad9
--- /dev/null
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/AbstractEntityTest.php
@@ -0,0 +1,192 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Eav\Test\Unit\Model\Entity\VersionControl;
+
+use Magento\Eav\Model\Entity\VersionControl\AbstractEntity;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+/**
+ * Test for version control abstract entity model.
+ */
+class AbstractEntityTest extends \Magento\Eav\Test\Unit\Model\Entity\AbstractEntityTest
+{
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entitySnapshot;
+
+    /**
+     * @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entityRelationComposite;
+
+    protected function setUp()
+    {
+        $this->entitySnapshot = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
+            ['isModified', 'registerSnapshot'],
+            [],
+            '',
+            false
+        );
+
+        $this->entityRelationComposite = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite',
+            ['processRelations'],
+            [],
+            '',
+            false
+        );
+
+        parent::setUp();
+    }
+
+    /**
+     * @param string $attributeCode
+     * @param int $attributeSetId
+     * @param array $productData
+     * @param array $productOrigData
+     *
+     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
+     * @dataProvider productAttributesDataProvider
+     */
+    public function testSave($attributeCode, $attributeSetId, $productData, $productOrigData)
+    {
+        $object = $this->getMock(
+            'Magento\Catalog\Model\Product',
+            ['getOrigData', '__wakeup', 'beforeSave', 'afterSave', 'validateBeforeSave'],
+            [],
+            '',
+            false
+        );
+
+        $object->setEntityTypeId(1);
+        foreach ($productData as $key => $value) {
+            $object->setData($key, $value);
+        }
+        $object->expects($this->any())->method('getOrigData')->will($this->returnValue($productOrigData));
+
+        $entityType = new \Magento\Framework\Object();
+        $entityType->setEntityTypeCode('test');
+        $entityType->setEntityTypeId(0);
+        $entityType->setEntityTable('table');
+
+        $attributes = $this->_getAttributes();
+
+        $attribute = $this->_getAttributeMock($attributeCode, $attributeSetId);
+
+        /** @var $backendModel \Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend */
+        $backendModel = $this->getMock(
+            'Magento\Eav\Model\Entity\Attribute\Backend\AbstractBackend',
+            [
+                'getBackend',
+                'getBackendTable',
+                'getAffectedFields',
+                'isStatic',
+                'getEntityValueId',
+                'getEntityIdField'
+            ]
+        );
+
+        $backendModel->expects(
+            $this->once()
+        )->method(
+            'getAffectedFields'
+        )->will(
+            $this->returnValue(['test_table' => [['value_id' => 0, 'attribute_id' => $attributeCode]]])
+        );
+
+        $backendModel->expects($this->any())->method('isStatic')->will($this->returnValue(false));
+        $backendModel->expects($this->never())->method('getEntityValueId');
+        $backendModel->expects(
+            isset($productData['entity_id']) ? $this->never() : $this->once()
+        )->method(
+            'getEntityIdField'
+        )->will(
+            $this->returnValue('entity_id')
+        );
+
+        $backendModel->setAttribute($attribute);
+
+        $attribute->expects($this->any())->method('getBackend')->will($this->returnValue($backendModel));
+        $attribute->setId(222);
+        $attributes[$attributeCode] = $attribute;
+        $eavConfig = $this->getMockBuilder('Magento\Eav\Model\Config')
+            ->disableOriginalConstructor()
+            ->getMock();
+
+        $objectManager = new ObjectManager($this);
+
+        $this->entitySnapshot->expects($this->once())->method('isModified')->willReturn(true);
+        $this->entitySnapshot->expects($this->once())->method('registerSnapshot')->with($object);
+
+        $this->entityRelationComposite->expects($this->once())->method('processRelations')->with($object);
+
+        $arguments =  $objectManager->getConstructArguments(
+            'Magento\Eav\Model\Entity\VersionControl\AbstractEntity',
+            [
+                'eavConfig' => $eavConfig,
+                'entitySnapshot' => $this->entitySnapshot,
+                'entityRelationComposite' => $this->entityRelationComposite,
+                'data' => [
+                    'type' => $entityType,
+                    'entityTable' => 'entityTable',
+                    'attributesByCode' => $attributes
+                ]
+            ]
+        );
+
+        /** @var $model AbstractEntity|\PHPUnit_Framework_MockObject_MockObject */
+        $model = $this->getMockBuilder('Magento\Eav\Model\Entity\VersionControl\AbstractEntity')
+            ->setConstructorArgs($arguments)
+            ->setMethods(['_getValue', 'beginTransaction', 'commit', 'rollback'])
+            ->getMock();
+
+        $model->expects($this->any())->method('_getValue')->will($this->returnValue($eavConfig));
+
+        $eavConfig->expects($this->any())->method('getAttribute')->will(
+            $this->returnCallback(
+                function ($entityType, $attributeCode) use ($attributes) {
+                    return $entityType && isset($attributes[$attributeCode]) ? $attributes[$attributeCode] : null;
+                }
+            )
+        );
+
+        $model->setConnection($this->_getAdapterMock());
+        $model->isPartialSave(true);
+        $model->save($object);
+    }
+
+    public function testSaveNotModified()
+    {
+        $objectManager = new ObjectManager($this);
+
+        /** @var $object \Magento\Catalog\Model\Product|\PHPUnit_Framework_MockObject_MockObject */
+        $object = $this->getMock('Magento\Catalog\Model\Product', [], [], '', false);
+
+        $arguments = $objectManager->getConstructArguments(
+            'Magento\Eav\Model\Entity\VersionControl\AbstractEntity',
+            [
+                'entitySnapshot' => $this->entitySnapshot,
+                'entityRelationComposite' => $this->entityRelationComposite,
+            ]
+        );
+
+        /** @var $model AbstractEntity|\PHPUnit_Framework_MockObject_MockObject */
+        $model = $this->getMockBuilder('Magento\Eav\Model\Entity\VersionControl\AbstractEntity')
+            ->setConstructorArgs($arguments)
+            ->setMethods(['beginTransaction', 'commit'])
+            ->getMock();
+
+        $this->entitySnapshot->expects($this->once())->method('isModified')->willReturn(false);
+        $this->entitySnapshot->expects($this->never())->method('registerSnapshot');
+
+        $this->entityRelationComposite->expects($this->once())->method('processRelations')->with($object);
+
+        $model->save($object);
+    }
+}
diff --git a/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/MetadataTest.php b/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/MetadataTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..77e00daf49c9b623a851c86b7fbf5679d8e39faf
--- /dev/null
+++ b/app/code/Magento/Eav/Test/Unit/Model/Entity/VersionControl/MetadataTest.php
@@ -0,0 +1,104 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Eav\Test\Unit\Model\Entity\VersionControl;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+/**
+ * Test for version control metadata model.
+ */
+class MetadataTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Eav\Model\Entity\VersionControl\Metadata
+     */
+    protected $metadata;
+
+    /**
+     * @var \Magento\Framework\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\AbstractDb|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $resource;
+
+    /**
+     * @var \Magento\Framework\DB\Adapter\AdapterInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $connection;
+
+    protected function setUp()
+    {
+        $objectManager = new ObjectManager($this);
+
+        $this->model = $this->getMock(
+            'Magento\Framework\Model\AbstractModel',
+            ['getResource', 'getAttributes'],
+            [],
+            '',
+            false
+        );
+
+        $this->resource = $this->getMockForAbstractClass(
+            'Magento\Framework\DB\Adapter\AdapterInterface',
+            [],
+            '',
+            false,
+            false,
+            true,
+            ['getReadConnection', 'getEntityTable']
+        );
+
+        $this->connection = $this->getMockForAbstractClass(
+            'Magento\Framework\DB\Adapter\AdapterInterface',
+            [],
+            '',
+            false,
+            false
+        );
+
+        $this->model->expects($this->any())->method('getResource')->willReturn($this->resource);
+
+        $this->resource->expects($this->any())->method('getReadConnection')->willReturn($this->connection);
+
+        $this->metadata = $objectManager->getObject(
+            'Magento\Eav\Model\Entity\VersionControl\Metadata'
+        );
+    }
+
+    public function testGetFields()
+    {
+        $entityTable = 'entity_table';
+
+        $expectedDescribedTable = ['field1' => null, 'field2' => null];
+        $expectedAttributes = ['attribute1' => 'value1', 'attribute2' => 'value2'];
+
+        $expectedResults = array_merge($expectedDescribedTable, $expectedAttributes);
+
+        $this->resource->expects($this->any())->method('getEntityTable')->willReturn($entityTable);
+
+        $this->connection->expects($this->once())->method('describeTable')->with($entityTable)->willReturn(
+            $expectedDescribedTable
+        );
+
+        $this->model->expects($this->any())->method('getAttributes')->willReturn($expectedAttributes);
+        //check that fields load with null initial value
+        $this->assertEquals(
+            array_fill_keys(array_keys($expectedResults), null),
+            $this->metadata->getFields($this->model)
+        );
+
+        // Testing loading data from cache.
+        $this->connection->expects($this->never())->method('describeTable');
+
+        $this->assertEquals(
+            array_fill_keys(array_keys($expectedResults), null),
+            $this->metadata->getFields($this->model)
+        );
+    }
+}
diff --git a/app/code/Magento/Quote/Model/Quote.php b/app/code/Magento/Quote/Model/Quote.php
index 2dd5c4ca3add051bb7c518b939e8a1011e098a10..d55c9a70bb78a1fb496e4522c3639576dc935c62 100644
--- a/app/code/Magento/Quote/Model/Quote.php
+++ b/app/code/Magento/Quote/Model/Quote.php
@@ -801,33 +801,6 @@ class Quote extends AbstractExtensibleModel implements \Magento\Quote\Api\Data\C
         parent::beforeSave();
     }
 
-    /**
-     * Save related items
-     *
-     * @return $this
-     */
-    public function afterSave()
-    {
-        parent::afterSave();
-
-        if (null !== $this->_addresses) {
-            $this->getAddressesCollection()->save();
-        }
-
-        if (null !== $this->_items) {
-            $this->getItemsCollection()->save();
-        }
-
-        if (null !== $this->_payments) {
-            $this->getPaymentsCollection()->save();
-        }
-
-        if (null !== $this->_currentPayment) {
-            $this->getPayment()->save();
-        }
-        return $this;
-    }
-
     /**
      * Loading quote data by customer
      *
@@ -2496,6 +2469,46 @@ class Quote extends AbstractExtensibleModel implements \Magento\Quote\Api\Data\C
         return parent::_afterLoad();
     }
 
+    /**
+     * Checks if it was set
+     *
+     * @return bool
+     */
+    public function addressCollectionWasSet()
+    {
+        return null !== $this->_addresses;
+    }
+
+    /**
+     * Checks if it was set
+     *
+     * @return bool
+     */
+    public function itemsCollectionWasSet()
+    {
+        return null !== $this->_items;
+    }
+
+    /**
+     * Checks if it was set
+     *
+     * @return bool
+     */
+    public function paymentsCollectionWasSet()
+    {
+        return null !== $this->_payments;
+    }
+
+    /**
+     * Checks if it was set
+     *
+     * @return bool
+     */
+    public function currentPaymentWasSet()
+    {
+        return null !== $this->_currentPayment;
+    }
+
     /**
      * Return checkout method code
      *
diff --git a/app/code/Magento/Quote/Model/Quote/Address.php b/app/code/Magento/Quote/Model/Quote/Address.php
index 2d091f08d1db37e3320f316540eaabce7d3895f9..1c525a5a80af525844fae490d2e4a6de55d9da47 100644
--- a/app/code/Magento/Quote/Model/Quote/Address.php
+++ b/app/code/Magento/Quote/Model/Quote/Address.php
@@ -423,23 +423,6 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
             && $defaultBillingAddress == $defaultShippingAddress;
     }
 
-    /**
-     * Save child collections
-     *
-     * @return $this
-     */
-    public function afterSave()
-    {
-        parent::afterSave();
-        if (null !== $this->_items) {
-            $this->getItemsCollection()->save();
-        }
-        if (null !== $this->_rates) {
-            $this->getShippingRatesCollection()->save();
-        }
-        return $this;
-    }
-
     /**
      * Declare address quote model object
      *
@@ -538,7 +521,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
     /**
      * Retrieve address items collection
      *
-     * @return \Magento\Eav\Model\Entity\Collection\AbstractCollection
+     * @return \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
      */
     public function getItemsCollection()
     {
@@ -779,7 +762,7 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
     /**
      * Retrieve collection of quote shipping rates
      *
-     * @return \Magento\Eav\Model\Entity\Collection\AbstractCollection
+     * @return \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
      */
     public function getShippingRatesCollection()
     {
@@ -1114,6 +1097,26 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
         $this->setId(null);
     }
 
+    /**
+     * Checks if it was set
+     *
+     * @return bool
+     */
+    public function itemsCollectionWasSet()
+    {
+        return null !== $this->_items;
+    }
+
+    /**
+     * Checks if it was set
+     *
+     * @return bool
+     */
+    public function shippingRatesCollectionWasSet()
+    {
+        return null !== $this->_rates;
+    }
+
     /**
      * Validate minimum amount
      *
@@ -1572,7 +1575,12 @@ class Address extends \Magento\Customer\Model\Address\AbstractAddress implements
      */
     public function getEmail()
     {
-        return $this->getData(self::KEY_EMAIL);
+        $email = $this->getData(self::KEY_EMAIL);
+        if (!$email) {
+            $email = $this->getQuote()->getCustomerEmail();
+            $this->setEmail($email);
+        }
+        return $email;
     }
 
     /**
diff --git a/app/code/Magento/Quote/Model/Quote/Address/Relation.php b/app/code/Magento/Quote/Model/Quote/Address/Relation.php
new file mode 100644
index 0000000000000000000000000000000000000000..f5e499d4dcd6f90c302aa27cf696ece18b630681
--- /dev/null
+++ b/app/code/Magento/Quote/Model/Quote/Address/Relation.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Model\Quote\Address;
+
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface;
+
+class Relation implements RelationInterface
+{
+    /**
+     * Process object relations
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return void
+     */
+    public function processRelation(\Magento\Framework\Model\AbstractModel $object)
+    {
+        /**
+         * @var $object \Magento\Quote\Model\Quote\Address
+         */
+        if ($object->itemsCollectionWasSet()) {
+            $object->getItemsCollection()->save();
+        }
+        if ($object->shippingRatesCollectionWasSet()) {
+            $object->getShippingRatesCollection()->save();
+        }
+    }
+}
diff --git a/app/code/Magento/Quote/Model/Quote/Relation.php b/app/code/Magento/Quote/Model/Quote/Relation.php
new file mode 100644
index 0000000000000000000000000000000000000000..5e131ae6b3b015bab21603b1b316a7d00d644337
--- /dev/null
+++ b/app/code/Magento/Quote/Model/Quote/Relation.php
@@ -0,0 +1,36 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Model\Quote;
+
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface;
+
+class Relation implements RelationInterface
+{
+    /**
+     * Process object relations
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return void
+     */
+    public function processRelation(\Magento\Framework\Model\AbstractModel $object)
+    {
+        /**
+         * @var $object \Magento\Quote\Model\Quote
+         */
+        if ($object->addressCollectionWasSet()) {
+            $object->getAddressesCollection()->save();
+        }
+        if ($object->itemsCollectionWasSet()) {
+            $object->getItemsCollection()->save();
+        }
+        if ($object->paymentsCollectionWasSet()) {
+            $object->getPaymentsCollection()->save();
+        }
+        if ($object->currentPaymentWasSet()) {
+            $object->getPayment()->save();
+        }
+    }
+}
diff --git a/app/code/Magento/Quote/Model/QuoteManagement.php b/app/code/Magento/Quote/Model/QuoteManagement.php
index 8efb0a3794ddc6a584f1b4ae333c14a12ccac911..3a75073c3960f5741e0e296ca212755b0021e4a5 100644
--- a/app/code/Magento/Quote/Model/QuoteManagement.php
+++ b/app/code/Magento/Quote/Model/QuoteManagement.php
@@ -328,6 +328,7 @@ class QuoteManagement implements \Magento\Quote\Api\CartManagementInterface
         $this->checkoutSession->setLastSuccessQuoteId($quote->getId());
         $this->checkoutSession->setLastOrderId($order->getId());
         $this->checkoutSession->setLastRealOrderId($order->getIncrementId());
+        $this->checkoutSession->setLastOrderStatus($order->getStatus());
 
         $this->eventManager->dispatch('checkout_submit_all_after', ['order' => $order, 'quote' => $quote]);
         return $order->getId();
diff --git a/app/code/Magento/Quote/Model/Resource/Quote.php b/app/code/Magento/Quote/Model/Resource/Quote.php
index c9ac55ba5414bb7a9368eb495b62bbdf952bad44..c942d9bd2f86a51a404b560f2be507413324d0e4 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote.php
@@ -8,7 +8,10 @@
 
 namespace Magento\Quote\Model\Resource;
 
-use Magento\Framework\Model\Resource\Db\AbstractDb;
+use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
+use Magento\SalesSequence\Model\Manager;
 
 /**
  * Quote resource model
@@ -22,15 +25,19 @@ class Quote extends AbstractDb
 
     /**
      * @param \Magento\Framework\Model\Resource\Db\Context $context
+     * @param Snapshot $entitySnapshot,
+     * @param RelationComposite $entityRelationComposite,
      * @param \Magento\SalesSequence\Model\Manager $sequenceManager
      * @param null $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
-        \Magento\SalesSequence\Model\Manager $sequenceManager,
+        Snapshot $entitySnapshot,
+        RelationComposite $entityRelationComposite,
+        Manager $sequenceManager,
         $resourcePrefix = null
     ) {
-        parent::__construct($context, $resourcePrefix);
+        parent::__construct($context, $entitySnapshot, $entityRelationComposite, $resourcePrefix);
         $this->sequenceManager = $sequenceManager;
     }
 
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address.php b/app/code/Magento/Quote/Model/Resource/Quote/Address.php
index 350193fc2e13f7e5e260a063ddd1e06539f8ebb8..56d71a651e18a430a6201716464b7dd6700a1b18 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Address.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Address.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Quote\Model\Resource\Quote;
 
-use Magento\Framework\Model\Resource\Db\AbstractDb;
+use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb;
 
 /**
  * Quote address resource model
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Collection.php
index 960d256ca93ab766ea243de3216b370a401ff6fc..521daa91741d3806d4a96575cd0d696ea7cebae1 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Collection.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Collection.php
@@ -10,7 +10,7 @@ namespace Magento\Quote\Model\Resource\Quote\Address;
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection
 {
     /**
      * Event prefix
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Item.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Item.php
index 44365e28efd5339f851a5d9bf05d6dc06efd3a56..d156ba6804657d9bc20c62a117210bc5b7994dc0 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Item.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Item.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Quote\Model\Resource\Quote\Address;
 
-use Magento\Framework\Model\Resource\Db\AbstractDb;
+use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb;
 
 /**
  * Quote address item resource model
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Item/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Item/Collection.php
index 3ef5acacbbfae979a6f83a33a1b14d08d6e3eb67..03b381a572470fac7e1ff727ae76e71f129e9bce 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Item/Collection.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Item/Collection.php
@@ -10,7 +10,7 @@ namespace Magento\Quote\Model\Resource\Quote\Address\Item;
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection
 {
     /**
      * Resource initialization
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate.php
index 20177eb97cd48d36657ee22e8099d966caeaa250..221f1b42c5a1fe927e32fae8a3dac80e61b74ac7 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Quote\Model\Resource\Quote\Address;
 
-use Magento\Framework\Model\Resource\Db\AbstractDb;
+use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb;
 
 /**
  * Quote address shipping rate resource model
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate/Collection.php
index f21945483c6873facccac4eb9efeebe611ba723c..94d13b94377aaec1409cb8aa97e191bcb78b1fdc 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate/Collection.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Address/Rate/Collection.php
@@ -10,7 +10,7 @@ namespace Magento\Quote\Model\Resource\Quote\Address\Rate;
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection
 {
     /**
      * Whether to load fixed items only
@@ -24,8 +24,9 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Shipping\Model\CarrierFactoryInterface $carrierFactory
-     * @param \Zend_Db_Adapter_Abstract $connection
+     * @param \Zend_Db_Adapter_Abstract|null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
      */
     public function __construct(
@@ -33,11 +34,20 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Shipping\Model\CarrierFactoryInterface $carrierFactory,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
     ) {
-        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
+        parent::__construct(
+            $entityFactory,
+            $logger,
+            $fetchStrategy,
+            $eventManager,
+            $entitySnapshot,
+            $connection,
+            $resource
+        );
         $this->_carrierFactory = $carrierFactory;
     }
 
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Collection.php
index 426caa5d17fceb6b413de08d980edaeac59a611c..20e325fbf3678273365f9f20e185c1343cc0162d 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Collection.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Collection.php
@@ -10,7 +10,7 @@ namespace Magento\Quote\Model\Resource\Quote;
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection
 {
     /**
      * Resource initialization
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Item.php b/app/code/Magento/Quote/Model/Resource/Quote/Item.php
index dbe8c0944870f21be9a933a361f33076e354080d..0f527977b5a8fd1228b469d844d9e34d7bb6381a 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Item.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Item.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Quote\Model\Resource\Quote;
 
-use Magento\Framework\Model\Resource\Db\AbstractDb;
+use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb;
 
 /**
  * Quote resource model
@@ -29,7 +29,7 @@ class Item extends AbstractDb
      */
     public function save(\Magento\Framework\Model\AbstractModel $object)
     {
-        $hasDataChanges = $object->hasDataChanges();
+        $hasDataChanges = $this->isModified($object);
         $object->setIsOptionsSaved(false);
 
         $result = parent::save($object);
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Item/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Item/Collection.php
index 8f90d543450507681fd9e6678ce3390d37525eb1..56bbda864bc2cd501e68588e8582894708287169 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Item/Collection.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Item/Collection.php
@@ -8,7 +8,7 @@ namespace Magento\Quote\Model\Resource\Quote\Item;
 /**
  * Quote item resource collection
  */
-class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection
 {
     /**
      * Collection quote instance
@@ -44,24 +44,35 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Quote\Model\Resource\Quote\Item\Option\CollectionFactory $itemOptionCollectionFactory
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
+     * @param Option\CollectionFactory $itemOptionCollectionFactory
      * @param \Magento\Catalog\Model\Resource\Product\CollectionFactory $productCollectionFactory
      * @param \Magento\Quote\Model\Quote\Config $quoteConfig
-     * @param \Zend_Db_Adapter_Abstract $connection
+     * @param \Zend_Db_Adapter_Abstract|null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
+     * @SuppressWarnings(PHPMD.ExcessiveParameterList)
      */
     public function __construct(
         \Magento\Framework\Data\Collection\EntityFactory $entityFactory,
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Quote\Model\Resource\Quote\Item\Option\CollectionFactory $itemOptionCollectionFactory,
         \Magento\Catalog\Model\Resource\Product\CollectionFactory $productCollectionFactory,
         \Magento\Quote\Model\Quote\Config $quoteConfig,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
     ) {
-        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
+        parent::__construct(
+            $entityFactory,
+            $logger,
+            $fetchStrategy,
+            $eventManager,
+            $entitySnapshot,
+            $connection,
+            $resource
+        );
         $this->_itemOptionCollectionFactory = $itemOptionCollectionFactory;
         $this->_productCollectionFactory = $productCollectionFactory;
         $this->_quoteConfig = $quoteConfig;
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Payment.php b/app/code/Magento/Quote/Model/Resource/Quote/Payment.php
index 3275211dbf876b0405ef96cd17fe1842fe7fbfe4..8fc4f3446e2b129a9019cc4ce8def5475e1cb587 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Payment.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Payment.php
@@ -5,7 +5,7 @@
  */
 namespace Magento\Quote\Model\Resource\Quote;
 
-use Magento\Framework\Model\Resource\Db\AbstractDb;
+use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb;
 
 /**
  * Quote payment resource model
diff --git a/app/code/Magento/Quote/Model/Resource/Quote/Payment/Collection.php b/app/code/Magento/Quote/Model/Resource/Quote/Payment/Collection.php
index b1f14b76e7a53170de91a9f6ebe5e6ca5119291a..18b09bf83430939b3e4a3d508c9a602bea12bae7 100644
--- a/app/code/Magento/Quote/Model/Resource/Quote/Payment/Collection.php
+++ b/app/code/Magento/Quote/Model/Resource/Quote/Payment/Collection.php
@@ -8,14 +8,15 @@ namespace Magento\Quote\Model\Resource\Quote\Payment;
 /**
  * Quote payments collection
  */
-class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+class Collection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection
 {
     /**
      * @param \Magento\Framework\Data\Collection\EntityFactory $entityFactory
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Zend_Db_Adapter_Abstract $connection
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
+     * @param \Zend_Db_Adapter_Abstract|null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
      */
     public function __construct(
@@ -23,10 +24,19 @@ class Collection extends \Magento\Framework\Model\Resource\Db\Collection\Abstrac
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
     ) {
-        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
+        parent::__construct(
+            $entityFactory,
+            $logger,
+            $fetchStrategy,
+            $eventManager,
+            $entitySnapshot,
+            $connection,
+            $resource
+        );
     }
 
     /**
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/RelationTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/RelationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..b8fa10e5ed63043809e17c2ee10bb39926e9bc08
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Address/RelationTest.php
@@ -0,0 +1,66 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Test\Unit\Model\Quote\Address;
+
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class RelationTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Framework\Model\AbstractModel | \PHPUnit_Framework_MockObject_MockObject
+     */
+    private $modelMock;
+
+    /**
+     * @var \Magento\Quote\Model\Quote\Address\Relation
+     */
+    private $relation;
+
+    protected function setUp()
+    {
+        $objectManager = new ObjectManager($this);
+        $this->modelMock = $this->getMock(
+            'Magento\Framework\Model\AbstractModel',
+            [
+                'getItemsCollection',
+                'getShippingRatesCollection',
+                'itemsCollectionWasSet',
+                'shippingRatesCollectionWasSet'
+            ],
+            [],
+            '',
+            false
+        );
+        $this->relation = $objectManager->getObject('Magento\Quote\Model\Quote\Address\Relation', []);
+    }
+
+    public function testProcessRelation()
+    {
+        $itemsCollection = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\Collection\AbstractCollection',
+            [],
+            [],
+            '',
+            false
+        );
+        $shippingRatesCollection = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\Collection\AbstractCollection',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->modelMock->expects($this->once())->method('itemsCollectionWasSet')->willReturn(true);
+        $this->modelMock->expects($this->once())->method('getItemsCollection')->willReturn($itemsCollection);
+        $this->modelMock->expects($this->once())->method('shippingRatesCollectionWasSet')->willReturn(true);
+        $this->modelMock->expects($this->once())
+            ->method('getShippingRatesCollection')
+            ->willReturn($shippingRatesCollection);
+        $itemsCollection->expects($this->once())->method('save');
+        $shippingRatesCollection->expects($this->once())->method('save');
+        $this->relation->processRelation($this->modelMock);
+    }
+}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/AbstractItemTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/AbstractItemTest.php
index 2fd80d4588170a5594df523ff5586f5b6ef086d8..996d1d54955f38aee5c92e51030e5258497ef3a9 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/AbstractItemTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/Item/AbstractItemTest.php
@@ -22,7 +22,7 @@ class AbstractItemTest extends \PHPUnit_Framework_TestCase
     public function testGetTotalDiscountAmount($expectedDiscountAmount, $children, $calculated, $myDiscountAmount)
     {
         $abstractItemMock = $this->getMockForAbstractClass(
-            '\Magento\Quote\Model\Quote\Item\AbstractItem',
+            'Magento\Quote\Model\Quote\Item\AbstractItem',
             [],
             '',
             false,
@@ -51,7 +51,7 @@ class AbstractItemTest extends \PHPUnit_Framework_TestCase
     {
         $childOneDiscountAmount = 1000;
         $childOneItemMock = $this->getMockForAbstractClass(
-            '\Magento\Quote\Model\Quote\Item\AbstractItem',
+            'Magento\Quote\Model\Quote\Item\AbstractItem',
             [],
             '',
             false,
@@ -65,7 +65,7 @@ class AbstractItemTest extends \PHPUnit_Framework_TestCase
 
         $childTwoDiscountAmount = 50;
         $childTwoItemMock = $this->getMockForAbstractClass(
-            '\Magento\Quote\Model\Quote\Item\AbstractItem',
+            'Magento\Quote\Model\Quote\Item\AbstractItem',
             [],
             '',
             false,
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Quote/RelationTest.php b/app/code/Magento/Quote/Test/Unit/Model/Quote/RelationTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3b0723b9273e046a59f667ad3b3b5526d4182bcd
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/Quote/RelationTest.php
@@ -0,0 +1,82 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Test\Unit\Model\Quote;
+
+use Magento\Quote\Model\Quote\Relation;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+class RelationTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Relation
+     */
+    private $model;
+
+    /**
+     * @var \Magento\Quote\Model\Quote|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $quoteMock;
+
+    /**
+     * Mock class dependencies
+     */
+    protected function setUp()
+    {
+        $this->quoteMock = $this->getMock('Magento\Quote\Model\Quote', [], [], '', false);
+
+        $objectManager = new ObjectManager($this);
+        $this->model = $objectManager->getObject(
+            'Magento\Quote\Model\Quote\Relation'
+        );
+    }
+
+    /**
+     * Test for processRelation
+     */
+    public function testProcessRelation()
+    {
+        $addressCollectionMock = $this->getMock(
+            'Magento\Eav\Model\Entity\Collection\AbstractCollection',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->quoteMock->expects($this->once())->method('addressCollectionWasSet')->willReturn(true);
+        $this->quoteMock->expects($this->once())->method('getAddressesCollection')->willReturn($addressCollectionMock);
+        $addressCollectionMock->expects($this->once())->method('save');
+
+
+        $itemsCollectionMock = $this->getMock(
+            'Magento\Eav\Model\Entity\Collection\AbstractCollection',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->quoteMock->expects($this->once())->method('itemsCollectionWasSet')->willReturn(true);
+        $this->quoteMock->expects($this->once())->method('getItemsCollection')->willReturn($itemsCollectionMock);
+        $itemsCollectionMock->expects($this->once())->method('save');
+
+        $paymentCollectionMock = $this->getMock(
+            'Magento\Eav\Model\Entity\Collection\AbstractCollection',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->quoteMock->expects($this->once())->method('paymentsCollectionWasSet')->willReturn(true);
+        $this->quoteMock->expects($this->once())->method('getPaymentsCollection')->willReturn($paymentCollectionMock);
+        $paymentCollectionMock->expects($this->once())->method('save');
+
+        $paymentMock = $this->getMock('Magento\Quote\Model\Quote\Payment', [], [], '', false);
+        $this->quoteMock->expects($this->once())->method('currentPaymentWasSet')->willReturn(true);
+        $this->quoteMock->expects($this->once())->method('getPayment')->willReturn($paymentMock);
+        $paymentMock->expects($this->once())->method('save');
+
+        $this->model->processRelation($this->quoteMock);
+    }
+}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
index 287aaaa980f7ae354b3726adaea44f2e893cdbfc..b6a44c587386f6c5fa0e885261ac30c06a7c83c6 100644
--- a/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
+++ b/app/code/Magento/Quote/Test/Unit/Model/QuoteManagementTest.php
@@ -211,7 +211,7 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase
         $this->dataObjectHelperMock = $this->getMock('\Magento\Framework\Api\DataObjectHelper', [], [], '', false);
         $this->checkoutSessionMock = $this->getMock(
             'Magento\Checkout\Model\Session',
-            ['setLastQuoteId', 'setLastSuccessQuoteId', 'setLastOrderId', 'setLastRealOrderId'],
+            ['setLastQuoteId', 'setLastSuccessQuoteId', 'setLastOrderId', 'setLastRealOrderId', 'setLastOrderStatus'],
             [],
             '',
             false
@@ -652,6 +652,7 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase
         $cartId = 100;
         $orderId = 332;
         $orderIncrementId = 100003332;
+        $orderStatus = 'status1';
         $email = 'email@mail.com';
 
         $this->quoteRepositoryMock->expects($this->once())
@@ -710,14 +711,17 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase
         $service->expects($this->once())->method('submit')->willReturn($orderMock);
 
         $this->quoteMock->expects($this->atLeastOnce())->method('getId')->willReturn($cartId);
+
         $orderMock->expects($this->atLeastOnce())->method('getId')->willReturn($orderId);
         $orderMock->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($orderIncrementId);
+        $orderMock->expects($this->atLeastOnce())->method('getStatus')->willReturn($orderStatus);
 
         $this->checkoutSessionMock->expects($this->once())->method('setLastQuoteId')->with($cartId);
         $this->checkoutSessionMock->expects($this->once())->method('setLastSuccessQuoteId')->with($cartId);
         $this->checkoutSessionMock->expects($this->once())->method('setLastOrderId')->with($orderId);
         $this->checkoutSessionMock->expects($this->once())->method('setLastRealOrderId')->with($orderIncrementId);
-
+        $this->checkoutSessionMock->expects($this->once())->method('setLastOrderStatus')->with($orderStatus);
+ 
         $this->assertEquals($orderId, $service->placeOrder($cartId));
     }
 
@@ -726,6 +730,7 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase
         $cartId = 323;
         $orderId = 332;
         $orderIncrementId = 100003332;
+        $orderStatus = 'status1';
 
         /** @var \PHPUnit_Framework_MockObject_MockObject|\Magento\Quote\Model\QuoteManagement $service */
         $service = $this->getMock(
@@ -785,13 +790,16 @@ class QuoteManagementTest extends \PHPUnit_Framework_TestCase
         $service->expects($this->once())->method('submit')->willReturn($orderMock);
 
         $this->quoteMock->expects($this->atLeastOnce())->method('getId')->willReturn($cartId);
+
         $orderMock->expects($this->atLeastOnce())->method('getId')->willReturn($orderId);
         $orderMock->expects($this->atLeastOnce())->method('getIncrementId')->willReturn($orderIncrementId);
+        $orderMock->expects($this->atLeastOnce())->method('getStatus')->willReturn($orderStatus);
 
         $this->checkoutSessionMock->expects($this->once())->method('setLastQuoteId')->with($cartId);
         $this->checkoutSessionMock->expects($this->once())->method('setLastSuccessQuoteId')->with($cartId);
         $this->checkoutSessionMock->expects($this->once())->method('setLastOrderId')->with($orderId);
         $this->checkoutSessionMock->expects($this->once())->method('setLastRealOrderId')->with($orderIncrementId);
+        $this->checkoutSessionMock->expects($this->once())->method('setLastOrderStatus')->with($orderStatus);
 
         $paymentMethod = $this->getMock('Magento\Quote\Model\Quote\Payment', ['setChecks', 'getData'], [], '', false);
         $paymentMethod->expects($this->once())->method('setChecks');
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/Item/CollectionTest.php b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/Item/CollectionTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..04b1ab4442d2ebf9ac3f3d089cecc34504e90555
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/Item/CollectionTest.php
@@ -0,0 +1,94 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Test\Unit\Model\Resource\Quote\Item;
+
+use Magento\Quote\Model\Resource\Quote\Item\Collection;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
+
+/**
+ * Class CollectionTest
+ */
+class CollectionTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Collection
+     */
+    private $collection;
+
+    /**
+     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $connectionMock;
+
+    /**
+     * @var \Magento\Framework\Event\ManagerInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $eventManagerMock;
+
+    /**
+     * @var \Zend_Db_Select|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $selectMock;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\AbstractDb|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $resourceMock;
+
+    /**
+     * @var \Magento\Framework\Data\Collection\Db\FetchStrategyInterface|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $fetchStrategyMock;
+
+    /**
+     * @var \Magento\Framework\Data\Collection\EntityFactory|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entityFactoryMock;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entitySnapshotMock;
+
+    /**
+     * Mock class dependencies
+     */
+    protected function setUp()
+    {
+        $this->entityFactoryMock = $this->getMock('Magento\Framework\Data\Collection\EntityFactory', [], [], '', false);
+        $this->fetchStrategyMock = $this->getMockForAbstractClass(
+            'Magento\Framework\Data\Collection\Db\FetchStrategyInterface'
+        );
+        $this->eventManagerMock = $this->getMock('Magento\Framework\Event\ManagerInterface', [], [], '', false);
+
+        $this->selectMock = $this->getMock('Zend_Db_Select', [], [], '', false);
+        $this->connectionMock = $this->getMock('Magento\Framework\DB\Adapter\Pdo\Mysql', [], [], '', false);
+        $this->connectionMock->expects($this->atLeastOnce())
+            ->method('select')
+            ->will($this->returnValue($this->selectMock));
+
+        $this->resourceMock = $this->getMock('Magento\Framework\Model\Resource\Db\AbstractDb', [], [], '', false);
+        $this->resourceMock->expects($this->any())->method('getReadConnection')->will(
+            $this->returnValue($this->connectionMock)
+        );
+
+        $objectManager = new ObjectManager($this);
+        $this->collection = $objectManager->getObject(
+            'Magento\Quote\Model\Resource\Quote\Item\Collection',
+            [
+                'entityFactory' => $this->entityFactoryMock,
+                'fetchStrategy' => $this->fetchStrategyMock,
+                'eventManager' => $this->eventManagerMock,
+                'resource' => $this->resourceMock
+            ]
+        );
+    }
+
+    public function testInstanceOf()
+    {
+        $this->assertInstanceOf('Magento\Framework\Model\Resource\Db\VersionControl\Collection', $this->collection);
+    }
+}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/ItemTest.php b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/ItemTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..60eb9d9eda57e978a5fd8c95a6f5de3cadfee183
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/ItemTest.php
@@ -0,0 +1,179 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Test\Unit\Model\Resource\Quote;
+
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
+use Magento\Quote\Model\Resource\Quote\Item;
+use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
+
+/**
+ * Class ItemTest
+ *
+ * @SuppressWarnings(PHPMD.TooManyFields)
+ * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ */
+class ItemTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var Item
+     */
+    protected $model;
+
+    /**
+     * @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $resourceMock;
+
+    /**
+     * @var \Magento\Quote\Model\Quote\Item|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $quoteItemMock;
+
+    /**
+     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $adapterMock;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entitySnapshotMock;
+
+    /**
+     * @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $relationCompositeMock;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\ObjectRelationProcessor|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $objectRelationProcessorMock;
+
+    /**
+     * Mock class dependencies
+     */
+    public function setUp()
+    {
+        $this->resourceMock = $this->getMock('Magento\Framework\App\Resource', [], [], '', false);
+        $this->quoteItemMock = $this->getMock('Magento\Quote\Model\Quote\Item', [], [], '', false);
+        $this->adapterMock = $this->getMock(
+            'Magento\Framework\DB\Adapter\Pdo\Mysql',
+            [
+                'describeTable',
+                'insert',
+                'lastInsertId',
+                'beginTransaction',
+                'rollback',
+                'commit',
+                'quoteInto',
+                'update'
+            ],
+            [],
+            '',
+            false
+        );
+        $this->entitySnapshotMock = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->relationCompositeMock = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->objectRelationProcessorMock = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\ObjectRelationProcessor',
+            [],
+            [],
+            '',
+            false
+        );
+        $contextMock = $this->getMock('\Magento\Framework\Model\Resource\Db\Context', [], [], '', false);
+        $contextMock->expects($this->once())->method('getResources')->willReturn($this->resourceMock);
+        $contextMock->expects($this->once())
+            ->method('getObjectRelationProcessor')
+            ->willReturn($this->objectRelationProcessorMock);
+
+        $objectManager = new ObjectManagerHelper($this);
+        $this->model = $objectManager->getObject(
+            'Magento\Quote\Model\Resource\Quote\Item',
+            [
+                'context' => $contextMock,
+                'entitySnapshot' => $this->entitySnapshotMock,
+                'entityRelationComposite' => $this->relationCompositeMock
+            ]
+        );
+    }
+
+    public function testInstanceOf()
+    {
+        $this->assertInstanceOf('Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb', $this->model);
+    }
+
+    public function testSaveNotModifiedItem()
+    {
+        $this->entitySnapshotMock->expects($this->exactly(2))
+            ->method('isModified')
+            ->with($this->quoteItemMock)
+            ->willReturn(false);
+
+        $this->quoteItemMock->expects($this->never())
+            ->method('isOptionsSaved');
+        $this->quoteItemMock->expects($this->never())
+            ->method('saveItemOptions');
+
+        $this->resourceMock->expects($this->any())
+            ->method('getConnection')
+            ->willReturn($this->adapterMock);
+
+        $this->assertEquals($this->model, $this->model->save($this->quoteItemMock));
+    }
+
+    public function testSaveSavedBeforeItem()
+    {
+        $this->entitySnapshotMock->expects($this->exactly(2))
+            ->method('isModified')
+            ->with($this->quoteItemMock)
+            ->willReturn(true);
+
+        $this->quoteItemMock->expects($this->once())
+            ->method('isOptionsSaved')
+            ->willReturn(true);
+        $this->quoteItemMock->expects($this->never())
+            ->method('saveItemOptions');
+
+        $this->resourceMock->expects($this->any())
+            ->method('getConnection')
+            ->willReturn($this->adapterMock);
+
+        $this->assertEquals($this->model, $this->model->save($this->quoteItemMock));
+    }
+
+    public function testSaveModifiedItem()
+    {
+        $this->entitySnapshotMock->expects($this->exactly(2))
+            ->method('isModified')
+            ->with($this->quoteItemMock)
+            ->willReturn(true);
+
+        $this->quoteItemMock->expects($this->once())
+            ->method('isOptionsSaved')
+            ->willReturn(false);
+        $this->quoteItemMock->expects($this->once())
+            ->method('saveItemOptions');
+
+        $this->resourceMock->expects($this->any())
+            ->method('getConnection')
+            ->willReturn($this->adapterMock);
+
+        $this->assertEquals($this->model, $this->model->save($this->quoteItemMock));
+    }
+}
diff --git a/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/QuoteAddressTest.php b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/QuoteAddressTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..a7713ff991ba28f6d17e7d13547abc6a8640ea83
--- /dev/null
+++ b/app/code/Magento/Quote/Test/Unit/Model/Resource/Quote/QuoteAddressTest.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Quote\Test\Unit\Model\Resource\Quote;
+
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
+
+/**
+ * Class QuoteAddressTest
+ */
+class QuoteAddressTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var \Magento\Quote\Model\Resource\Quote\Address
+     */
+    protected $addressResource;
+
+    /**
+     * @var \Magento\Framework\App\Resource|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $appResourceMock;
+
+    /**
+     * @var \Magento\Quote\Model\Quote\Address|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $addressMock;
+
+    /**
+     * @var \Magento\Quote\Model\Quote|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $quoteMock;
+
+    /**
+     * @var \Magento\Framework\DB\Adapter\Pdo\Mysql|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $adapterMock;
+
+    /**
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $entitySnapshotMock;
+
+    /**
+     * @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject
+     */
+    protected $relationCompositeMock;
+
+    /**
+     * Init
+     */
+    public function setUp()
+    {
+        $this->addressMock = $this->getMock(
+            'Magento\Quote\Model\Quote\Address',
+            ['__wakeup', 'getOrderId', 'hasDataChanges', 'beforeSave', 'afterSave', 'validateBeforeSave', 'getOrder'],
+            [],
+            '',
+            false
+        );
+        $this->quoteMock = $this->getMock(
+            'Magento\Quote\Model\Quote',
+            ['__wakeup', 'getId'],
+            [],
+            '',
+            false
+        );
+        $this->appResourceMock = $this->getMock(
+            'Magento\Framework\App\Resource',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->adapterMock = $this->getMock(
+            'Magento\Framework\DB\Adapter\Pdo\Mysql',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->entitySnapshotMock = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->relationCompositeMock = $this->getMock(
+            'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite',
+            [],
+            [],
+            '',
+            false
+        );
+        $this->appResourceMock->expects($this->any())
+                              ->method('getConnection')
+                              ->will($this->returnValue($this->adapterMock));
+        $objectManager = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
+        $this->adapterMock->expects($this->any())
+                          ->method('describeTable')
+                          ->will($this->returnValue([]));
+        $this->adapterMock->expects($this->any())
+                          ->method('insert');
+        $this->adapterMock->expects($this->any())
+                          ->method('lastInsertId');
+        $this->addressResource = $objectManager->getObject(
+            'Magento\Quote\Model\Resource\Quote\Address',
+            [
+                'resource' => $this->appResourceMock,
+                'entitySnapshot' => $this->entitySnapshotMock,
+                'entityRelationComposite' => $this->relationCompositeMock
+            ]
+        );
+    }
+
+    public function testSave()
+    {
+        $this->entitySnapshotMock->expects($this->once())
+                                 ->method('isModified')
+                                 ->with($this->addressMock)
+                                 ->willReturn(true);
+        $this->entitySnapshotMock->expects($this->once())
+                                 ->method('registerSnapshot')
+                                 ->with($this->addressMock);
+        $this->relationCompositeMock->expects($this->once())
+                                 ->method('processRelations')
+                                 ->with($this->addressMock);
+        $this->addressResource->save($this->addressMock);
+    }
+}
diff --git a/app/code/Magento/Quote/etc/di.xml b/app/code/Magento/Quote/etc/di.xml
index 0c3b51e3a5ddc2e2a5c3b6991de7eb92629c999b..8766552b2bca3a3ee0743e672a0335d4c5c858d2 100644
--- a/app/code/Magento/Quote/etc/di.xml
+++ b/app/code/Magento/Quote/etc/di.xml
@@ -55,6 +55,30 @@
             <argument name="addressConfig" xsi:type="object">Magento\Customer\Model\Address\Config\Proxy</argument>
         </arguments>
     </type>
+    <virtualType name="QuoteAddressRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite">
+        <arguments>
+            <argument name="relationProcessors" xsi:type="array">
+                <item name="default" xsi:type="object">Magento\Quote\Model\Quote\Address\Relation</item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <type name="Magento\Quote\Model\Resource\Quote\Address">
+        <arguments>
+            <argument name="entityRelationComposite" xsi:type="object">QuoteAddressRelationsComposite</argument>
+        </arguments>
+    </type>
+    <virtualType name="QuoteRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite">
+        <arguments>
+            <argument name="relationProcessors" xsi:type="array">
+                <item name="default" xsi:type="object">Magento\Quote\Model\Quote\Relation</item>
+            </argument>
+        </arguments>
+    </virtualType>
+    <type name="Magento\Quote\Model\Resource\Quote">
+        <arguments>
+            <argument name="entityRelationComposite" xsi:type="object">QuoteRelationsComposite</argument>
+        </arguments>
+    </type>
     <preference for="Magento\Quote\Api\Data\AddressAdditionalDataInterface" type="Magento\Quote\Model\AddressAdditionalData" />
     <preference for="Magento\Quote\Api\Data\TotalsAdditionalDataInterface" type="Magento\Quote\Model\Cart\TotalsAdditionalData" />
     <preference for="\Magento\Quote\Model\Quote\Address\CustomAttributeListInterface" type="\Magento\Quote\Model\Quote\Address\CustomAttributeList" />
diff --git a/app/code/Magento/Reports/Model/Resource/Customer/Collection.php b/app/code/Magento/Reports/Model/Resource/Customer/Collection.php
index c602eb91ae9b4284b289204770089483d4879ffe..637f593308083813a3e0f89cac78e612279d76a1 100644
--- a/app/code/Magento/Reports/Model/Resource/Customer/Collection.php
+++ b/app/code/Magento/Reports/Model/Resource/Customer/Collection.php
@@ -81,6 +81,7 @@ class Collection extends \Magento\Customer\Model\Resource\Customer\Collection
      * @param \Magento\Eav\Model\EntityFactory $eavEntityFactory
      * @param \Magento\Eav\Model\Resource\Helper $resourceHelper
      * @param \Magento\Framework\Validator\UniversalFactory $universalFactory
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Framework\Object\Copy\Config $fieldsetConfig
      * @param \Magento\Quote\Model\QuoteRepository $quoteRepository
      * @param \Magento\Quote\Model\Resource\Quote\Item\CollectionFactory $quoteItemFactory
@@ -100,6 +101,7 @@ class Collection extends \Magento\Customer\Model\Resource\Customer\Collection
         \Magento\Eav\Model\EntityFactory $eavEntityFactory,
         \Magento\Eav\Model\Resource\Helper $resourceHelper,
         \Magento\Framework\Validator\UniversalFactory $universalFactory,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Framework\Object\Copy\Config $fieldsetConfig,
         \Magento\Quote\Model\QuoteRepository $quoteRepository,
         \Magento\Quote\Model\Resource\Quote\Item\CollectionFactory $quoteItemFactory,
@@ -117,6 +119,7 @@ class Collection extends \Magento\Customer\Model\Resource\Customer\Collection
             $eavEntityFactory,
             $resourceHelper,
             $universalFactory,
+            $entitySnapshot,
             $fieldsetConfig,
             $connection,
             $modelName
diff --git a/app/code/Magento/Reports/Model/Resource/Order/Collection.php b/app/code/Magento/Reports/Model/Resource/Order/Collection.php
index 07c2e2aa8c4a76d1d262f38904d52b00ea622f99..97294fb8ddd9371e270a9dde67709910fbe56696 100644
--- a/app/code/Magento/Reports/Model/Resource/Order/Collection.php
+++ b/app/code/Magento/Reports/Model/Resource/Order/Collection.php
@@ -72,7 +72,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Collection
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Framework\DB\Helper $coreResourceHelper
      * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
      * @param \Magento\Store\Model\StoreManagerInterface $storeManager
@@ -89,7 +89,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Collection
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Framework\DB\Helper $coreResourceHelper,
         \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
         \Magento\Store\Model\StoreManagerInterface $storeManager,
diff --git a/app/code/Magento/Reports/Model/Resource/Quote/Collection.php b/app/code/Magento/Reports/Model/Resource/Quote/Collection.php
index c83ab61da03371c03db533b27a46a4ad88c82205..ccad3cf8f4e8c37eabe56bc75897674dc820dd2c 100644
--- a/app/code/Magento/Reports/Model/Resource/Quote/Collection.php
+++ b/app/code/Magento/Reports/Model/Resource/Quote/Collection.php
@@ -17,6 +17,7 @@ class Collection extends \Magento\Quote\Model\Resource\Quote\Collection
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Customer\Model\Resource\Customer $customerResource
      * @param \Zend_Db_Adapter_Abstract $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
@@ -26,11 +27,20 @@ class Collection extends \Magento\Quote\Model\Resource\Quote\Collection
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Customer\Model\Resource\Customer $customerResource,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
     ) {
-        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
+        parent::__construct(
+            $entityFactory,
+            $logger,
+            $fetchStrategy,
+            $eventManager,
+            $entitySnapshot,
+            $connection,
+            $resource
+        );
         $this->customerResource = $customerResource;
     }
 
diff --git a/app/code/Magento/Reports/Test/Unit/Model/Resource/Order/CollectionTest.php b/app/code/Magento/Reports/Test/Unit/Model/Resource/Order/CollectionTest.php
index 22a6bb1be49c2719d81af2339c7feef95295a195..b2414a6b388de779cec6e34ce0a06527085f9996 100644
--- a/app/code/Magento/Reports/Test/Unit/Model/Resource/Order/CollectionTest.php
+++ b/app/code/Magento/Reports/Test/Unit/Model/Resource/Order/CollectionTest.php
@@ -102,7 +102,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
             ->getMock();
         $this->managerMock = $this->getMockBuilder('Magento\Framework\Event\ManagerInterface')
             ->getMock();
-        $this->entitySnapshotMock = $this->getMockBuilder('Magento\Sales\Model\Resource\EntitySnapshot')
+        $this->entitySnapshotMock = $this->getMockBuilder('Magento\Framework\Model\Resource\Db\VersionControl\Snapshot')
             ->disableOriginalConstructor()
             ->getMock();
         $this->helperMock = $this->getMockBuilder('Magento\Framework\DB\Helper')
diff --git a/app/code/Magento/Reports/Test/Unit/Model/Resource/Quote/CollectionTest.php b/app/code/Magento/Reports/Test/Unit/Model/Resource/Quote/CollectionTest.php
index a8bea7e05133cba46c465b46f3d6e9f170559d3c..3f24f1a6d7e7be362ab20453647af0c9dd6c7952 100644
--- a/app/code/Magento/Reports/Test/Unit/Model/Resource/Quote/CollectionTest.php
+++ b/app/code/Magento/Reports/Test/Unit/Model/Resource/Quote/CollectionTest.php
@@ -42,6 +42,11 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
      */
     protected $entityFactoryMock;
 
+    /**
+     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot
+     */
+    protected $entitySnapshotMock;
+
     protected function setUp()
     {
         $this->selectMock = $this->getMockBuilder('Magento\Framework\DB\Select')
@@ -81,6 +86,10 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
         $this->entityFactoryMock = $this->getMockBuilder('Magento\Framework\Data\Collection\EntityFactory')
             ->disableOriginalConstructor()
             ->getMock();
+        $this->entitySnapshotMock = $this->getMockBuilder('Magento\Framework\Model\Resource\Db\VersionControl\Snapshot')
+            ->disableOriginalConstructor()
+            ->setMethods(['registerSnapshot'])
+            ->getMock();
 
         $helper = new \Magento\Framework\TestFramework\Unit\Helper\ObjectManager($this);
         $this->model = $helper->getObject(
@@ -89,7 +98,8 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
                 'customerResource' => $this->customerResourceMock,
                 'resource' => $this->resourceMock,
                 'fetchStrategy' => $this->fetchStrategyMock,
-                'entityFactory' => $this->entityFactoryMock
+                'entityFactory' => $this->entityFactoryMock,
+                'entitySnapshot' => $this->entitySnapshotMock
             ]
         );
     }
@@ -154,7 +164,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
             ->withAnyParameters()
             ->willReturn($customerId);
 
-        $itemMock = $this->getMockBuilder('Magento\Framework\Object')
+        $itemMock = $this->getMockBuilder('Magento\Framework\Model\AbstractModel')
             ->disableOriginalConstructor()
             ->getMock();
         $itemMock->expects($this->once())
diff --git a/app/code/Magento/Sales/Model/AbstractModel.php b/app/code/Magento/Sales/Model/AbstractModel.php
index 9f409bcbd76bb2dfacf96116b06584e6c70d12b3..e018d84d95c2d6b3674ea63b5961d925b08d91e2 100644
--- a/app/code/Magento/Sales/Model/AbstractModel.php
+++ b/app/code/Magento/Sales/Model/AbstractModel.php
@@ -45,16 +45,6 @@ abstract class AbstractModel extends AbstractExtensibleModel
         );
     }
 
-    /**
-     * Returns _eventPrefix
-     *
-     * @return string
-     */
-    public function getEventPrefix()
-    {
-        return $this->_eventPrefix;
-    }
-
     /**
      * Returns _eventObject
      *
diff --git a/app/code/Magento/Sales/Model/Resource/Collection/AbstractCollection.php b/app/code/Magento/Sales/Model/Resource/Collection/AbstractCollection.php
index b0e4edf8dd32d65c367b71a823f16dca05c47219..d32dc6ee981c70f1d498d27d15ac04fb7f507d87 100644
--- a/app/code/Magento/Sales/Model/Resource/Collection/AbstractCollection.php
+++ b/app/code/Magento/Sales/Model/Resource/Collection/AbstractCollection.php
@@ -9,41 +9,13 @@ namespace Magento\Sales\Model\Resource\Collection;
  * Flat sales abstract collection
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
  */
-abstract class AbstractCollection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+abstract class AbstractCollection extends \Magento\Framework\Model\Resource\Db\VersionControl\Collection
 {
     /**
      * @var \Zend_Db_Select
      */
     protected $_countSelect;
 
-    /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot
-     */
-    protected $entitySnapshot;
-
-    /**
-     * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory
-     * @param \Psr\Log\LoggerInterface $logger
-     * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
-     * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot
-     * @param string|null $connection
-     * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
-     * @throws \Zend_Exception
-     */
-    public function __construct(
-        \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory,
-        \Psr\Log\LoggerInterface $logger,
-        \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
-        \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot,
-        $connection = null,
-        \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
-    ) {
-        $this->entitySnapshot = $entitySnapshot;
-        parent::__construct($entityFactory, $logger, $fetchStrategy, $eventManager, $connection, $resource);
-    }
-
     /**
      * Set select count sql
      *
@@ -233,63 +205,4 @@ abstract class AbstractCollection extends \Magento\Framework\Model\Resource\Db\C
     {
         return $this;
     }
-
-    /**
-     * Returns a collection item that corresponds to the fetched row
-     * and moves the internal data pointer ahead
-     * All returned rows marked as non changed to prevent unnecessary persistence operations
-     *
-     * @return  \Magento\Framework\Object|bool
-     */
-    public function fetchItem()
-    {
-        if (null === $this->_fetchStmt) {
-            $this->_renderOrders()->_renderLimit();
-
-            $this->_fetchStmt = $this->getConnection()->query($this->getSelect());
-        }
-        $data = $this->_fetchStmt->fetch();
-        if (!empty($data) && is_array($data)) {
-            /**@var \Magento\Sales\Model\AbstractModel $item */
-            $item = $this->getNewEmptyItem();
-            if ($this->getIdFieldName()) {
-                $item->setIdFieldName($this->getIdFieldName());
-            }
-            $item->setData($data);
-            $this->entitySnapshot->registerSnapshot($item);
-            return $item;
-        }
-        return false;
-    }
-
-    /**
-     * Load data with filter in place
-     * All returned rows marked as non changed to prevent unnecessary persistence operations
-     *
-     * @param   bool $printQuery
-     * @param   bool $logQuery
-     * @return  $this
-     */
-    public function loadWithFilter($printQuery = false, $logQuery = false)
-    {
-        $this->_beforeLoad();
-        $this->_renderFilters()->_renderOrders()->_renderLimit();
-        $this->printLogQuery($printQuery, $logQuery);
-        $data = $this->getData();
-        $this->resetData();
-        if (is_array($data)) {
-            foreach ($data as $row) {
-                $item = $this->getNewEmptyItem();
-                if ($this->getIdFieldName()) {
-                    $item->setIdFieldName($this->getIdFieldName());
-                }
-                $item->setData($row);
-                $this->entitySnapshot->registerSnapshot($item);
-                $this->addItem($item);
-            }
-        }
-        $this->_setIsLoaded();
-        $this->_afterLoad();
-        return $this;
-    }
 }
diff --git a/app/code/Magento/Sales/Model/Resource/EntityAbstract.php b/app/code/Magento/Sales/Model/Resource/EntityAbstract.php
index 44989d28a214cc6f2531e7313591ac3d9bf27d68..b095ebf88a3ae1d73b0e28d07b9eceabc06d3d3b 100644
--- a/app/code/Magento/Sales/Model/Resource/EntityAbstract.php
+++ b/app/code/Magento/Sales/Model/Resource/EntityAbstract.php
@@ -5,9 +5,11 @@
  */
 namespace Magento\Sales\Model\Resource;
 
-use Magento\Framework\Model\Resource\Db\AbstractDb;
-use Magento\Sales\Model\EntityInterface;
+use Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\SalesSequence\Model\Manager;
+use Magento\Sales\Model\EntityInterface;
 
 /**
  * Abstract sales entity provides to its children knowledge about eventPrefix and eventObject
@@ -47,46 +49,33 @@ abstract class EntityAbstract extends AbstractDb
      */
     protected $attribute;
 
-
     /**
      * @var Manager
      */
     protected $sequenceManager;
 
-    /**
-     * @var EntitySnapshot
-     */
-    protected $entitySnapshot;
-
-    /**
-     * @var EntityRelationComposite
-     */
-    protected $entityRelationComposite;
-
     /**
      * @param \Magento\Framework\Model\Resource\Db\Context $context
+     * @param Snapshot $entitySnapshot
+     * @param RelationComposite $entityRelationComposite
      * @param Attribute $attribute
      * @param Manager $sequenceManager
-     * @param EntitySnapshot $entitySnapshot
-     * @param EntityRelationComposite $entityRelationComposite
      * @param string $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        RelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Resource\Attribute $attribute,
         Manager $sequenceManager,
-        EntitySnapshot $entitySnapshot,
-        EntityRelationComposite $entityRelationComposite,
         $resourcePrefix = null
     ) {
         $this->attribute = $attribute;
         $this->sequenceManager = $sequenceManager;
-        $this->entitySnapshot = $entitySnapshot;
-        $this->entityRelationComposite = $entityRelationComposite;
         if ($resourcePrefix === null) {
             $resourcePrefix = 'sales';
         }
-        parent::__construct($context, $resourcePrefix);
+        parent::__construct($context, $entitySnapshot, $entityRelationComposite, $resourcePrefix);
     }
 
     /**
@@ -171,83 +160,39 @@ abstract class EntityAbstract extends AbstractDb
     }
 
     /**
-     * Perform actions after object delete
-     *
-     * @param \Magento\Framework\Model\AbstractModel $object
-     * @return $this
+     * @inheritdoc
      */
-    protected function _afterDelete(\Magento\Framework\Model\AbstractModel $object)
+    protected function updateObject(\Magento\Framework\Model\AbstractModel $object)
     {
-        parent::_afterDelete($object);
-        return $this;
+        $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $object->getId());
+        $data = $this->_prepareDataForSave($object);
+        unset($data[$this->getIdFieldName()]);
+        $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition);
     }
 
     /**
-     * Perform actions after object load, mark loaded data as data without changes
-     *
-     * @param \Magento\Framework\Model\AbstractModel|\Magento\Framework\Object $object
-     * @return $this
-     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     * @inheritdoc
      */
-    protected function _afterLoad(\Magento\Framework\Model\AbstractModel $object)
+    protected function saveNewObject(\Magento\Framework\Model\AbstractModel $object)
     {
-        $this->entitySnapshot->registerSnapshot($object);
-        return $this;
+        $bind = $this->_prepareDataForSave($object);
+        unset($bind[$this->getIdFieldName()]);
+        $this->_getWriteAdapter()->insert($this->getMainTable(), $bind);
+        $object->setId($this->_getWriteAdapter()->lastInsertId($this->getMainTable()));
+        if ($this->_useIsObjectNew) {
+            $object->isObjectNew(false);
+        }
     }
 
     /**
-     * Save entity
+     * Perform actions after object delete
      *
      * @param \Magento\Framework\Model\AbstractModel $object
      * @return $this
-     * @throws \Exception
      */
-    public function save(\Magento\Framework\Model\AbstractModel $object)
+    protected function _afterDelete(\Magento\Framework\Model\AbstractModel $object)
     {
-        if ($object->isDeleted()) {
-            return $this->delete($object);
-        }
-        if (!$this->entitySnapshot->isModified($object)) {
-            $this->entityRelationComposite->processRelations($object);
-            return $this;
-        }
-        $this->beginTransaction();
-
-        try {
-            $object->validateBeforeSave();
-            $object->beforeSave();
-            if ($object->isSaveAllowed()) {
-                $this->_serializeFields($object);
-                $this->_beforeSave($object);
-                $this->_checkUnique($object);
-                $this->objectRelationProcessor->validateDataIntegrity($this->getMainTable(), $object->getData());
-                if ($object->getId() !== null && (!$this->_useIsObjectNew || !$object->isObjectNew())) {
-                    $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $object->getId());
-                    $data = $this->_prepareDataForSave($object);
-                    unset($data[$this->getIdFieldName()]);
-                    $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition);
-                } else {
-                    $bind = $this->_prepareDataForSave($object);
-                    unset($bind[$this->getIdFieldName()]);
-                    $this->_getWriteAdapter()->insert($this->getMainTable(), $bind);
-                    $object->setId($this->_getWriteAdapter()->lastInsertId($this->getMainTable()));
-                    if ($this->_useIsObjectNew) {
-                        $object->isObjectNew(false);
-                    }
-                }
-                $this->unserializeFields($object);
-                $this->_afterSave($object);
-                $this->entitySnapshot->registerSnapshot($object);
-                $object->afterSave();
-                $this->entityRelationComposite->processRelations($object);
-            }
-            $this->addCommitCallback([$object, 'afterCommitCallback'])->commit();
-            $object->setHasDataChanges(false);
-        } catch (\Exception $e) {
-            $this->rollBack();
-            $object->setHasDataChanges(true);
-            throw $e;
-        }
+        parent::_afterDelete($object);
         return $this;
     }
 }
diff --git a/app/code/Magento/Sales/Model/Resource/EntityMetadata.php b/app/code/Magento/Sales/Model/Resource/EntityMetadata.php
deleted file mode 100644
index d39a9a63cb5ab9b25dd11321a01a4dbdbb8560ab..0000000000000000000000000000000000000000
--- a/app/code/Magento/Sales/Model/Resource/EntityMetadata.php
+++ /dev/null
@@ -1,37 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Sales\Model\Resource;
-
-use Magento\Sales\Model\AbstractModel;
-
-/**
- * Class EntityMetadata represents a list of entity fields that are applicable for persistence operations
- */
-class EntityMetadata
-{
-    /**
-     * @var array
-     */
-    protected $metadataInfo = [];
-
-    /**
-     * Returns list of entity fields that are applicable for persistence operations
-     *
-     * @param AbstractModel $entity
-     * @return array
-     * @throws \Magento\Framework\Exception\LocalizedException
-     */
-    public function getFields(AbstractModel $entity)
-    {
-        if (!isset($this->metadataInfo[get_class($entity)])) {
-            $this->metadataInfo[get_class($entity)] =
-                $entity->getResource()->getReadConnection()->describeTable(
-                    $entity->getResource()->getMainTable()
-                );
-        }
-        return $this->metadataInfo[get_class($entity)];
-    }
-}
diff --git a/app/code/Magento/Sales/Model/Resource/EntityRelationInterface.php b/app/code/Magento/Sales/Model/Resource/EntityRelationInterface.php
deleted file mode 100644
index 72d26e580e8dff1b8940b82ca4433c5cfa27e69f..0000000000000000000000000000000000000000
--- a/app/code/Magento/Sales/Model/Resource/EntityRelationInterface.php
+++ /dev/null
@@ -1,21 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-
-namespace Magento\Sales\Model\Resource;
-
-/**
- * Interface EntityRelationInterface
- */
-interface EntityRelationInterface
-{
-    /**
-     * Process object relations
-     *
-     * @param \Magento\Sales\Model\AbstractModel $object
-     * @return void
-     */
-    public function processRelation(\Magento\Sales\Model\AbstractModel $object);
-}
diff --git a/app/code/Magento/Sales/Model/Resource/EntitySnapshot.php b/app/code/Magento/Sales/Model/Resource/EntitySnapshot.php
deleted file mode 100644
index 47a008445ebf5f3807944a1115a39d5d72f86c87..0000000000000000000000000000000000000000
--- a/app/code/Magento/Sales/Model/Resource/EntitySnapshot.php
+++ /dev/null
@@ -1,70 +0,0 @@
-<?php
-/**
- * Copyright © 2015 Magento. All rights reserved.
- * See COPYING.txt for license details.
- */
-namespace Magento\Sales\Model\Resource;
-
-use Magento\Framework\Model\AbstractModel;
-
-/**
- * Class EntitySnapshot register snapshot of entity data, for tracking changes
- */
-class EntitySnapshot
-{
-    /**
-     * Array of snapshots of entities data
-     *
-     * @var array
-     */
-    protected $snapshotData = [];
-
-    /**
-     * @var EntityMetadata
-     */
-    protected $entityMetadata;
-
-    /**
-     * Initialization
-     *
-     * @param EntityMetadata $entityMetadata
-     */
-    public function __construct(
-        EntityMetadata $entityMetadata
-    ) {
-        $this->entityMetadata = $entityMetadata;
-    }
-
-    /**
-     * Register snapshot of entity data, for tracking changes
-     *
-     * @param AbstractModel $entity
-     * @return void
-     */
-    public function registerSnapshot(AbstractModel $entity)
-    {
-        $data = array_intersect_key($entity->getData(), $this->entityMetadata->getFields($entity));
-        $this->snapshotData[get_class($entity)][$entity->getId()] = $data;
-    }
-
-    /**
-     * Check is current entity has changes, by comparing current object state with stored snapshot
-     *
-     * @param AbstractModel $entity
-     * @return bool
-     */
-    public function isModified(AbstractModel $entity)
-    {
-        if (!$entity->getId()) {
-            return true;
-        }
-        if (!isset($this->snapshotData[get_class($entity)][$entity->getId()])) {
-            return true;
-        }
-        $data = array_intersect_key($entity->getData(), $this->entityMetadata->getFields($entity));
-        if ($data !== $this->snapshotData[get_class($entity)][$entity->getId()]) {
-            return true;
-        }
-        return false;
-    }
-}
diff --git a/app/code/Magento/Sales/Model/Resource/Order.php b/app/code/Magento/Sales/Model/Resource/Order.php
index 24b205c079d7266f3f010806d039466e25f2b25c..f44ca611da317a9068111add4782c16dec481591 100644
--- a/app/code/Magento/Sales/Model/Resource/Order.php
+++ b/app/code/Magento/Sales/Model/Resource/Order.php
@@ -11,6 +11,8 @@ use Magento\SalesSequence\Model\Manager;
 use Magento\Sales\Model\Resource\EntityAbstract as SalesResource;
 use Magento\Sales\Model\Resource\Order\Handler\State as StateHandler;
 use Magento\Sales\Model\Spi\OrderResourceInterface;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
 
 /**
  * Flat sales order resource
@@ -53,27 +55,27 @@ class Order extends SalesResource implements OrderResourceInterface
      * @param \Magento\Framework\Model\Resource\Db\Context $context
      * @param Attribute $attribute
      * @param Manager $sequenceManager
-     * @param EntitySnapshot $entitySnapshot
-     * @param EntityRelationComposite $entityRelationComposite
+     * @param Snapshot $entitySnapshot
+     * @param RelationComposite $entityRelationComposite
      * @param StateHandler $stateHandler
      * @param string $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        RelationComposite $entityRelationComposite,
         Attribute $attribute,
         Manager $sequenceManager,
-        EntitySnapshot $entitySnapshot,
-        EntityRelationComposite $entityRelationComposite,
         StateHandler $stateHandler,
         $resourcePrefix = null
     ) {
         $this->stateHandler = $stateHandler;
         parent::__construct(
             $context,
-            $attribute,
-            $sequenceManager,
             $entitySnapshot,
             $entityRelationComposite,
+            $attribute,
+            $sequenceManager,
             $resourcePrefix
         );
     }
@@ -138,8 +140,6 @@ class Order extends SalesResource implements OrderResourceInterface
      */
     protected function _beforeSave(\Magento\Framework\Model\AbstractModel $object)
     {
-        /** @var \Magento\Sales\Model\Order $object */
-        $this->stateHandler->check($object);
         if (!$object->getId()) {
             /** @var \Magento\Store\Model\Store $store */
             $store = $object->getStore();
@@ -161,4 +161,14 @@ class Order extends SalesResource implements OrderResourceInterface
         }
         return parent::_beforeSave($object);
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function save(\Magento\Framework\Model\AbstractModel $object)
+    {
+        /** @var \Magento\Sales\Model\Order $object */
+        $this->stateHandler->check($object);
+        return parent::save($object);
+    }
 }
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Address.php b/app/code/Magento/Sales/Model/Resource/Order/Address.php
index 878bfdf6a8ad9fd6bbf30f71642c3f6fe8bf64d1..760895576385ec3fd42c8598f2f34e9e590bba1a 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Address.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Address.php
@@ -7,7 +7,7 @@ namespace Magento\Sales\Model\Resource\Order;
 
 use Magento\Sales\Model\Resource\EntityAbstract as SalesResource;
 use Magento\Sales\Model\Spi\OrderAddressResourceInterface;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 
 /**
  * Flat sales order address resource
@@ -35,18 +35,18 @@ class Address extends SalesResource implements OrderAddressResourceInterface
      * @param \Magento\Framework\Model\Resource\Db\Context $context
      * @param \Magento\Sales\Model\Resource\Attribute $attribute
      * @param \Magento\SalesSequence\Model\Manager $sequenceManager
-     * @param EntitySnapshot $entitySnapshot
-     * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite
+     * @param Snapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite
      * @param \Magento\Sales\Model\Order\Address\Validator $validator
      * @param \Magento\Sales\Model\Resource\GridPool $gridPool
      * @param string $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Resource\Attribute $attribute,
         \Magento\SalesSequence\Model\Manager $sequenceManager,
-        EntitySnapshot $entitySnapshot,
-        \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Order\Address\Validator $validator,
         \Magento\Sales\Model\Resource\GridPool $gridPool,
         $resourcePrefix = null
@@ -55,10 +55,10 @@ class Address extends SalesResource implements OrderAddressResourceInterface
         $this->gridPool = $gridPool;
         parent::__construct(
             $context,
-            $attribute,
-            $sequenceManager,
             $entitySnapshot,
             $entityRelationComposite,
+            $attribute,
+            $sequenceManager,
             $resourcePrefix
         );
     }
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Collection.php
index 4254242321fa2c11b6bf60fb819bc2c74a6ce615..2e68417ba67ee7523c848d233c6634f4101d51b8 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Collection.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Collection.php
@@ -39,7 +39,7 @@ class Collection extends AbstractCollection implements OrderSearchResultInterfac
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Framework\DB\Helper $coreResourceHelper
      * @param string|null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
@@ -49,7 +49,7 @@ class Collection extends AbstractCollection implements OrderSearchResultInterfac
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Framework\DB\Helper $coreResourceHelper,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo.php b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo.php
index f0a5c4d693428efed1a537f29db22df1af9758cb..255d4cd4388f1c67652a252c1737b57bd23f6890 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo.php
@@ -9,7 +9,7 @@ use Magento\Framework\App\Resource as AppResource;
 use Magento\SalesSequence\Model\Manager;
 use Magento\Sales\Model\Resource\Attribute;
 use Magento\Sales\Model\Resource\EntityAbstract as SalesResource;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Sales\Model\Spi\CreditmemoResourceInterface;
 
 /**
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Comment.php b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Comment.php
index 3056759346691ebb39edfbd90f0cbb5adb160382..304677688895668a68a1650f1a24ef9dbec0bfdd 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Comment.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Comment.php
@@ -6,7 +6,7 @@
 namespace Magento\Sales\Model\Resource\Order\Creditmemo;
 
 use Magento\Sales\Model\Resource\EntityAbstract;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Sales\Model\Spi\CreditmemoCommentResourceInterface;
 
 /**
@@ -34,27 +34,27 @@ class Comment extends EntityAbstract implements CreditmemoCommentResourceInterfa
      * @param \Magento\Framework\Model\Resource\Db\Context $context
      * @param \Magento\Sales\Model\Resource\Attribute $attribute
      * @param \Magento\SalesSequence\Model\Manager $sequenceManager
-     * @param EntitySnapshot $entitySnapshot
-     * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite
+     * @param Snapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite
      * @param \Magento\Sales\Model\Order\Creditmemo\Comment\Validator $validator
      * @param string $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Resource\Attribute $attribute,
         \Magento\SalesSequence\Model\Manager $sequenceManager,
-        EntitySnapshot $entitySnapshot,
-        \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Order\Creditmemo\Comment\Validator $validator,
         $resourcePrefix = null
     ) {
         $this->validator = $validator;
         parent::__construct(
             $context,
-            $attribute,
-            $sequenceManager,
             $entitySnapshot,
             $entityRelationComposite,
+            $attribute,
+            $sequenceManager,
             $resourcePrefix
         );
     }
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Order/Grid/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Order/Grid/Collection.php
index 85eeb520f00038005fc02d39303e096723775948..c24cfddac98ab0f1e998c390ed099e04a8518234 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Order/Grid/Collection.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Order/Grid/Collection.php
@@ -23,7 +23,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Creditmemo\Grid\Col
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
      * @param \Magento\Framework\Registry $registryManager
-     * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
      */
@@ -32,7 +32,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Creditmemo\Grid\Col
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Framework\Registry $registryManager,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Relation.php b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Relation.php
index 674e9552b7ae54cc956fa539c09ed3fef49e1933..6aabb91138517a7696271fc16063a1fea8876789 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Relation.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Creditmemo/Relation.php
@@ -6,12 +6,12 @@
 
 namespace Magento\Sales\Model\Resource\Order\Creditmemo;
 
-use Magento\Sales\Model\Resource\EntityRelationInterface;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface;
 
 /**
  * Class Relation
  */
-class Relation implements EntityRelationInterface
+class Relation implements RelationInterface
 {
     /**
      * @var Item
@@ -38,11 +38,11 @@ class Relation implements EntityRelationInterface
     /**
      * Process relations for CreditMemo
      *
-     * @param \Magento\Sales\Model\AbstractModel $object
+     * @param \Magento\Framework\Model\AbstractModel $object
      * @throws \Exception
      * @return void
      */
-    public function processRelation(\Magento\Sales\Model\AbstractModel $object)
+    public function processRelation(\Magento\Framework\Model\AbstractModel $object)
     {
         /** @var \Magento\Sales\Model\Order\Creditmemo $object */
         if (null !== $object->getItems()) {
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Invoice.php b/app/code/Magento/Sales/Model/Resource/Order/Invoice.php
index 6fb7504394cf8f3c813089146dbeb577b19cb448..33a095ce60c66d85b5ff05d8e4c4c8ec4568f7ed 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Invoice.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Invoice.php
@@ -9,7 +9,7 @@ use Magento\Framework\App\Resource;
 use Magento\SalesSequence\Model\Manager;
 use Magento\Sales\Model\Resource\Attribute;
 use Magento\Sales\Model\Resource\EntityAbstract as SalesResource;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Sales\Model\Spi\InvoiceResourceInterface;
 
 /**
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Comment.php b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Comment.php
index f54208f1e5d5d11edc3ea35408223a2423752ea0..ad15a0a99dfd38d804ad68c407a63726512d4d75 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Comment.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Comment.php
@@ -6,7 +6,7 @@
 namespace Magento\Sales\Model\Resource\Order\Invoice;
 
 use Magento\Sales\Model\Resource\EntityAbstract;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Sales\Model\Spi\InvoiceCommentResourceInterface;
 
 /**
@@ -34,27 +34,27 @@ class Comment extends EntityAbstract implements InvoiceCommentResourceInterface
      * @param \Magento\Framework\Model\Resource\Db\Context $context
      * @param \Magento\Sales\Model\Resource\Attribute $attribute
      * @param \Magento\SalesSequence\Model\Manager $sequenceManager
-     * @param EntitySnapshot $entitySnapshot
-     * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite
+     * @param Snapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite
      * @param \Magento\Sales\Model\Order\Invoice\Comment\Validator $validator
      * @param string $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Resource\Attribute $attribute,
         \Magento\SalesSequence\Model\Manager $sequenceManager,
-        EntitySnapshot $entitySnapshot,
-        \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Order\Invoice\Comment\Validator $validator,
         $resourcePrefix = null
     ) {
         $this->validator = $validator;
         parent::__construct(
             $context,
-            $attribute,
-            $sequenceManager,
             $entitySnapshot,
             $entityRelationComposite,
+            $attribute,
+            $sequenceManager,
             $resourcePrefix
         );
     }
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Orders/Grid/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Orders/Grid/Collection.php
index 6f6d71c655ebb10c595db011e3f5777c6e1a1754..2a79e1c08d2575123511f230b5270453baec11da 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Orders/Grid/Collection.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Orders/Grid/Collection.php
@@ -17,7 +17,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Invoice\Grid\Collec
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Framework\Registry $registryManager
      * @param null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
@@ -27,7 +27,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Invoice\Grid\Collec
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Framework\Registry $registryManager,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Relation.php b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Relation.php
index 80f10e6adbaad2b6d2a61cdbfd17d9f2223ca2ec..b2da74d1d74333752376e0e0df64f2f99ad75a24 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Invoice/Relation.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Invoice/Relation.php
@@ -6,14 +6,14 @@
 
 namespace Magento\Sales\Model\Resource\Order\Invoice;
 
-use Magento\Sales\Model\Resource\EntityRelationInterface;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface;
 use Magento\Sales\Model\Resource\Order\Invoice\Item as InvoiceItemResource;
 use Magento\Sales\Model\Resource\Order\Invoice\Comment as InvoiceCommentResource;
 
 /**
  * Class Relation
  */
-class Relation implements EntityRelationInterface
+class Relation implements RelationInterface
 {
     /**
      * @var InvoiceItemResource
@@ -40,11 +40,11 @@ class Relation implements EntityRelationInterface
     /**
      * Process relations for Shipment
      *
-     * @param \Magento\Sales\Model\AbstractModel $object
+     * @param \Magento\Framework\Model\AbstractModel $object
      * @return void
      * @throws \Exception
      */
-    public function processRelation(\Magento\Sales\Model\AbstractModel $object)
+    public function processRelation(\Magento\Framework\Model\AbstractModel $object)
     {
         /** @var $object \Magento\Sales\Model\Order\Invoice */
         if (null !== $object->getItems()) {
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Payment/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Payment/Collection.php
index 8f73ee346165a646e8e8939bcdae16d6d64256b4..284dd3dc81937a4b7da960ff0a90abb074481e4b 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Payment/Collection.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Payment/Collection.php
@@ -32,7 +32,7 @@ class Collection extends AbstractCollection implements OrderPaymentSearchResultI
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
      */
@@ -41,7 +41,7 @@ class Collection extends AbstractCollection implements OrderPaymentSearchResultI
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
     ) {
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Relation.php b/app/code/Magento/Sales/Model/Resource/Order/Relation.php
index 749de294fe06d4057c2a990d875821bc5e45840c..f832d285383280a67360c2ea6e28066beac0e6b9 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Relation.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Relation.php
@@ -6,9 +6,8 @@
 
 namespace Magento\Sales\Model\Resource\Order;
 
-use Magento\Sales\Model\AbstractModel;
 use Magento\Sales\Model\Resource\Order\Handler\Address as AddressHandler;
-use Magento\Sales\Model\Resource\EntityRelationInterface;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface;
 use Magento\Sales\Model\Resource\Order\Item as OrderItemResource;
 use Magento\Sales\Model\Resource\Order\Payment as OrderPaymentResource;
 use Magento\Sales\Model\Resource\Order\Status\History as OrderStatusHistoryResource;
@@ -16,7 +15,7 @@ use Magento\Sales\Model\Resource\Order\Status\History as OrderStatusHistoryResou
 /**
  * Class Relation
  */
-class Relation implements EntityRelationInterface
+class Relation implements RelationInterface
 {
     /**
      * @var AddressHandler
@@ -59,11 +58,11 @@ class Relation implements EntityRelationInterface
     /**
      * Save relations for Order
      *
-     * @param AbstractModel $object
+     * @param \Magento\Framework\Model\AbstractModel $object
      * @return void
      * @throws \Exception
      */
-    public function processRelation(AbstractModel $object)
+    public function processRelation(\Magento\Framework\Model\AbstractModel $object)
     {
         /** @var \Magento\Sales\Model\Order $object */
         $this->addressHandler->removeEmptyAddresses($object);
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment.php
index 8fe7b8afa972e655edfcaed864336d697ef0791f..32293e81802cc33e1a738ce2acd867b88117d82b 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Shipment.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment.php
@@ -9,7 +9,7 @@ use Magento\Framework\App\Resource as AppResource;
 use Magento\SalesSequence\Model\Manager;
 use Magento\Sales\Model\Resource\Attribute;
 use Magento\Sales\Model\Resource\EntityAbstract as SalesResource;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Sales\Model\Resource\Order\Shipment\Grid as ShipmentGrid;
 use Magento\Sales\Model\Spi\ShipmentResourceInterface;
 
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Comment.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Comment.php
index 0379873ee76fb01c21ce4b02d95cec43c174406d..f77505a9fe208524ac4ffe094226b3f528ecf1cd 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Comment.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Comment.php
@@ -6,7 +6,7 @@
 namespace Magento\Sales\Model\Resource\Order\Shipment;
 
 use Magento\Sales\Model\Resource\EntityAbstract;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Sales\Model\Spi\ShipmentCommentResourceInterface;
 
 /**
@@ -34,27 +34,27 @@ class Comment extends EntityAbstract implements ShipmentCommentResourceInterface
      * @param \Magento\Framework\Model\Resource\Db\Context $context
      * @param \Magento\Sales\Model\Resource\Attribute $attribute
      * @param \Magento\SalesSequence\Model\Manager $sequenceManager
-     * @param EntitySnapshot $entitySnapshot
-     * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite
+     * @param Snapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite
      * @param \Magento\Sales\Model\Order\Shipment\Comment\Validator $validator
      * @param string $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Resource\Attribute $attribute,
         \Magento\SalesSequence\Model\Manager $sequenceManager,
-        EntitySnapshot $entitySnapshot,
-        \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Order\Shipment\Comment\Validator $validator,
         $resourcePrefix = null
     ) {
         $this->validator = $validator;
         parent::__construct(
             $context,
-            $attribute,
-            $sequenceManager,
             $entitySnapshot,
             $entityRelationComposite,
+            $attribute,
+            $sequenceManager,
             $resourcePrefix
         );
     }
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Order/Grid/Collection.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Order/Grid/Collection.php
index ae31f67f65deb94365871772b991d45ebcebf9f0..d61ea0fbd7c82fb0455ffe6d5c502be45f0a4afe 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Order/Grid/Collection.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Order/Grid/Collection.php
@@ -22,7 +22,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Shipment\Grid\Colle
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Framework\Registry $registryManager
      * @param null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
@@ -32,7 +32,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Shipment\Grid\Colle
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Framework\Registry $registryManager,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Relation.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Relation.php
index 8d25d48c40e2195d5dcb1c14e82c3b1e050eba28..32efe9ad52732e700ddb73b33e6968e75c7a7f4a 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Relation.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Relation.php
@@ -6,7 +6,7 @@
 
 namespace Magento\Sales\Model\Resource\Order\Shipment;
 
-use Magento\Sales\Model\Resource\EntityRelationInterface;
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface;
 use Magento\Sales\Model\Resource\Order\Shipment\Item as ShipmentItemResource;
 use Magento\Sales\Model\Resource\Order\Shipment\Comment as ShipmentCommentResource;
 use Magento\Sales\Model\Resource\Order\Shipment\Track as ShipmentTrackResource;
@@ -14,7 +14,7 @@ use Magento\Sales\Model\Resource\Order\Shipment\Track as ShipmentTrackResource;
 /**
  * Class Relation
  */
-class Relation implements EntityRelationInterface
+class Relation implements RelationInterface
 {
     /**
      * @var ShipmentItemResource
@@ -49,11 +49,11 @@ class Relation implements EntityRelationInterface
     /**
      * Process relations for Shipment
      *
-     * @param \Magento\Sales\Model\AbstractModel $object
+     * @param \Magento\Framework\Model\AbstractModel $object
      * @return void
      * @throws \Exception
      */
-    public function processRelation(\Magento\Sales\Model\AbstractModel $object)
+    public function processRelation(\Magento\Framework\Model\AbstractModel $object)
     {
         /** @var \Magento\Sales\Model\Order\Shipment $object */
         if (null !== $object->getItems()) {
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Track.php b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Track.php
index 07dfa2beb992ecc46df47024df476e44e5ab70bd..6db8bf2ee10496a2716e0cbd707dc46b5d040911 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Shipment/Track.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Shipment/Track.php
@@ -6,7 +6,7 @@
 namespace Magento\Sales\Model\Resource\Order\Shipment;
 
 use Magento\Sales\Model\Resource\EntityAbstract as SalesResource;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Sales\Model\Spi\ShipmentTrackResourceInterface;
 
 /**
@@ -34,27 +34,27 @@ class Track extends SalesResource implements ShipmentTrackResourceInterface
      * @param \Magento\Framework\Model\Resource\Db\Context $context
      * @param \Magento\Sales\Model\Resource\Attribute $attribute
      * @param \Magento\SalesSequence\Model\Manager $sequenceManager
-     * @param EntitySnapshot $entitySnapshot
-     * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite
+     * @param Snapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite
      * @param \Magento\Sales\Model\Order\Shipment\Track\Validator $validator
      * @param string $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Resource\Attribute $attribute,
         \Magento\SalesSequence\Model\Manager $sequenceManager,
-        EntitySnapshot $entitySnapshot,
-        \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Order\Shipment\Track\Validator $validator,
         $resourcePrefix = null
     ) {
         $this->validator = $validator;
         parent::__construct(
             $context,
-            $attribute,
-            $sequenceManager,
             $entitySnapshot,
             $entityRelationComposite,
+            $attribute,
+            $sequenceManager,
             $resourcePrefix
         );
     }
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Status.php b/app/code/Magento/Sales/Model/Resource/Order/Status.php
index 6ebf0702bb9eb87d96a082a47c702619052edcfc..b28a95f490823a288fb89a33ee0eb5d045e33b51 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Status.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Status.php
@@ -10,14 +10,14 @@ use Psr\Log\LoggerInterface as LogWriter;
 use Magento\Framework\Exception\LocalizedException;
 use Magento\SalesSequence\Model\Manager;
 use \Magento\Sales\Model\Resource\EntityAbstract;
-use \Magento\Sales\Model\Resource\EntitySnapshot;
+use \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 
 /**
  * Order status resource model
  *
  * @author      Magento Core Team <core@magentocommerce.com>
  */
-class Status extends \Magento\Framework\Model\Resource\Db\AbstractDb
+class Status extends \Magento\Framework\Model\Resource\Db\VersionControl\AbstractDb
 {
     /**
      * Status labels table
diff --git a/app/code/Magento/Sales/Model/Resource/Order/Status/History.php b/app/code/Magento/Sales/Model/Resource/Order/Status/History.php
index 8c13fdef8880954947e7c6c6f26f0d7b98b6cc22..2dbf7cc79946d97159b0dc71f069007f353196c7 100644
--- a/app/code/Magento/Sales/Model/Resource/Order/Status/History.php
+++ b/app/code/Magento/Sales/Model/Resource/Order/Status/History.php
@@ -7,7 +7,7 @@ namespace Magento\Sales\Model\Resource\Order\Status;
 
 use Magento\Sales\Model\Order\Status\History\Validator;
 use Magento\Sales\Model\Resource\EntityAbstract;
-use Magento\Sales\Model\Resource\EntitySnapshot;
+use Magento\Framework\Model\Resource\Db\VersionControl\Snapshot;
 use Magento\Sales\Model\Spi\OrderStatusHistoryResourceInterface;
 
 /**
@@ -26,27 +26,27 @@ class History extends EntityAbstract implements OrderStatusHistoryResourceInterf
      * @param \Magento\Framework\Model\Resource\Db\Context $context
      * @param \Magento\Sales\Model\Resource\Attribute $attribute
      * @param \Magento\SalesSequence\Model\Manager $sequenceManager
-     * @param EntitySnapshot $entitySnapshot
-     * @param \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite
+     * @param Snapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite
      * @param Validator $validator
      * @param string $resourcePrefix
      */
     public function __construct(
         \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite $entityRelationComposite,
         \Magento\Sales\Model\Resource\Attribute $attribute,
         \Magento\SalesSequence\Model\Manager $sequenceManager,
-        EntitySnapshot $entitySnapshot,
-        \Magento\Sales\Model\Resource\EntityRelationComposite $entityRelationComposite,
         Validator $validator,
         $resourcePrefix = null
     ) {
         $this->validator = $validator;
         parent::__construct(
             $context,
-            $attribute,
-            $sequenceManager,
             $entitySnapshot,
             $entityRelationComposite,
+            $attribute,
+            $sequenceManager,
             $resourcePrefix
         );
     }
diff --git a/app/code/Magento/Sales/Model/Resource/Transaction/Grid/Collection.php b/app/code/Magento/Sales/Model/Resource/Transaction/Grid/Collection.php
index 9bd3c5d4aac539ad12d462d2d4c3100be3328703..f58c41554af1cde9e63f7597945889fd9313aebd 100644
--- a/app/code/Magento/Sales/Model/Resource/Transaction/Grid/Collection.php
+++ b/app/code/Magento/Sales/Model/Resource/Transaction/Grid/Collection.php
@@ -20,7 +20,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Payment\Transaction
      * @param \Psr\Log\LoggerInterface $logger
      * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
      * @param \Magento\Framework\Event\ManagerInterface $eventManager
-     * @param \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot
+     * @param \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot
      * @param \Magento\Framework\Registry $registryManager
      * @param null $connection
      * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
@@ -30,7 +30,7 @@ class Collection extends \Magento\Sales\Model\Resource\Order\Payment\Transaction
         \Psr\Log\LoggerInterface $logger,
         \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
         \Magento\Framework\Event\ManagerInterface $eventManager,
-        \Magento\Sales\Model\Resource\EntitySnapshot $entitySnapshot,
+        \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot $entitySnapshot,
         \Magento\Framework\Registry $registryManager,
         $connection = null,
         \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/AddressTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/AddressTest.php
index 85d167520a3bbdff1809a69a82a284f79c76be32..fd9d023735b57c1bcdccb2f6d4b1deba2829b12f 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/AddressTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/AddressTest.php
@@ -46,7 +46,7 @@ class AddressTest extends \PHPUnit_Framework_TestCase
     protected $gridPoolMock;
 
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $entitySnapshotMock;
 
@@ -95,7 +95,7 @@ class AddressTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->entitySnapshotMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
             [],
             [],
             '',
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Creditmemo/CommentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Creditmemo/CommentTest.php
index cb90e1429574daec837ab14470e58f5685eb192f..f5f43992bf9bfbd7ec5ab2cb15b7dd15edeab04b 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Creditmemo/CommentTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Creditmemo/CommentTest.php
@@ -35,7 +35,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase
      */
     protected $validatorMock;
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $entitySnapshotMock;
 
@@ -73,7 +73,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->entitySnapshotMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
             [],
             [],
             '',
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Invoice/CommentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Invoice/CommentTest.php
index 307b36d867efaf5e2d92b2b1c2bd54fb00147493..5348b94492ff3539e979d7ba852719aad2c52407 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Invoice/CommentTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Invoice/CommentTest.php
@@ -35,7 +35,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase
      */
     protected $validatorMock;
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $entitySnapshotMock;
 
@@ -73,7 +73,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->entitySnapshotMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
             [],
             [],
             '',
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/CommentTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/CommentTest.php
index bc6d3793a0621a69cc068d564fb0c267c1bdee8c..d397e2d7b79c109b19f2932c51c5905a48ba8e4f 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/CommentTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/CommentTest.php
@@ -35,7 +35,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase
      */
     protected $validatorMock;
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $entitySnapshotMock;
 
@@ -73,7 +73,7 @@ class CommentTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->entitySnapshotMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
             [],
             [],
             '',
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/TrackTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/TrackTest.php
index d9c4b184b6c3812fa386c4489fc7e13f4504f55d..6a10d12526840f0147931793c476602254b646f4 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/TrackTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Shipment/TrackTest.php
@@ -35,7 +35,7 @@ class TrackTest extends \PHPUnit_Framework_TestCase
      */
     protected $validatorMock;
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $entitySnapshotMock;
 
@@ -73,7 +73,7 @@ class TrackTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->entitySnapshotMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
             [],
             [],
             '',
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/History/CollectionTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/History/CollectionTest.php
index 7d0dc3b50ec512812807269d2ef8ae59763f95a1..e3222511a2389b3cd7fe4d56621ca4d346d16c0f 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/History/CollectionTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/History/CollectionTest.php
@@ -48,7 +48,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
      */
     protected $entityFactoryMock;
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $entitySnapshotMock;
 
@@ -59,7 +59,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
         $this->selectMock = $this->getMock('Zend_Db_Select', [], [], '', false);
         $this->historyItemMock = $this->getMock(
             'Magento\Sales\Model\Order\Status\History',
-            ['__wakeup', 'setData'],
+            ['__wakeup', 'addData'],
             [],
             '',
             false
@@ -74,7 +74,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
             ['getReadConnection', 'getMainTable', 'getTable', '__wakeup']
         );
         $this->entitySnapshotMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
             [],
             [],
             '',
@@ -97,7 +97,7 @@ class CollectionTest extends \PHPUnit_Framework_TestCase
 
         $data = [['data']];
         $this->historyItemMock->expects($this->once())
-            ->method('setData')
+            ->method('addData')
             ->with($this->equalTo($data[0]))
             ->will($this->returnValue($this->historyItemMock));
 
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/HistoryTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/HistoryTest.php
index eced486c174c08fccd775c5540d6f16a6b34c624..0dfcf1e512a5ad94cc26535d148777901b1a42b5 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/HistoryTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/Order/Status/HistoryTest.php
@@ -37,7 +37,7 @@ class HistoryTest extends \PHPUnit_Framework_TestCase
     protected $validatorMock;
 
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $entitySnapshotMock;
 
@@ -65,7 +65,7 @@ class HistoryTest extends \PHPUnit_Framework_TestCase
             false
         );
         $this->entitySnapshotMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
             [],
             [],
             '',
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/OrderTest.php b/app/code/Magento/Sales/Test/Unit/Model/Resource/OrderTest.php
index 397e6b0374502cd78ccc7084e3ac7ddc8fd20dfa..647427af5956808ff1eb5505bf46ceadb7d1b23d 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/OrderTest.php
+++ b/app/code/Magento/Sales/Test/Unit/Model/Resource/OrderTest.php
@@ -5,6 +5,7 @@
  */
 namespace Magento\Sales\Test\Unit\Model\Resource;
 
+use Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite;
 use \Magento\Sales\Model\Resource\Order;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
@@ -50,12 +51,12 @@ class OrderTest extends \PHPUnit_Framework_TestCase
      */
     protected $adapterMock;
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $entitySnapshotMock;
 
     /**
-     * @var \Magento\Sales\Model\Resource\EntityRelationComposite|\PHPUnit_Framework_MockObject_MockObject
+     * @var RelationComposite|\PHPUnit_Framework_MockObject_MockObject
      */
     protected $relationCompositeMock;
 
@@ -97,14 +98,14 @@ class OrderTest extends \PHPUnit_Framework_TestCase
         );
         $this->salesSequenceMock = $this->getMock('Magento\SalesSequence\Model\Sequence', [], [], '', false);
         $this->entitySnapshotMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
             [],
             [],
             '',
             false
         );
         $this->relationCompositeMock = $this->getMock(
-            'Magento\Sales\Model\Resource\EntityRelationComposite',
+            'Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite',
             [],
             [],
             '',
diff --git a/app/code/Magento/Sales/etc/di.xml b/app/code/Magento/Sales/etc/di.xml
index c0aec4a0857a24fdc363ad679fc38b3a44bc7408..28ea25b9dcf30f4db415e56c8f90753867ff14be 100644
--- a/app/code/Magento/Sales/etc/di.xml
+++ b/app/code/Magento/Sales/etc/di.xml
@@ -220,7 +220,7 @@
             <argument name="resourcePrefix" xsi:type="string">sales</argument>
         </arguments>
     </type>
-    <virtualType name="OrderRelationsComposite" type="Magento\Sales\Model\Resource\EntityRelationComposite">
+    <virtualType name="OrderRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite">
         <arguments>
             <argument name="relationProcessors" xsi:type="array">
                 <item name="default" xsi:type="object">Magento\Sales\Model\Resource\Order\Relation</item>
@@ -232,7 +232,7 @@
             <argument name="entityRelationComposite" xsi:type="object">OrderRelationsComposite</argument>
         </arguments>
     </type>
-    <virtualType name="InvoiceRelationsComposite" type="Magento\Sales\Model\Resource\EntityRelationComposite">
+    <virtualType name="InvoiceRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite">
         <arguments>
             <argument name="relationProcessors" xsi:type="array">
                 <item name="default" xsi:type="object">Magento\Sales\Model\Resource\Order\Invoice\Relation</item>
@@ -244,7 +244,7 @@
             <argument name="entityRelationComposite" xsi:type="object">InvoiceRelationsComposite</argument>
         </arguments>
     </type>
-    <virtualType name="ShipmentRelationsComposite" type="Magento\Sales\Model\Resource\EntityRelationComposite">
+    <virtualType name="ShipmentRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite">
         <arguments>
             <argument name="relationProcessors" xsi:type="array">
                 <item name="default" xsi:type="object">Magento\Sales\Model\Resource\Order\Shipment\Relation</item>
@@ -256,7 +256,7 @@
             <argument name="entityRelationComposite" xsi:type="object">ShipmentRelationsComposite</argument>
         </arguments>
     </type>
-    <virtualType name="CreditmemoRelationsComposite" type="Magento\Sales\Model\Resource\EntityRelationComposite">
+    <virtualType name="CreditmemoRelationsComposite" type="Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite">
         <arguments>
             <argument name="relationProcessors" xsi:type="array">
                 <item name="default" xsi:type="object">Magento\Sales\Model\Resource\Order\Creditmemo\Relation</item>
diff --git a/app/code/Magento/Sales/view/adminhtml/templates/order/details.phtml b/app/code/Magento/Sales/view/adminhtml/templates/order/details.phtml
index 196c1d42977c1482a4793ee9fe3c320e63983286..8a4bc2971760994b04dbf9b18b4ff0a804d89130 100644
--- a/app/code/Magento/Sales/view/adminhtml/templates/order/details.phtml
+++ b/app/code/Magento/Sales/view/adminhtml/templates/order/details.phtml
@@ -14,8 +14,8 @@ store name = $_order->getStore()->getGroup()->getName()
 ?>
 <?php $_order = $block->getOrder() ?>
 <div>
-<?php echo __('Customer Name: %1', $_order->getCustomerFirstname() ? $_order->getCustomerName() : $_order->getBillingAddress()->getName()) ?><br />
-<?php echo __('Purchased From: %1', $_order->getStore()->getGroup()->getName()) ?><br />
+<?php echo __('Customer Name: %1', $block->escapeHtml($_order->getCustomerFirstname() ? $_order->getCustomerName() : $_order->getBillingAddress()->getName())) ?><br />
+<?php echo __('Purchased From: %1', $block->escapeHtml($_order->getStore()->getGroup()->getName())) ?><br />
 </div>
 <table cellpadding="0" border="0" width="100%" style="border:1px solid #bebcb7; background:#f8f7f5;">
     <thead>
diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address.php
index cf8a02f20f8489eebb0a4d52c3b9e4172e274bff..becd0114cd30e313f035823e5c7d42b49db79338 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_address.php
@@ -5,9 +5,11 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+
 /** @var \Magento\Customer\Model\Address $customerAddress */
 $customerAddress = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
     ->create('Magento\Customer\Model\Address');
+
 $customerAddress->isObjectNew(true);
 $customerAddress->setData(
     [
diff --git a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_two_addresses.php b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_two_addresses.php
index b715451581bf1796b04556498e444ae0a1503267..72b4ffaa01c12d3e2d6dc1166c9f38ed5556bac3 100644
--- a/dev/tests/integration/testsuite/Magento/Customer/_files/customer_two_addresses.php
+++ b/dev/tests/integration/testsuite/Magento/Customer/_files/customer_two_addresses.php
@@ -11,6 +11,7 @@ require 'customer_address.php';
 /** @var \Magento\Customer\Model\Address $customerAddress */
 $customerAddress = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()
     ->create('Magento\Customer\Model\Address');
+
 $customerAddress->isObjectNew(true);
 $customerAddress->setData(
     [
diff --git a/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php b/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php
index 3573fdb87f541e900636e9ed6d921649e35fedc7..737a51721f8a75798c56ec4fd6547afed332e3cc 100755
--- a/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php
+++ b/lib/internal/Magento/Framework/Data/Collection/AbstractDb.php
@@ -577,6 +577,7 @@ abstract class AbstractDb extends \Magento\Framework\Data\Collection
                     $item->setIdFieldName($this->getIdFieldName());
                 }
                 $item->addData($row);
+                $this->beforeAddLoadedItem($item);
                 $this->addItem($item);
             }
         }
@@ -585,6 +586,17 @@ abstract class AbstractDb extends \Magento\Framework\Data\Collection
         return $this;
     }
 
+    /**
+     * Let do something before add loaded item in collection
+     *
+     * @param \Magento\Framework\Object $item
+     * @return \Magento\Framework\Object
+     */
+    protected function beforeAddLoadedItem(\Magento\Framework\Object $item)
+    {
+        return $item;
+    }
+
     /**
      * Returns a collection item that corresponds to the fetched row
      * and moves the internal data pointer ahead
diff --git a/lib/internal/Magento/Framework/Model/AbstractModel.php b/lib/internal/Magento/Framework/Model/AbstractModel.php
index 1c702229061d364526c8e48def6afc36be4b1227..72f6357f06c9fd8a59a3afdb75da20bb7219efe9 100644
--- a/lib/internal/Magento/Framework/Model/AbstractModel.php
+++ b/lib/internal/Magento/Framework/Model/AbstractModel.php
@@ -3,7 +3,6 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-
 namespace Magento\Framework\Model;
 
 use Magento\Framework\Phrase;
@@ -937,4 +936,14 @@ abstract class AbstractModel extends \Magento\Framework\Object
     {
         return $this->storedData;
     }
+
+    /**
+     * Returns _eventPrefix
+     *
+     * @return string
+     */
+    public function getEventPrefix()
+    {
+        return $this->_eventPrefix;
+    }
 }
diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php b/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php
index 87732d71a0f068818c993fd836d8baa8bb9d9d3a..824b0d5128a8d3329b0a85037d00cd4cf5b1bd6b 100644
--- a/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php
+++ b/lib/internal/Magento/Framework/Model/Resource/Db/AbstractDb.php
@@ -13,6 +13,7 @@ use Magento\Framework\Exception\LocalizedException;
  * Abstract resource model class
  * @SuppressWarnings(PHPMD.NumberOfChildren)
  * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
+ * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
  */
 abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractResource
 {
@@ -394,6 +395,7 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso
      * @param \Magento\Framework\Model\AbstractModel $object
      * @return $this
      * @SuppressWarnings(PHPMD.CyclomaticComplexity)
+     * @throws \Exception
      * @api
      */
     public function save(\Magento\Framework\Model\AbstractModel $object)
@@ -401,13 +403,16 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso
         if ($object->isDeleted()) {
             return $this->delete($object);
         }
-        if (!$object->hasDataChanges()) {
-            return $this;
-        }
 
         $this->beginTransaction();
 
         try {
+            if (!$this->isModified($object)) {
+                $this->processNotModifiedSave($object);
+                $this->commit();
+                $object->setHasDataChanges(false);
+                return $this;
+            }
             $object->validateBeforeSave();
             $object->beforeSave();
             if ($object->isSaveAllowed()) {
@@ -415,53 +420,13 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso
                 $this->_beforeSave($object);
                 $this->_checkUnique($object);
                 $this->objectRelationProcessor->validateDataIntegrity($this->getMainTable(), $object->getData());
-                if ($object->getId() !== null && (!$this->_useIsObjectNew || !$object->isObjectNew())) {
-                    $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $object->getId());
-                    /**
-                     * Not auto increment primary key support
-                     */
-                    if ($this->_isPkAutoIncrement) {
-                        $data = $this->prepareDataForUpdate($object);
-                        if (!empty($data)) {
-                            $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition);
-                        }
-                    } else {
-                        $select = $this->_getWriteAdapter()->select()->from(
-                            $this->getMainTable(),
-                            [$this->getIdFieldName()]
-                        )->where(
-                            $condition
-                        );
-                        if ($this->_getWriteAdapter()->fetchOne($select) !== false) {
-                            $data = $this->prepareDataForUpdate($object);
-                            if (!empty($data)) {
-                                $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition);
-                            }
-                        } else {
-                            $this->_getWriteAdapter()->insert(
-                                $this->getMainTable(),
-                                $this->_prepareDataForSave($object)
-                            );
-                        }
-                    }
+                if ($this->isObjectNotNew($object)) {
+                    $this->updateObject($object);
                 } else {
-                    $bind = $this->_prepareDataForSave($object);
-                    if ($this->_isPkAutoIncrement) {
-                        unset($bind[$this->getIdFieldName()]);
-                    }
-                    $this->_getWriteAdapter()->insert($this->getMainTable(), $bind);
-
-                    $object->setId($this->_getWriteAdapter()->lastInsertId($this->getMainTable()));
-
-                    if ($this->_useIsObjectNew) {
-                        $object->isObjectNew(false);
-                    }
+                    $this->saveNewObject($object);
                 }
-
                 $this->unserializeFields($object);
-                $this->_afterSave($object);
-
-                $object->afterSave();
+                $this->processAfterSaves($object);
             }
             $this->addCommitCallback([$object, 'afterCommitCallback'])->commit();
             $object->setHasDataChanges(false);
@@ -798,4 +763,111 @@ abstract class AbstractDb extends \Magento\Framework\Model\Resource\AbstractReso
 
         return $data;
     }
+
+    /**
+     * Check if object is new
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return bool
+     */
+    protected function isObjectNotNew(\Magento\Framework\Model\AbstractModel $object)
+    {
+        return $object->getId() !== null && (!$this->_useIsObjectNew || !$object->isObjectNew());
+    }
+
+    /**
+     * Save New Object
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @throws LocalizedException
+     * @return void
+     */
+    protected function saveNewObject(\Magento\Framework\Model\AbstractModel $object)
+    {
+        $bind = $this->_prepareDataForSave($object);
+        if ($this->_isPkAutoIncrement) {
+            unset($bind[$this->getIdFieldName()]);
+        }
+        $this->_getWriteAdapter()->insert($this->getMainTable(), $bind);
+
+        $object->setId($this->_getWriteAdapter()->lastInsertId($this->getMainTable()));
+
+        if ($this->_useIsObjectNew) {
+            $object->isObjectNew(false);
+        }
+    }
+
+    /**
+     * Update existing object
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @throws LocalizedException
+     * @return void
+     */
+    protected function updateObject(\Magento\Framework\Model\AbstractModel $object)
+    {
+        $condition = $this->_getWriteAdapter()->quoteInto($this->getIdFieldName() . '=?', $object->getId());
+        /**
+         * Not auto increment primary key support
+         */
+        if ($this->_isPkAutoIncrement) {
+            $data = $this->prepareDataForUpdate($object);
+            if (!empty($data)) {
+                $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition);
+            }
+        } else {
+            $select = $this->_getWriteAdapter()->select()->from(
+                $this->getMainTable(),
+                [$this->getIdFieldName()]
+            )->where(
+                $condition
+            );
+            if ($this->_getWriteAdapter()->fetchOne($select) !== false) {
+                $data = $this->prepareDataForUpdate($object);
+                if (!empty($data)) {
+                    $this->_getWriteAdapter()->update($this->getMainTable(), $data, $condition);
+                }
+            } else {
+                $this->_getWriteAdapter()->insert(
+                    $this->getMainTable(),
+                    $this->_prepareDataForSave($object)
+                );
+            }
+        }
+    }
+
+    /**
+     * Sequences of after save call
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return void
+     */
+    protected function processAfterSaves(\Magento\Framework\Model\AbstractModel $object)
+    {
+        $this->_afterSave($object);
+        $object->afterSave();
+    }
+
+    /**
+     * Check if object was modified
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return bool
+     */
+    protected function isModified(\Magento\Framework\Model\AbstractModel $object)
+    {
+        return $object->hasDataChanges();
+    }
+
+    /**
+     * Process object which was modified
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return $this
+     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+     */
+    protected function processNotModifiedSave(\Magento\Framework\Model\AbstractModel $object)
+    {
+        return $this;
+    }
 }
diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/AbstractDb.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/AbstractDb.php
new file mode 100644
index 0000000000000000000000000000000000000000..78c6a1b4c05bb70ed2e0f3363b42e0755cde4f89
--- /dev/null
+++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/AbstractDb.php
@@ -0,0 +1,76 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Model\Resource\Db\VersionControl;
+
+/**
+ * Class AbstractDb with snapshot saving and relation save processing
+ */
+abstract class AbstractDb extends \Magento\Framework\Model\Resource\Db\AbstractDb
+{
+    /**
+     * @var Snapshot
+     */
+    protected $entitySnapshot;
+
+    /**
+     * @var RelationComposite
+     */
+    protected $entityRelationComposite;
+
+    /**
+     * @param Snapshot $entitySnapshot
+     * @param RelationComposite $entityRelationComposite
+     * @param \Magento\Framework\Model\Resource\Db\Context $context
+     * @param string $resourcePrefix
+     */
+    public function __construct(
+        \Magento\Framework\Model\Resource\Db\Context $context,
+        Snapshot $entitySnapshot,
+        RelationComposite $entityRelationComposite,
+        $resourcePrefix = null
+    ) {
+        $this->entitySnapshot = $entitySnapshot;
+        $this->entityRelationComposite = $entityRelationComposite;
+        parent::__construct($context, $resourcePrefix);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    protected function _afterLoad(\Magento\Framework\Model\AbstractModel $object)
+    {
+        $this->entitySnapshot->registerSnapshot($object);
+        return parent::_afterLoad($object);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    protected function processAfterSaves(\Magento\Framework\Model\AbstractModel $object)
+    {
+        $this->_afterSave($object);
+        $this->entitySnapshot->registerSnapshot($object);
+        $object->afterSave();
+        $this->entityRelationComposite->processRelations($object);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    protected function isModified(\Magento\Framework\Model\AbstractModel $object)
+    {
+        return $this->entitySnapshot->isModified($object);
+    }
+
+    /**
+     * @inheritdoc
+     */
+    protected function processNotModifiedSave(\Magento\Framework\Model\AbstractModel $object)
+    {
+        $this->entityRelationComposite->processRelations($object);
+        return $this;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Collection.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Collection.php
new file mode 100644
index 0000000000000000000000000000000000000000..84f2334021e834c56d4aaa436c426a4eaf49d906
--- /dev/null
+++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Collection.php
@@ -0,0 +1,67 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Model\Resource\Db\VersionControl;
+
+/**
+ * Class Collection
+ */
+abstract class Collection extends \Magento\Framework\Model\Resource\Db\Collection\AbstractCollection
+{
+    /**
+     * @var Snapshot
+     */
+    protected $entitySnapshot;
+
+    /**
+     * @param \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory
+     * @param \Psr\Log\LoggerInterface $logger
+     * @param \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy
+     * @param \Magento\Framework\Event\ManagerInterface $eventManager
+     * @param Snapshot $entitySnapshot
+     * @param \Zend_Db_Adapter_Abstract $connection
+     * @param \Magento\Framework\Model\Resource\Db\AbstractDb $resource
+     */
+    public function __construct(
+        \Magento\Framework\Data\Collection\EntityFactoryInterface $entityFactory,
+        \Psr\Log\LoggerInterface $logger,
+        \Magento\Framework\Data\Collection\Db\FetchStrategyInterface $fetchStrategy,
+        \Magento\Framework\Event\ManagerInterface $eventManager,
+        Snapshot $entitySnapshot,
+        $connection = null,
+        \Magento\Framework\Model\Resource\Db\AbstractDb $resource = null
+    ) {
+        $this->entitySnapshot = $entitySnapshot;
+        parent::__construct(
+            $entityFactory,
+            $logger,
+            $fetchStrategy,
+            $eventManager,
+            $connection,
+            $resource
+        );
+    }
+
+    /**
+     * @inheritdoc
+     */
+    public function fetchItem()
+    {
+        $item = parent::fetchItem();
+        if ($item) {
+            $this->entitySnapshot->registerSnapshot($item);
+        }
+        return $item;
+    }
+
+    /**
+     * @inheritdoc
+     */
+    protected function beforeAddLoadedItem(\Magento\Framework\Object $item)
+    {
+        $this->entitySnapshot->registerSnapshot($item);
+        return $item;
+    }
+}
diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Metadata.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Metadata.php
new file mode 100644
index 0000000000000000000000000000000000000000..b761d22717f2f0ecb5fe99f5b3c15e43405f58c4
--- /dev/null
+++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Metadata.php
@@ -0,0 +1,41 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Model\Resource\Db\VersionControl;
+
+/**
+ * Class Metadata represents a list of entity fields that are applicable for persistence operations
+ */
+class Metadata
+{
+    /**
+     * @var array
+     */
+    protected $metadataInfo = [];
+
+    /**
+     * Returns list of entity fields that are applicable for persistence operations
+     *
+     * @param \Magento\Framework\Object $entity
+     * @return array
+     * @throws \Magento\Framework\Exception\LocalizedException
+     */
+    public function getFields(\Magento\Framework\Object $entity)
+    {
+        $entityClass = get_class($entity);
+        if (!isset($this->metadataInfo[$entityClass])) {
+            $this->metadataInfo[$entityClass] =
+                array_fill_keys(
+                    array_keys(
+                        $entity->getResource()->getReadConnection()->describeTable(
+                            $entity->getResource()->getMainTable()
+                        )
+                    ),
+                    null
+                );
+        }
+        return $this->metadataInfo[$entityClass];
+    }
+}
diff --git a/app/code/Magento/Sales/Model/Resource/EntityRelationComposite.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationComposite.php
similarity index 81%
rename from app/code/Magento/Sales/Model/Resource/EntityRelationComposite.php
rename to lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationComposite.php
index 3c367791a20f82990084b87525e54e77455596e2..42a2496f284447fd7dcec95dda0507c8987df2fc 100644
--- a/app/code/Magento/Sales/Model/Resource/EntityRelationComposite.php
+++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationComposite.php
@@ -3,16 +3,15 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
+namespace Magento\Framework\Model\Resource\Db\VersionControl;
 
-namespace Magento\Sales\Model\Resource;
-
-use Magento\Sales\Model\AbstractModel;
+use Magento\Framework\Model\AbstractModel;
 use Magento\Framework\Event\ManagerInterface as EventManager;
 
 /**
- * Class EntityRelationComposite
+ * Class RelationComposite
  */
-class EntityRelationComposite
+class RelationComposite
 {
     /**
      * @var array
@@ -37,13 +36,15 @@ class EntityRelationComposite
     }
 
     /**
+     * Process model's relations saves
+     *
      * @param AbstractModel $object
      * @return void
      */
     public function processRelations(AbstractModel $object)
     {
         foreach ($this->relationProcessors as $processor) {
-            /**@var $processor \Magento\Sales\Model\Resource\EntityRelationInterface*/
+            /**@var $processor RelationInterface*/
             $processor->processRelation($object);
         }
         $this->eventManager->dispatch(
diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationInterface.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..b16d44509381ae2231c707610f51e6df26daa998
--- /dev/null
+++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/RelationInterface.php
@@ -0,0 +1,20 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Model\Resource\Db\VersionControl;
+
+/**
+ * Interface RelationInterface
+ */
+interface RelationInterface
+{
+    /**
+     * Process object relations
+     *
+     * @param \Magento\Framework\Model\AbstractModel $object
+     * @return void
+     */
+    public function processRelation(\Magento\Framework\Model\AbstractModel $object);
+}
diff --git a/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Snapshot.php b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Snapshot.php
new file mode 100644
index 0000000000000000000000000000000000000000..dc837426020a4361561a6a5d013367bb1f0e659f
--- /dev/null
+++ b/lib/internal/Magento/Framework/Model/Resource/Db/VersionControl/Snapshot.php
@@ -0,0 +1,75 @@
+<?php
+/**
+ * Copyright © 2015 Magento. All rights reserved.
+ * See COPYING.txt for license details.
+ */
+namespace Magento\Framework\Model\Resource\Db\VersionControl;
+
+/**
+ * Class Snapshot register snapshot of entity data, for tracking changes
+ */
+class Snapshot
+{
+    /**
+     * Array of snapshots of entities data
+     *
+     * @var array
+     */
+    protected $snapshotData = [];
+
+    /**
+     * @var Metadata
+     */
+    protected $metadata;
+
+    /**
+     * Initialization
+     *
+     * @param Metadata $metadata
+     */
+    public function __construct(
+        Metadata $metadata
+    ) {
+        $this->metadata = $metadata;
+    }
+
+    /**
+     * Register snapshot of entity data, for tracking changes
+     *
+     * @param \Magento\Framework\Object $entity
+     * @return void
+     * @SuppressWarnings(PHPMD.UnusedLocalVariable)
+     */
+    public function registerSnapshot(\Magento\Framework\Object $entity)
+    {
+        $metaData = $this->metadata->getFields($entity);
+        $filteredData = array_intersect_key($entity->getData(), $metaData);
+        $data = array_merge($metaData, $filteredData);
+        $this->snapshotData[get_class($entity)][$entity->getId()] = $data;
+    }
+
+    /**
+     * Check is current entity has changes, by comparing current object state with stored snapshot
+     *
+     * @param \Magento\Framework\Object $entity
+     * @return bool
+     */
+    public function isModified(\Magento\Framework\Object $entity)
+    {
+        if (!$entity->getId()) {
+            return true;
+        }
+
+        $entityClass = get_class($entity);
+        if (!isset($this->snapshotData[$entityClass][$entity->getId()])) {
+            return true;
+        }
+        foreach ($this->snapshotData[$entityClass][$entity->getId()] as $field => $value) {
+            if ($entity->getDataByKey($field) != $value) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+}
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntityMetadataTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/MetadataTest.php
similarity index 80%
rename from app/code/Magento/Sales/Test/Unit/Model/Resource/EntityMetadataTest.php
rename to lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/MetadataTest.php
index bfb0c1ab8c0325d064ad3ce6cd663fe07cc86edf..553ea15c2be9a1d8324d10ac14981d10bbc9da29 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntityMetadataTest.php
+++ b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/MetadataTest.php
@@ -3,22 +3,22 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Sales\Test\Unit\Model\Resource;
+namespace Magento\Framework\Model\Test\Unit\Resource\Db\VersionControl;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 /**
- * Class EntityMetadataTest
+ * Class Version Control MetadataTest
  */
-class EntityMetadataTest extends \PHPUnit_Framework_TestCase
+class MetadataTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Sales\Model\Resource\EntityMetadata
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Metadata
      */
     protected $entityMetadata;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Sales\Model\AbstractModel
+     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\AbstractModel
      */
     protected $model;
 
@@ -39,7 +39,7 @@ class EntityMetadataTest extends \PHPUnit_Framework_TestCase
     {
         $objectManager = new ObjectManager($this);
         $this->model = $this->getMock(
-            'Magento\Sales\Model\AbstractModel',
+            'Magento\Framework\Model\AbstractModel',
             [],
             [],
             '',
@@ -63,13 +63,15 @@ class EntityMetadataTest extends \PHPUnit_Framework_TestCase
         );
         $this->model->expects($this->any())->method('getResource')->willReturn($this->resource);
         $this->resource->expects($this->any())->method('getReadConnection')->willReturn($this->connection);
-        $this->entityMetadata = $objectManager->getObject('Magento\Sales\Model\Resource\EntityMetadata');
+        $this->entityMetadata = $objectManager->getObject(
+            'Magento\Framework\Model\Resource\Db\VersionControl\Metadata'
+        );
     }
 
     public function testGetFields()
     {
         $mainTable = 'main_table';
-        $expectedDescribedTable = 'described_table';
+        $expectedDescribedTable = ['described_table' => null];
         $this->resource->expects($this->any())->method('getMainTable')->willReturn($mainTable);
         $this->connection->expects($this->once())->method('describeTable')->with($mainTable)->willReturn(
             $expectedDescribedTable
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntityRelationCompositeTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/RelationCompositeTest.php
similarity index 56%
rename from app/code/Magento/Sales/Test/Unit/Model/Resource/EntityRelationCompositeTest.php
rename to lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/RelationCompositeTest.php
index 9da63a991cd7e6b5b973b1e2bc429fe4807a1efa..942b5bd8c59238101fa0b3b3ef0255772a878d36 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntityRelationCompositeTest.php
+++ b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/RelationCompositeTest.php
@@ -4,25 +4,25 @@
  * See COPYING.txt for license details.
  */
 
-namespace Magento\Sales\Test\Unit\Model\Resource;
+namespace Magento\Framework\Model\Test\Unit\Resource\Db\VersionControl;
 
 /**
- * Class EntityRelationCompositeTest
+ * Class RelationCompositeTest
  */
-class EntityRelationCompositeTest extends \PHPUnit_Framework_TestCase
+class RelationCompositeTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Sales\Model\Resource\EntityRelationComposite
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite
      */
     protected $entityRelationComposite;
 
     /**
-     * @var \Magento\Sales\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\AbstractModel|\PHPUnit_Framework_MockObject_MockObject
      */
-    protected $salesModelMock;
+    protected $modelMock;
 
     /**
-     * @var \Magento\Sales\Model\Resource\EntityRelationInterface|\PHPUnit_Framework_MockObject_MockObject
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface
      */
     protected $relationProcessorMock;
 
@@ -33,7 +33,7 @@ class EntityRelationCompositeTest extends \PHPUnit_Framework_TestCase
 
     public function setUp()
     {
-        $this->salesModelMock = $this->getMockBuilder('Magento\Sales\Model\AbstractModel')
+        $this->modelMock = $this->getMockBuilder('Magento\Framework\Model\AbstractModel')
             ->disableOriginalConstructor()
             ->setMethods(
                 [
@@ -41,16 +41,17 @@ class EntityRelationCompositeTest extends \PHPUnit_Framework_TestCase
                 ]
             )
             ->getMockForAbstractClass();
-        $this->relationProcessorMock = $this->getMockBuilder('Magento\Sales\Model\AbstractModel')
+        $this->relationProcessorMock = $this->getMockBuilder('Magento\Framework\Model\AbstractModel')
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
         $this->eventManagerMock = $this->getMockBuilder('Magento\Framework\Event\ManagerInterface')
             ->disableOriginalConstructor()
             ->getMockForAbstractClass();
-        $this->relationProcessorMock = $this->getMockBuilder('Magento\Sales\Model\Resource\EntityRelationInterface')
-            ->disableOriginalConstructor()
-            ->getMockForAbstractClass();
-        $this->entityRelationComposite = new \Magento\Sales\Model\Resource\EntityRelationComposite(
+        $this->relationProcessorMock = $this->getMockBuilder(
+            'Magento\Framework\Model\Resource\Db\VersionControl\RelationInterface'
+        )->disableOriginalConstructor()->getMockForAbstractClass();
+
+        $this->entityRelationComposite = new \Magento\Framework\Model\Resource\Db\VersionControl\RelationComposite(
             $this->eventManagerMock,
             [
                 'default' => $this->relationProcessorMock
@@ -62,18 +63,18 @@ class EntityRelationCompositeTest extends \PHPUnit_Framework_TestCase
     {
         $this->relationProcessorMock->expects($this->once())
             ->method('processRelation')
-            ->with($this->salesModelMock);
-        $this->salesModelMock->expects($this->once())
+            ->with($this->modelMock);
+        $this->modelMock->expects($this->once())
             ->method('getEventPrefix')
-            ->willReturn('sales_event_prefix');
+            ->willReturn('custom_event_prefix');
         $this->eventManagerMock->expects($this->once())
             ->method('dispatch')
             ->with(
-                'sales_event_prefix_process_relation',
+                'custom_event_prefix_process_relation',
                 [
-                    'object' => $this->salesModelMock
+                    'object' => $this->modelMock
                 ]
             );
-        $this->entityRelationComposite->processRelations($this->salesModelMock);
+        $this->entityRelationComposite->processRelations($this->modelMock);
     }
 }
diff --git a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntitySnapshotTest.php b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/SnapshotTest.php
similarity index 62%
rename from app/code/Magento/Sales/Test/Unit/Model/Resource/EntitySnapshotTest.php
rename to lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/SnapshotTest.php
index 6a7b4c896a0449f535d37589ece506fbc84ea42c..34aa803dae17641c5c679a9adb9078f869e9da31 100644
--- a/app/code/Magento/Sales/Test/Unit/Model/Resource/EntitySnapshotTest.php
+++ b/lib/internal/Magento/Framework/Model/Test/Unit/Resource/Db/VersionControl/SnapshotTest.php
@@ -3,27 +3,27 @@
  * Copyright © 2015 Magento. All rights reserved.
  * See COPYING.txt for license details.
  */
-namespace Magento\Sales\Test\Unit\Model\Resource;
+namespace Magento\Framework\Model\Test\Unit\Resource\Db\VersionControl;
 
 use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
 
 /**
- * Class EntitySnapshotTest
+ * Class SnapshotTest
  */
-class EntitySnapshotTest extends \PHPUnit_Framework_TestCase
+class SnapshotTest extends \PHPUnit_Framework_TestCase
 {
     /**
-     * @var \Magento\Sales\Model\Resource\EntitySnapshot
+     * @var \Magento\Framework\Model\Resource\Db\VersionControl\Snapshot
      */
     protected $entitySnapshot;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Sales\Model\Resource\EntityMetadata
+     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\Resource\Db\VersionControl\Metadata
      */
     protected $entityMetadata;
 
     /**
-     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Sales\Model\AbstractModel
+     * @var \PHPUnit_Framework_MockObject_MockObject | \Magento\Framework\Model\AbstractModel
      */
     protected $model;
 
@@ -34,24 +34,24 @@ class EntitySnapshotTest extends \PHPUnit_Framework_TestCase
     {
         $objectManager = new ObjectManager($this);
         $this->model = $this->getMock(
-            'Magento\Sales\Model\AbstractModel',
-            [],
+            'Magento\Framework\Model\AbstractModel',
+            ['getId'],
             [],
             '',
             false
         );
 
         $this->entityMetadata = $this->getMock(
-            'Magento\Sales\Model\Resource\EntityMetadata',
-            [],
+            'Magento\Framework\Model\Resource\Db\VersionControl\Metadata',
+            ['getFields'],
             [],
             '',
             false
         );
 
         $this->entitySnapshot = $objectManager->getObject(
-            'Magento\Sales\Model\Resource\EntitySnapshot',
-            ['entityMetadata' => $this->entityMetadata]
+            'Magento\Framework\Model\Resource\Db\VersionControl\Snapshot',
+            ['metadata' => $this->entityMetadata]
         );
     }
 
@@ -65,14 +65,16 @@ class EntitySnapshotTest extends \PHPUnit_Framework_TestCase
             'custom_not_present_attribute' => ''
         ];
         $fields = [
-            'id',
-            'name',
-            'description'
+            'id' => [],
+            'name' => [],
+            'description' => []
         ];
-        $this->model->expects($this->once())->method('getData')->willReturn($data);
-        $this->model->expects($this->once())->method('getId')->willReturn($entityId);
-        $this->entityMetadata->expects($this->once())->method('getFields')->with($this->model)->willReturn($fields);
+        $this->assertTrue($this->entitySnapshot->isModified($this->model));
+        $this->model->setData($data);
+        $this->model->expects($this->any())->method('getId')->willReturn($entityId);
+        $this->entityMetadata->expects($this->any())->method('getFields')->with($this->model)->willReturn($fields);
         $this->entitySnapshot->registerSnapshot($this->model);
+        $this->assertFalse($this->entitySnapshot->isModified($this->model));
     }
 
     public function testIsModified()
@@ -90,15 +92,11 @@ class EntitySnapshotTest extends \PHPUnit_Framework_TestCase
             'description' => []
         ];
         $modifiedData = array_merge($data, ['name' => 'newName']);
-        $this->model->expects($this->exactly(4))->method('getData')->willReturnOnConsecutiveCalls(
-            $data,
-            $modifiedData,
-            $modifiedData,
-            $modifiedData
-        );
         $this->model->expects($this->any())->method('getId')->willReturn($entityId);
-        $this->entityMetadata->expects($this->exactly(4))->method('getFields')->with($this->model)->willReturn($fields);
+        $this->entityMetadata->expects($this->exactly(2))->method('getFields')->with($this->model)->willReturn($fields);
+        $this->model->setData($data);
         $this->entitySnapshot->registerSnapshot($this->model);
+        $this->model->setData($modifiedData);
         $this->assertTrue($this->entitySnapshot->isModified($this->model));
         $this->entitySnapshot->registerSnapshot($this->model);
         $this->assertFalse($this->entitySnapshot->isModified($this->model));