Note that there are some explanatory texts on larger screens.

plurals
  1. PORe-writing Linq Expression in NHibernate + DDD context
    primarykey
    data
    text
    <p>I have a thorny question about transforming Linq Expressions. I had a good search about, but I couldn't find anything that seems to cover this case. I'm reasonably familiar with Linq, at least in terms of creating and passing lambdas to methods, but I'm somewhat weaker on the Expression stuff. </p> <p>First, some context: I have a generic persistence solution based on NHibernate used inside a number of DDD-ish projects. For special cases where a given collection of children within an aggregate could be essentially infinite (ie very large indeed), I cannot simply map a set or bag as it would never be acceptable for the entire collection to be loaded into memory. In this architecture it's not possible for code consuming the API to talk to the Repository directly to do a query or limit the results that way. I could of course not have a collection in the API at all and expose methods to retrieve relevant subsets of child objects instead (and if this doesn't work that's what I'll do), but I'm trying to do something slightly different and I've <em>almost</em> got it working...</p> <p>These projects are being mapped with Fluent (not auto-mapping), and so I added a method to my base map class in the form</p> <pre><code>HasManyQueryable&lt;TCollection&gt;(Expression&lt;Func&lt;T, IQueryable&lt;TCollection&gt;&gt;&gt; memberExpression, Expression&lt;Func&lt;T, TCollection, bool&gt;&gt; selector) </code></pre> <p>This method derives the relevant <code>PropertyInfo</code> from the first <code>Expression</code> (which specifies the member to map). The selector <code>Expression</code> contains the relationship between the parent and child objects as a substitute for a normal NHibernate mapping.</p> <p>So, suppose I have a selector in the map for a domain type <code>User</code> (which is <code>T</code> above):</p> <pre><code>HasManyQueryable&lt;Transaction&gt;(x =&gt; x.Transactions, (u, t) =&gt; t.User == u); </code></pre> <p>This specifies a mapping between the subset of all <code>Transactions</code> where <code>Transaction.User</code> is the supplied <code>User</code> <em>u</em>, and the <code>User.Transactions</code> property which is <code>IQueryable&lt;Transaction&gt;</code>. When an actual <code>User</code> object is constructed, I need to turn this into </p> <pre><code>Expression&lt;Func&lt;Transaction, bool&gt;&gt; expression = (t =&gt; t.User == this) </code></pre> <p>where <code>this</code> is the <code>User</code> object being constructed. In other words, I want to take a general rule that says how to map <code>Users</code> to <code>Transactions</code> and turn it into a rule about mapping <em>this</em> <code>User</code> to <code>Transactions</code>. I can then use this expression to generate an <code>IQueryable&lt;Transaction&gt;</code> from the Repository by doing a Linq query, thus:</p> <pre><code>return Repository.For&lt;Transaction&gt;().Where(selector); </code></pre> <p>This can only work when the selector is <code>Func&lt;Transaction, bool&gt;</code>, hence my ultimate need is to turn the original expression, which would generate a <code>Func&lt;User, Transaction, bool&gt;</code> into <code>Func&lt;Transaction, bool&gt;</code>.</p> <p>This gives me an <code>IQueryable</code> collection where all the query operations are being done as Linq-to-NHibernate queries and thus the entire collection never gets loaded into memory (yes, I know you could frame a query that would actually make it do that, but I can catch those at code review time).</p> <p>Phew. Hope that makes sense.</p> <p>Anyone with leet Expression re-writing skills able to point me in the right direction?</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload