title: Cacheable(), FetchMany() and ToFuture() in same NHibernate Linq query
body: <p>Having a situation similar to the following example:</p>
  
  <p>1 parent entity <code>Employee</code> having 2 child collections: <code>Addresses</code> and <code>Phones</code></p>
  
  <p>I need to retrieve in a <code>single roundtrip</code> all employees with their Addresses and Phones initialized and also <code>cache the query</code> that achieves that in level 2 cache using <code>Cacheable()</code>.</p>
  
  <p>Using:</p>
  
  <pre><code>var baseQuery = session
      .Query&lt;Employee&gt;()
      .Cacheable();
  
  baseQuery
      .FetchMany(e =&gt; e.Addresses)
      .ToFuture();
  
  var list = baseQuery
      .FetchMany(e =&gt; e.Phones)
      .ToFuture()
      .ToList();
  </code></pre>
  
  <p>should work, but I get the following exception:</p>
  
  <pre><code>NHibernate.PropertyAccessException
  </code></pre>
  
  <p>Message:</p>
  
  <pre><code>Exception occurred getter of NHibernateTest.Objects.Entity`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]].Id
  </code></pre>
  
  <p>StackTrace:</p>
  
  <pre><code>at NHibernate.Properties.BasicPropertyAccessor.BasicGetter.Get(Object target) in p:\nhibernate-core\src\NHibernate\Properties\BasicPropertyAccessor.cs:line 213
  at NHibernate.Tuple.Entity.AbstractEntityTuplizer.GetIdentifier(Object entity) in p:\nhibernate-core\src\NHibernate\Tuple\Entity\AbstractEntityTuplizer.cs:line 139
  at NHibernate.Persister.Entity.AbstractEntityPersister.GetIdentifier(Object obj, EntityMode entityMode) in p:\nhibernate-core\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 3890
  at NHibernate.Persister.Entity.AbstractEntityPersister.IsTransient(Object entity, ISessionImplementor session) in p:\nhibernate-core\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs:line 3676
  at NHibernate.Engine.ForeignKeys.IsTransient(String entityName, Object entity, Nullable`1 assumed, ISessionImplementor session) in p:\nhibernate-core\src\NHibernate\Engine\ForeignKeys.cs:line 194
  at NHibernate.Engine.ForeignKeys.GetEntityIdentifierIfNotUnsaved(String entityName, Object entity, ISessionImplementor session) in p:\nhibernate-core\src\NHibernate\Engine\ForeignKeys.cs:line 250
  at NHibernate.Type.ManyToOneType.Disassemble(Object value, ISessionImplementor session, Object owner) in p:\nhibernate-core\src\NHibernate\Type\ManyToOneType.cs:line 137
  at NHibernate.Impl.MultipleQueriesCacheAssembler.Disassemble(Object value, ISessionImplementor session, Object owner) in p:\nhibernate-core\src\NHibernate\Impl\MultipleQueriesCacheAssembler.cs:line 33
  at NHibernate.Cache.StandardQueryCache.Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, Boolean isNaturalKeyLookup, ISessionImplementor session) in p:\nhibernate-core\src\NHibernate\Cache\StandardQueryCache.cs:line 74
  at NHibernate.Impl.MultiQueryImpl.ListUsingQueryCache() in p:\nhibernate-core\src\NHibernate\Impl\MultiQueryImpl.cs:line 749
  at NHibernate.Impl.MultiQueryImpl.List() in p:\nhibernate-core\src\NHibernate\Impl\MultiQueryImpl.cs:line 415
  at NHibernate.Impl.FutureQueryBatch.GetResultsFrom(IMultiQuery multiApproach) in p:\nhibernate-core\src\NHibernate\Impl\FutureQueryBatch.cs:line 24
  at NHibernate.Impl.FutureBatch`2.GetResults() in p:\nhibernate-core\src\NHibernate\Impl\FutureBatch.cs:line 73
  at NHibernate.Impl.FutureBatch`2.get_Results() in p:\nhibernate-core\src\NHibernate\Impl\FutureBatch.cs:line 31
  at NHibernate.Impl.FutureBatch`2.GetCurrentResult[TResult](Int32 currentIndex) in p:\nhibernate-core\src\NHibernate\Impl\FutureBatch.cs:line 79
  at NHibernate.Impl.FutureBatch`2.&lt;&gt;c__DisplayClass4`1.&lt;GetEnumerator&gt;b__3() in p:\nhibernate-core\src\NHibernate\Impl\FutureBatch.cs:line 63
  at NHibernate.Impl.DelayedEnumerator`1.&lt;get_Enumerable&gt;d__0.MoveNext() in p:\nhibernate-core\src\NHibernate\Impl\DelayedEnumerator.cs:line 26
  at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
  at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
  at Tests.Tests.CacheableFetchManyAndToFutureTest() in D:\somepath\Tests.cs:line 262
  </code></pre>
  
  <p>Inner exception:</p>
  
  <pre><code>System.Reflection.TargetException
  </code></pre>
  
  <p>Message:</p>
  
  <pre><code>Object does not match target type.
  </code></pre>
  
  <p>StackTrace:</p>
  
  <pre><code>at System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
  at System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
  at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
  at System.Reflection.RuntimePropertyInfo.GetValue(Object obj, Object[] index)
  at NHibernate.Properties.BasicPropertyAccessor.BasicGetter.Get(Object target) in p:\nhibernate-core\src\NHibernate\Properties\BasicPropertyAccessor.cs:line 207
  </code></pre>
  
  <p>Querying as following does not work since it generates a Cartesian product as a result which is ineffective. Having 1 employee with 2 addresses and 2 phones, each unique address and phone in the database would appear twice in Addresses and Phones collections. Making the results distinct after they are received at server is not a good option.</p>
  
  <pre><code>var list = session
      .Query&lt;Employee&gt;()
      .FetchMany(e =&gt; e.Addresses)
      .FetchMany(e =&gt; e.Phones)
      .Cacheable()
      .ToList();
  </code></pre>
  
  <p>Querying only with <code>FetchMany()</code> and <code>ToFuture()</code> (no <code>Cacheable()</code>) will return correctly all the employees with the corresponding addresses and phones (no duplicates) in 1 roundtrip but since the query is not cached there is no optimization for future identical requests:</p>
  
  <pre><code>var baseQuery = session
      .Query&lt;Employee&gt;();
  
  baseQuery
      .FetchMany(e =&gt; e.Addresses)
      .ToFuture();
  
  var list = baseQuery
      .FetchMany(e =&gt; e.Phones)
      .ToFuture()
      .ToList();
  </code></pre>
  
  <p>TLDR: How to retrieve all employees with addresses and phones initialized in a single roundtrip and have the query cached in level 2 cache? Thank you for replies!</p>