26
26
using Property = NHibernate . Mapping . Property ;
27
27
using NHibernate . SqlTypes ;
28
28
using System . Linq ;
29
+ using System . Linq . Expressions ;
29
30
using NHibernate . Bytecode ;
30
31
31
32
namespace NHibernate . Persister . Entity
@@ -258,6 +259,7 @@ public virtual void BindValues(DbCommand ps)
258
259
259
260
// This must be a Lazy<T>, because instances of this class must be thread safe.
260
261
private readonly Lazy < string [ ] > defaultUniqueKeyPropertyNamesForSelectId ;
262
+ private readonly Dictionary < string , int > propertyTableNumbersByNameAndSubclass = new Dictionary < string , int > ( ) ;
261
263
262
264
protected AbstractEntityPersister ( PersistentClass persistentClass , ICacheConcurrencyStrategy cache ,
263
265
ISessionFactoryImplementor factory )
@@ -443,6 +445,8 @@ protected AbstractEntityPersister(PersistentClass persistentClass, ICacheConcurr
443
445
definedBySubclass . Add ( isDefinedBySubclass ) ;
444
446
propNullables . Add ( prop . IsOptional || isDefinedBySubclass ) ; //TODO: is this completely correct?
445
447
types . Add ( prop . Type ) ;
448
+ propertyTableNumbersByNameAndSubclass [ prop . PersistentClass . EntityName + '.' + prop . Name ] =
449
+ persistentClass . GetJoinNumber ( prop ) ;
446
450
447
451
string [ ] cols = new string [ prop . ColumnSpan ] ;
448
452
string [ ] forms = new string [ prop . ColumnSpan ] ;
@@ -1109,6 +1113,16 @@ protected virtual bool IsIdOfTable(int property, int table)
1109
1113
1110
1114
protected abstract int GetSubclassPropertyTableNumber ( int i ) ;
1111
1115
1116
+ internal int GetSubclassPropertyTableNumber ( string propertyName , string entityName )
1117
+ {
1118
+ IType type = propertyMapping . ToType ( propertyName ) ;
1119
+ if ( type . IsAssociationType && ( ( IAssociationType ) type ) . UseLHSPrimaryKey )
1120
+ return 0 ;
1121
+ int tabnum ;
1122
+ propertyTableNumbersByNameAndSubclass . TryGetValue ( entityName + '.' + propertyName , out tabnum ) ;
1123
+ return tabnum ;
1124
+ }
1125
+
1112
1126
public abstract string FilterFragment ( string alias ) ;
1113
1127
1114
1128
protected internal virtual string DiscriminatorAlias
@@ -1161,11 +1175,18 @@ protected bool IsDeleteCallable(int j)
1161
1175
return deleteCallable [ j ] ;
1162
1176
}
1163
1177
1178
+ //Since 5.3
1179
+ [ Obsolete ( "This method has no more usage in NHibernate and will be removed in a future version." ) ]
1164
1180
protected virtual bool IsSubclassPropertyDeferred ( string propertyName , string entityName )
1165
1181
{
1166
1182
return false ;
1167
1183
}
1168
1184
1185
+ protected virtual bool IsPropertyDeferred ( int propertyIndex )
1186
+ {
1187
+ return false ;
1188
+ }
1189
+
1169
1190
protected virtual bool IsSubclassTableSequentialSelect ( int table )
1170
1191
{
1171
1192
return false ;
@@ -2590,15 +2611,23 @@ protected int Dehydrate(object id, object[] fields, object rowId, bool[] include
2590
2611
/// </summary>
2591
2612
public object [ ] Hydrate ( DbDataReader rs , object id , object obj , ILoadable rootLoadable ,
2592
2613
string [ ] [ ] suffixedPropertyColumns , bool allProperties , ISessionImplementor session )
2614
+ {
2615
+ return Hydrate ( rs , id , obj , suffixedPropertyColumns , allProperties , session ) ;
2616
+ }
2617
+
2618
+ /// <summary>
2619
+ /// Unmarshall the fields of a persistent instance from a result set,
2620
+ /// without resolving associations or collections
2621
+ /// </summary>
2622
+ public object [ ] Hydrate ( DbDataReader rs , object id , object obj ,
2623
+ string [ ] [ ] suffixedPropertyColumns , bool allProperties , ISessionImplementor session )
2593
2624
{
2594
2625
if ( log . IsDebugEnabled ( ) )
2595
2626
{
2596
2627
log . Debug ( "Hydrating entity: {0}" , MessageHelper . InfoString ( this , id , Factory ) ) ;
2597
2628
}
2598
2629
2599
- AbstractEntityPersister rootPersister = ( AbstractEntityPersister ) rootLoadable ;
2600
-
2601
- bool hasDeferred = rootPersister . HasSequentialSelect ;
2630
+ bool hasDeferred = HasSequentialSelect ;
2602
2631
DbCommand sequentialSelect = null ;
2603
2632
DbDataReader sequentialResultSet = null ;
2604
2633
bool sequentialSelectEmpty = false ;
@@ -2607,12 +2636,12 @@ public object[] Hydrate(DbDataReader rs, object id, object obj, ILoadable rootLo
2607
2636
{
2608
2637
if ( hasDeferred )
2609
2638
{
2610
- SqlString sql = rootPersister . GetSequentialSelect ( EntityName ) ;
2639
+ var sql = GetSequentialSelect ( ) ;
2611
2640
if ( sql != null )
2612
2641
{
2613
2642
//TODO: I am not so sure about the exception handling in this bit!
2614
2643
sequentialSelect = session . Batcher . PrepareCommand ( CommandType . Text , sql , IdentifierType . SqlTypes ( factory ) ) ;
2615
- rootPersister . IdentifierType . NullSafeSet ( sequentialSelect , id , 0 , session ) ;
2644
+ IdentifierType . NullSafeSet ( sequentialSelect , id , 0 , session ) ;
2616
2645
sequentialResultSet = session . Batcher . ExecuteReader ( sequentialSelect ) ;
2617
2646
if ( ! sequentialResultSet . Read ( ) )
2618
2647
{
@@ -2642,11 +2671,9 @@ public object[] Hydrate(DbDataReader rs, object id, object obj, ILoadable rootLo
2642
2671
}
2643
2672
}
2644
2673
2645
- string [ ] propNames = PropertyNames ;
2646
2674
IType [ ] types = PropertyTypes ;
2647
2675
object [ ] values = new object [ types . Length ] ;
2648
2676
bool [ ] laziness = PropertyLaziness ;
2649
- string [ ] propSubclassNames = SubclassPropertySubclassNameClosure ;
2650
2677
2651
2678
for ( int i = 0 ; i < types . Length ; i ++ )
2652
2679
{
@@ -2657,8 +2684,7 @@ public object[] Hydrate(DbDataReader rs, object id, object obj, ILoadable rootLo
2657
2684
else if ( allProperties || ! laziness [ i ] )
2658
2685
{
2659
2686
//decide which ResultSet to get the property value from:
2660
- bool propertyIsDeferred = hasDeferred
2661
- && rootPersister . IsSubclassPropertyDeferred ( propNames [ i ] , propSubclassNames [ i ] ) ;
2687
+ var propertyIsDeferred = hasDeferred && IsPropertyDeferred ( i ) ;
2662
2688
if ( propertyIsDeferred && sequentialSelectEmpty )
2663
2689
{
2664
2690
values [ i ] = null ;
@@ -2676,15 +2702,11 @@ public object[] Hydrate(DbDataReader rs, object id, object obj, ILoadable rootLo
2676
2702
}
2677
2703
}
2678
2704
2679
- if ( sequentialResultSet != null )
2680
- {
2681
- sequentialResultSet . Close ( ) ;
2682
- }
2683
-
2684
2705
return values ;
2685
2706
}
2686
2707
finally
2687
2708
{
2709
+ sequentialResultSet ? . Close ( ) ;
2688
2710
if ( sequentialSelect != null )
2689
2711
{
2690
2712
session . Batcher . CloseCommand ( sequentialSelect , sequentialResultSet ) ;
@@ -2702,11 +2724,18 @@ protected bool UseGetGeneratedKeys()
2702
2724
return Factory . Settings . IsGetGeneratedKeysEnabled ;
2703
2725
}
2704
2726
2727
+ //Since 5.3
2728
+ [ Obsolete ( "This method has no more usage in NHibernate and will be removed in a future version." ) ]
2705
2729
protected virtual SqlString GetSequentialSelect ( string entityName )
2706
2730
{
2707
2731
throw new NotSupportedException ( "no sequential selects" ) ;
2708
2732
}
2709
2733
2734
+ protected virtual SqlString GetSequentialSelect ( )
2735
+ {
2736
+ throw new NotSupportedException ( "no sequential select" ) ;
2737
+ }
2738
+
2710
2739
/// <summary>
2711
2740
/// Perform an SQL INSERT, and then retrieve a generated identifier.
2712
2741
/// </summary>
@@ -4491,5 +4520,49 @@ public string GetInfoString()
4491
4520
return MessageHelper . InfoString ( this ) ;
4492
4521
}
4493
4522
#endregion
4523
+
4524
+ internal SqlString GenerateSequentialSelect ( ILoadable persister )
4525
+ {
4526
+ //figure out which tables need to be fetched (only those that contains at least a no-lazy-property)
4527
+ AbstractEntityPersister subclassPersister = ( AbstractEntityPersister ) persister ;
4528
+ var tableNumbers = new HashSet < int > ( ) ;
4529
+ string [ ] props = subclassPersister . PropertyNames ;
4530
+ string [ ] classes = subclassPersister . PropertySubclassNames ;
4531
+ for ( int i = 0 ; i < props . Length ; i ++ )
4532
+ {
4533
+ int propTableNumber = GetSubclassPropertyTableNumber ( props [ i ] , classes [ i ] ) ;
4534
+ if ( IsSubclassTableSequentialSelect ( propTableNumber ) && ! IsSubclassTableLazy ( propTableNumber ) )
4535
+ {
4536
+ tableNumbers . Add ( propTableNumber ) ;
4537
+ }
4538
+ }
4539
+ if ( ( tableNumbers . Count == 0 ) )
4540
+ return null ;
4541
+
4542
+ //figure out which columns are needed (excludes lazy-properties)
4543
+ List < int > columnNumbers = new List < int > ( ) ;
4544
+ int [ ] columnTableNumbers = SubclassColumnTableNumberClosure ;
4545
+ for ( int i = 0 ; i < SubclassColumnClosure . Length ; i ++ )
4546
+ {
4547
+ if ( tableNumbers . Contains ( columnTableNumbers [ i ] ) )
4548
+ {
4549
+ columnNumbers . Add ( i ) ;
4550
+ }
4551
+ }
4552
+
4553
+ //figure out which formulas are needed (excludes lazy-properties)
4554
+ List < int > formulaNumbers = new List < int > ( ) ;
4555
+ int [ ] formulaTableNumbers = SubclassFormulaTableNumberClosure ;
4556
+ for ( int i = 0 ; i < SubclassFormulaTemplateClosure . Length ; i ++ )
4557
+ {
4558
+ if ( tableNumbers . Contains ( formulaTableNumbers [ i ] ) )
4559
+ {
4560
+ formulaNumbers . Add ( i ) ;
4561
+ }
4562
+ }
4563
+
4564
+ //render the SQL
4565
+ return RenderSelect ( tableNumbers . ToArray ( ) , columnNumbers . ToArray ( ) , formulaNumbers . ToArray ( ) ) ;
4566
+ }
4494
4567
}
4495
4568
}
0 commit comments