mongodb-odm-docs-dash/build.docset/Contents/Resources/Documents/reference/priming-references.html
2017-12-01 19:35:11 -08:00

299 lines
19 KiB
HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Priming References &mdash; Doctrine MongoDB ODM 1.1.5 documentation</title>
<link rel="stylesheet" href="../_static/bootstrap/css/bootstrap.min.css" type="text/css" />
<link rel="stylesheet" href="../_static/default.css" type="text/css" />
<link rel="stylesheet" href="../_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="../_static/layout.css" type="text/css" />
<link rel="stylesheet" href="../_static/configurationblock.css" type="text/css" />
<script type="text/javascript">
var DOCUMENTATION_OPTIONS = {
URL_ROOT: '../',
VERSION: '1.1.5',
COLLAPSE_MODINDEX: false,
FILE_SUFFIX: '.html',
HAS_SOURCE: true
};
</script>
<script type="text/javascript" src="../_static/jquery.js"></script>
<script type="text/javascript" src="../_static/configurationblock.js"></script>
<script type="text/javascript" src="../_static/underscore.js"></script>
<script type="text/javascript" src="../_static/configurationblock.js"></script>
<script type="text/javascript" src="../_static/doctools.js"></script>
<script type="text/javascript" src="../_static/configurationblock.js"></script>
<script src="../_static/bootstrap/js/bootstrap.min.js"></script>
<script type="text/javascript">
<!--
$(document).ready(function() {
$("#versions").change(function() {
var docsUrl = $(this).val();
window.location.href = docsUrl;
});
});
-->
</script>
<link rel="shortcut icon" href="../_static/doctrine.ico"/>
<link rel="search" title="Search" href="../search.html" />
<link rel="top" title="Doctrine MongoDB ODM 1.1.5 documentation" href="../index.html" />
</head>
<body>
<div id="wrapper">
<div id="header">
<h1 id="h1title"></h1>
<div id="logo">
<a href="http://www.doctrine-project.org/">Doctrine - PHP Database Libraries</a>
</div>
</div>
<div id="nav" class="cls">
<div class="tl cls">
<ul>
<li><a target="_top" href="http://www.doctrine-project.org/">Home</a></li>
<li><a target="_top" href="http://www.doctrine-project.org/about.html">About</a></li>
<li><a target="_top" href="http://www.doctrine-project.org/projects.html">Projects</a></li>
<li><a target="_top" href="http://www.doctrine-project.org/contribute.html">Contribute</a></li>
<li><a target="_top" href="http://www.doctrine-project.org/community.html">Community</a></li>
<li><a target="_top" href="http://www.doctrine-project.org/archive.html">Blog</a></li>
<li><a target="_top" href="http://www.doctrine-project.org/jira">Development</a></li>
</ul>
</div>
</div>
<div id="content" class="cls">
<div class="related">
<h3>Navigation</h3>
<ul>
<li><a href="/">Doctrine Homepage</a> &raquo;</li>
<li><a href="../index.html">Doctrine MongoDB ODM 1.1.5 documentation</a> &raquo;</li>
</ul>
</div>
<div class="document">
<div class="documentwrapper">
<div class="bodywrapper">
<div class="body" >
<div class="section" id="priming-references">
<h1>Priming References<a class="headerlink" href="#priming-references" title="Permalink to this headline"></a></h1>
<p>Priming references allows you to consolidate database queries when working with
<a class="reference internal" href="reference-mapping.html#reference-one"><span class="std std-ref">one</span></a> and <a class="reference internal" href="reference-mapping.html#reference-many"><span class="std std-ref">many</span></a> reference mappings.
This is useful for avoiding the
<a class="reference external" href="http://stackoverflow.com/q/97197/162228">n+1 problem</a> in your application.</p>
<div class="section" id="query-builder">
<h2>Query Builder<a class="headerlink" href="#query-builder" title="Permalink to this headline"></a></h2>
<p>Consider the following abbreviated model:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>
<span class="sd">/** @Document */</span>
<span class="k">class</span> <span class="nc">User</span>
<span class="p">{</span>
<span class="sd">/** @ReferenceMany(targetDocument=&quot;Account&quot;) */</span>
<span class="k">private</span> <span class="nv">$accounts</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>We would like to query for 100 users and then iterate over their referenced
accounts.</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>
<span class="nv">$qb</span> <span class="o">=</span> <span class="nv">$dm</span><span class="o">-&gt;</span><span class="na">createQueryBuilder</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">)</span>
<span class="o">-&gt;</span><span class="na">limit</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
<span class="nv">$query</span> <span class="o">=</span> <span class="nv">$qb</span><span class="o">-&gt;</span><span class="na">getQuery</span><span class="p">();</span>
<span class="nv">$users</span> <span class="o">=</span> <span class="nv">$query</span><span class="o">-&gt;</span><span class="na">execute</span><span class="p">();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$users</span> <span class="k">as</span> <span class="nv">$user</span><span class="p">)</span> <span class="p">{</span>
<span class="cm">/* PersistentCollection::initialize() will be invoked when we begin</span>
<span class="cm"> * iterating through the user&#39;s accounts. Any accounts not already</span>
<span class="cm"> * managed by the unit of work will need to be queried.</span>
<span class="cm"> */</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">getAccounts</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$account</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In this example, ODM would query the database once for the result set of users
and then, for each user, issue a separate query to load any accounts that are
not already being managed by the unit of work. This could result in as many as
100 additional database queries!</p>
<p>If we expect to iterate through all users and their accounts, we could optimize
this process by loading all of the referenced accounts with one query. The query
builder's <code class="docutils literal"><span class="pre">prime()</span></code> method allows us to do just that.</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>
<span class="nv">$qb</span> <span class="o">=</span> <span class="nv">$dm</span><span class="o">-&gt;</span><span class="na">createQueryBuilder</span><span class="p">(</span><span class="s1">&#39;User&#39;</span><span class="p">)</span>
<span class="o">-&gt;</span><span class="na">field</span><span class="p">(</span><span class="s1">&#39;accounts&#39;</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">prime</span><span class="p">(</span><span class="k">true</span><span class="p">)</span>
<span class="o">-&gt;</span><span class="na">limit</span><span class="p">(</span><span class="mi">100</span><span class="p">);</span>
<span class="nv">$query</span> <span class="o">=</span> <span class="nv">$qb</span><span class="o">-&gt;</span><span class="na">getQuery</span><span class="p">();</span>
<span class="cm">/* After querying for the users, ODM will collect the IDs of all referenced</span>
<span class="cm"> * accounts and load them with a single additional query.</span>
<span class="cm"> */</span>
<span class="nv">$users</span> <span class="o">=</span> <span class="nv">$query</span><span class="o">-&gt;</span><span class="na">execute</span><span class="p">();</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$users</span> <span class="k">as</span> <span class="nv">$user</span><span class="p">)</span> <span class="p">{</span>
<span class="cm">/* Accounts have already been loaded, so iterating through accounts will</span>
<span class="cm"> * not query an additional query.</span>
<span class="cm"> */</span>
<span class="k">foreach</span> <span class="p">(</span><span class="nv">$user</span><span class="o">-&gt;</span><span class="na">getAccounts</span><span class="p">()</span> <span class="k">as</span> <span class="nv">$account</span><span class="p">)</span> <span class="p">{</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
</div>
<p>In this case, priming will allow us to load all users and referenced accounts in
two database queries. If the accounts had used an
<a class="reference internal" href="inheritance-mapping.html#inheritance-mapping"><span class="std std-ref">inheritance mapping</span></a>, priming might require several
queries (one per discriminated class name).</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Priming is also compatible with <a class="reference internal" href="reference-mapping.html#storing-references"><span class="std std-ref">simple references</span></a>
and discriminated references. When priming discriminated references, ODM
will issue one query per distinct class among the referenced document(s).</p>
</div>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">Hydration must be enabled in the query builder for priming to work properly.
Disabling hydration will cause the DBRef to be returned for a referenced
document instead of the hydrated document object.</p>
</div>
</div>
<div class="section" id="inverse-references">
<h2>Inverse references<a class="headerlink" href="#inverse-references" title="Permalink to this headline"></a></h2>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">This feature was added in version 1.2.</p>
</div>
<p>When using inverse references (references mapped using <code class="docutils literal"><span class="pre">mappedBy</span></code> or
<code class="docutils literal"><span class="pre">repositoryMethod</span></code>) you can also enable primers on one-to-many references by
specifying them in the mapping:</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>
<span class="sd">/** @Document */</span>
<span class="k">class</span> <span class="nc">User</span>
<span class="p">{</span>
<span class="sd">/** @ReferenceMany(targetDocument=&quot;Account&quot;, prime={&quot;user&quot;}) */</span>
<span class="k">private</span> <span class="nv">$accounts</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
<p>When the collection is initialized, the configured primers are automatically
added to the query.</p>
<div class="admonition note">
<p class="first admonition-title">Note</p>
<p class="last">When using inverse references with <code class="docutils literal"><span class="pre">repositoryMethod</span></code>, be sure to return
an eager cursor from the repository method if you want to rely on primers
defined in the mapping. If the result is not an eager cursor, an exception
will be thrown and the collection won't be loaded. Also, any primers you
might have added in the <code class="docutils literal"><span class="pre">repositoryMethod</span></code> are overwritten with those
specified in the mapping.</p>
</div>
</div>
<div class="section" id="primer-callback">
<h2>Primer Callback<a class="headerlink" href="#primer-callback" title="Permalink to this headline"></a></h2>
<p>Passing <code class="docutils literal"><span class="pre">true</span></code> to <code class="docutils literal"><span class="pre">prime()</span></code> instructs ODM to load the referenced document(s)
on its own; however, we can also pass a custom callable (e.g. Closure instance)
to <code class="docutils literal"><span class="pre">prime()</span></code>, which allows more control over the priming query.</p>
<p>As an example, we can look at the default callable, which is found in the
<code class="docutils literal"><span class="pre">ReferencePrimer</span></code> class.</p>
<div class="highlight-php"><div class="highlight"><pre><span class="cp">&lt;?php</span>
<span class="k">function</span><span class="p">(</span><span class="nx">DocumentManager</span> <span class="nv">$dm</span><span class="p">,</span> <span class="nx">ClassMetadata</span> <span class="nv">$class</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$ids</span><span class="p">,</span> <span class="k">array</span> <span class="nv">$hints</span><span class="p">)</span> <span class="p">{</span>
<span class="nv">$qb</span> <span class="o">=</span> <span class="nv">$dm</span><span class="o">-&gt;</span><span class="na">createQueryBuilder</span><span class="p">(</span><span class="nv">$class</span><span class="o">-&gt;</span><span class="na">name</span><span class="p">)</span>
<span class="o">-&gt;</span><span class="na">field</span><span class="p">(</span><span class="nv">$class</span><span class="o">-&gt;</span><span class="na">identifier</span><span class="p">)</span><span class="o">-&gt;</span><span class="na">in</span><span class="p">(</span><span class="nv">$ids</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span> <span class="o">!</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$hints</span><span class="p">[</span><span class="nx">Query</span><span class="o">::</span><span class="na">HINT_SLAVE_OKAY</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$qb</span><span class="o">-&gt;</span><span class="na">slaveOkay</span><span class="p">(</span><span class="k">true</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span> <span class="o">!</span> <span class="k">empty</span><span class="p">(</span><span class="nv">$hints</span><span class="p">[</span><span class="nx">Query</span><span class="o">::</span><span class="na">HINT_READ_PREFERENCE</span><span class="p">]))</span> <span class="p">{</span>
<span class="nv">$qb</span><span class="o">-&gt;</span><span class="na">setReadPreference</span><span class="p">(</span>
<span class="nv">$hints</span><span class="p">[</span><span class="nx">Query</span><span class="o">::</span><span class="na">HINT_READ_PREFERENCE</span><span class="p">],</span>
<span class="nv">$hints</span><span class="p">[</span><span class="nx">Query</span><span class="o">::</span><span class="na">HINT_READ_PREFERENCE_TAGS</span><span class="p">]</span>
<span class="p">);</span>
<span class="p">}</span>
<span class="nv">$qb</span><span class="o">-&gt;</span><span class="na">getQuery</span><span class="p">()</span><span class="o">-&gt;</span><span class="na">toArray</span><span class="p">();</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Firstly, the callable is passed the <code class="docutils literal"><span class="pre">DocumentManager</span></code> of the main query. This
is necessary to create the query used for priming, and ensures that the results
will become managed in the same scope. The <code class="docutils literal"><span class="pre">ClassMetadata</span></code> argument provides
mapping information for the referenced class as well as its name, which is used
to create the query builder. An array of identifiers follows, which is used to
query for the documents to be primed. Lastly, the <code class="docutils literal"><span class="pre">UnitOfWork</span></code> hints from the
original query are provided so that the priming query can apply them as well.</p>
</div>
</div>
</div>
</div>
</div>
<div class="sphinxsidebar">
<div class="sphinxsidebarwrapper">
<div id="searchbox" style="">
<h3>Search</h3>
<form class="search" action="http://readthedocs.org/search/project/" method="get">
<input type="text" name="q" size="18">
<input type="submit" value="Go">
<input type="hidden" name="selected_facets" value="project:">
</form>
</div>
<h3><a href="../index.html">Table Of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Priming References</a><ul>
<li><a class="reference internal" href="#query-builder">Query Builder</a></li>
<li><a class="reference internal" href="#inverse-references">Inverse references</a></li>
<li><a class="reference internal" href="#primer-callback">Primer Callback</a></li>
</ul>
</li>
</ul>
<h3>This Page</h3>
<ul class="this-page-menu">
<li><a href="../_sources/reference/priming-references.rst.txt"
rel="nofollow">Show Source</a></li>
</ul>
</div>
</div>
<div class="clearer"></div>
</div>
<div class="footer">
&copy; Copyright 2013, Doctrine Project Team.
Created using <a href="http://sphinx.pocoo.org/">Sphinx</a> 1.6.2.
<br/>
<a target="_BLANK" href="http://www.servergrove.com"><img src="http://www.doctrine-project.org/_static/servergrove.jpg" /></a> <br/><br/>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_s-xclick" />
<input type="hidden" name="hosted_button_id" value="BAE2E3XANQ77Y" />
<input type="image" src="https://www.paypal.com/en_US/i/btn/btn_donateCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!" />
<img alt="" border="0" src="https://www.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1" />
</form>
</div>
</div>
<div id="bot-rcnr">
<div class="tl"><!-- corner --></div>
</div>
</div>
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript">
</script>
<script type="text/javascript">
_uacct = "UA-288343-7";
urchinTracker();
</script>
<a class="githublink" href="http://github.com/doctrine"><img src="https://s3.amazonaws.com/github/ribbons/forkme_right_orange_ff7600.png" alt="Fork me on GitHub"></a>
</body>
</html>