Best Way to Load a Custom Model in Magento 2

Best practice: via the service contract

The best practice is always to use the service contract whenever it's possible. You can find the list of reasons here: Magento 2: what are the benefits of using service contracts?

For details on how to implement a service contract I suggest you check this topic: How to implement service contract for a custom module in Magento 2?

If no service contract available

If there is no service contract available, you should use the model repository get method. Using this method, you benefit from the magento caching system for example for the CategoryRepository class:

public function get($categoryId, $storeId = null)
{
    $cacheKey = null !== $storeId ? $storeId : 'all';
    if (!isset($this->instances[$categoryId][$cacheKey])) {
        /** @var Category $category */
        $category = $this->categoryFactory->create();
        if (null !== $storeId) {
            $category->setStoreId($storeId);
        }
        $category->load($categoryId);
        if (!$category->getId()) {
            throw NoSuchEntityException::singleField('id', $categoryId);
        }
        $this->instances[$categoryId][$cacheKey] = $category;
    }
    return $this->instances[$categoryId][$cacheKey];
}

Deprecated load() method

Magento 2 is slowly moving away from the standard CRUD system by dropping the inheritance system and implementing it via composition using the new 2.1 EntityManager you can find details here: Magento 2.1: using the entity manager

Also I suggest you read this interesting topic about the deprecated CRUD methods: Deprecated save and load methods in Abstract Model

Why not using the resource model load

The main reason is that if you use the resource model load method, you will skip some important part of the loading system that are implemented in the model load method, see Magento\Framework\Model\AbstractModel :

public function load($modelId, $field = null)
{
    $this->_beforeLoad($modelId, $field);
    $this->_getResource()->load($this, $modelId, $field);
    $this->_afterLoad();
    $this->setOrigData();
    $this->_hasDataChanges = false;
    $this->updateStoredData();
    return $this;
}

Calling the resource model load method directly will have the following impact:

  • _beforeLoad is not called: thus the model load before events are not dispatched
  • _afterLoad is not called: thus the model load after events are not dispatched
  • the stored data are not updated which can cause various problems (for instance if you call prepareDataForUpdate from Magento\Framework\Model\ResourceModel\Db\AbstractDb )