Skip to content

Commit ba0f915

Browse files
committed
Push down Hydrate specific to SingleTableEntityPersister
1 parent 4f8c972 commit ba0f915

File tree

4 files changed

+265
-150
lines changed

4 files changed

+265
-150
lines changed

src/NHibernate/Async/Persister/Entity/AbstractEntityPersister.cs

+5-66
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ public Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj, ILoad
354354
/// Unmarshall the fields of a persistent instance from a result set,
355355
/// without resolving associations or collections
356356
/// </summary>
357-
public async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj,
357+
public virtual async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj,
358358
string[][] suffixedPropertyColumns, bool allProperties, ISessionImplementor session, CancellationToken cancellationToken)
359359
{
360360
cancellationToken.ThrowIfCancellationRequested();
@@ -363,53 +363,11 @@ public async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj,
363363
log.Debug("Hydrating entity: {0}", MessageHelper.InfoString(this, id, Factory));
364364
}
365365

366-
bool hasDeferred = HasSequentialSelect;
367-
DbCommand sequentialSelect = null;
368-
DbDataReader sequentialResultSet = null;
369-
bool sequentialSelectEmpty = false;
370366
using (session.BeginProcess())
371-
try
372367
{
373-
if (hasDeferred)
374-
{
375-
var sql = GetSequentialSelect();
376-
if (sql != null)
377-
{
378-
//TODO: I am not so sure about the exception handling in this bit!
379-
sequentialSelect = await (session.Batcher.PrepareCommandAsync(CommandType.Text, sql, IdentifierType.SqlTypes(factory), cancellationToken)).ConfigureAwait(false);
380-
await (IdentifierType.NullSafeSetAsync(sequentialSelect, id, 0, session, cancellationToken)).ConfigureAwait(false);
381-
sequentialResultSet = await (session.Batcher.ExecuteReaderAsync(sequentialSelect, cancellationToken)).ConfigureAwait(false);
382-
if (!await (sequentialResultSet.ReadAsync(cancellationToken)).ConfigureAwait(false))
383-
{
384-
// TODO: Deal with the "optional" attribute in the <join> mapping;
385-
// this code assumes that optional defaults to "true" because it
386-
// doesn't actually seem to work in the fetch="join" code
387-
//
388-
// Note that actual proper handling of optional-ality here is actually
389-
// more involved than this patch assumes. Remember that we might have
390-
// multiple <join/> mappings associated with a single entity. Really
391-
// a couple of things need to happen to properly handle optional here:
392-
// 1) First and foremost, when handling multiple <join/>s, we really
393-
// should be using the entity root table as the driving table;
394-
// another option here would be to choose some non-optional joined
395-
// table to use as the driving table. In all likelihood, just using
396-
// the root table is much simplier
397-
// 2) Need to add the FK columns corresponding to each joined table
398-
// to the generated select list; these would then be used when
399-
// iterating the result set to determine whether all non-optional
400-
// data is present
401-
// My initial thoughts on the best way to deal with this would be
402-
// to introduce a new SequentialSelect abstraction that actually gets
403-
// generated in the persisters (ok, SingleTable...) and utilized here.
404-
// It would encapsulated all this required optional-ality checking...
405-
sequentialSelectEmpty = true;
406-
}
407-
}
408-
}
409-
410-
IType[] types = PropertyTypes;
411-
object[] values = new object[types.Length];
412-
bool[] laziness = PropertyLaziness;
368+
var types = PropertyTypes;
369+
var values = new object[types.Length];
370+
var laziness = PropertyLaziness;
413371

414372
for (int i = 0; i < types.Length; i++)
415373
{
@@ -419,18 +377,7 @@ public async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj,
419377
}
420378
else if (allProperties || !laziness[i])
421379
{
422-
//decide which ResultSet to get the property value from:
423-
var propertyIsDeferred = hasDeferred && IsPropertyDeferred(i);
424-
if (propertyIsDeferred && sequentialSelectEmpty)
425-
{
426-
values[i] = null;
427-
}
428-
else
429-
{
430-
var propertyResultSet = propertyIsDeferred ? sequentialResultSet : rs;
431-
string[] cols = propertyIsDeferred ? propertyColumnAliases[i] : suffixedPropertyColumns[i];
432-
values[i] = await (types[i].HydrateAsync(propertyResultSet, cols, session, obj, cancellationToken)).ConfigureAwait(false);
433-
}
380+
values[i] = await (types[i].HydrateAsync(rs, suffixedPropertyColumns[i], session, obj, cancellationToken)).ConfigureAwait(false);
434381
}
435382
else
436383
{
@@ -440,14 +387,6 @@ public async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj,
440387

441388
return values;
442389
}
443-
finally
444-
{
445-
sequentialResultSet?.Close();
446-
if (sequentialSelect != null)
447-
{
448-
session.Batcher.CloseCommand(sequentialSelect, sequentialResultSet);
449-
}
450-
}
451390
}
452391

453392
/// <summary>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using System;
12+
using System.Collections.Generic;
13+
using System.Data;
14+
using System.Data.Common;
15+
using System.Text;
16+
using System.Linq;
17+
using NHibernate.Cache;
18+
using NHibernate.Engine;
19+
using NHibernate.Impl;
20+
using NHibernate.Intercept;
21+
using NHibernate.Mapping;
22+
using NHibernate.Properties;
23+
using NHibernate.SqlCommand;
24+
using NHibernate.Type;
25+
using NHibernate.Util;
26+
27+
namespace NHibernate.Persister.Entity
28+
{
29+
using System.Threading.Tasks;
30+
using System.Threading;
31+
public partial class SingleTableEntityPersister : AbstractEntityPersister, IQueryable
32+
{
33+
34+
public override async Task<object[]> HydrateAsync(DbDataReader rs, object id, object obj, string[][] suffixedPropertyColumns, bool allProperties, ISessionImplementor session, CancellationToken cancellationToken)
35+
{
36+
cancellationToken.ThrowIfCancellationRequested();
37+
if (!hasSequentialSelects)
38+
{
39+
return await (base.HydrateAsync(rs, id, obj, suffixedPropertyColumns, allProperties, session, cancellationToken)).ConfigureAwait(false);
40+
}
41+
42+
if (log.IsDebugEnabled())
43+
{
44+
log.Debug("Hydrating entity: {0}", MessageHelper.InfoString(this, id, Factory));
45+
}
46+
47+
DbCommand sequentialSelect = null;
48+
DbDataReader sequentialResultSet = null;
49+
bool sequentialSelectEmpty = false;
50+
using (session.BeginProcess())
51+
{
52+
try
53+
{
54+
var sql = GetSequentialSelect();
55+
if (sql != null)
56+
{
57+
//TODO: I am not so sure about the exception handling in this bit!
58+
sequentialSelect = await (session.Batcher.PrepareCommandAsync(
59+
CommandType.Text,
60+
sql,
61+
IdentifierType.SqlTypes(Factory), cancellationToken)).ConfigureAwait(false);
62+
await (IdentifierType.NullSafeSetAsync(sequentialSelect, id, 0, session, cancellationToken)).ConfigureAwait(false);
63+
sequentialResultSet = await (session.Batcher.ExecuteReaderAsync(sequentialSelect, cancellationToken)).ConfigureAwait(false);
64+
if (!await (sequentialResultSet.ReadAsync(cancellationToken)).ConfigureAwait(false))
65+
{
66+
// TODO: Deal with the "optional" attribute in the <join> mapping;
67+
// this code assumes that optional defaults to "true" because it
68+
// doesn't actually seem to work in the fetch="join" code
69+
//
70+
// Note that actual proper handling of optional-ality here is actually
71+
// more involved than this patch assumes. Remember that we might have
72+
// multiple <join/> mappings associated with a single entity. Really
73+
// a couple of things need to happen to properly handle optional here:
74+
// 1) First and foremost, when handling multiple <join/>s, we really
75+
// should be using the entity root table as the driving table;
76+
// another option here would be to choose some non-optional joined
77+
// table to use as the driving table. In all likelihood, just using
78+
// the root table is much simplier
79+
// 2) Need to add the FK columns corresponding to each joined table
80+
// to the generated select list; these would then be used when
81+
// iterating the result set to determine whether all non-optional
82+
// data is present
83+
// My initial thoughts on the best way to deal with this would be
84+
// to introduce a new SequentialSelect abstraction that actually gets
85+
// generated in the persisters (ok, SingleTable...) and utilized here.
86+
// It would encapsulated all this required optional-ality checking...
87+
sequentialSelectEmpty = true;
88+
}
89+
}
90+
91+
IType[] types = PropertyTypes;
92+
object[] values = new object[types.Length];
93+
bool[] laziness = PropertyLaziness;
94+
95+
for (int i = 0; i < types.Length; i++)
96+
{
97+
if (!propertySelectable[i])
98+
{
99+
values[i] = BackrefPropertyAccessor.Unknown;
100+
}
101+
else if (allProperties || !laziness[i])
102+
{
103+
//decide which ResultSet to get the property value from:
104+
var propertyIsDeferred = subclassTableSequentialSelect[GetSubclassPropertyTableNumber(i)];
105+
if (propertyIsDeferred && sequentialSelectEmpty)
106+
{
107+
values[i] = null;
108+
}
109+
else
110+
{
111+
var propertyResultSet = propertyIsDeferred ? sequentialResultSet : rs;
112+
string[] cols = propertyIsDeferred
113+
? propertyColumnAliases[i]
114+
: suffixedPropertyColumns[i];
115+
values[i] = await (types[i].HydrateAsync(propertyResultSet, cols, session, obj, cancellationToken)).ConfigureAwait(false);
116+
}
117+
}
118+
else
119+
{
120+
values[i] = LazyPropertyInitializer.UnfetchedProperty;
121+
}
122+
}
123+
124+
return values;
125+
}
126+
finally
127+
{
128+
sequentialResultSet?.Close();
129+
if (sequentialSelect != null)
130+
{
131+
session.Batcher.CloseCommand(sequentialSelect, sequentialResultSet);
132+
}
133+
}
134+
}
135+
}
136+
}
137+
}

0 commit comments

Comments
 (0)