77using System ;
88using System . Collections . Generic ;
99using System . Linq . Expressions ;
10- using Xtensive . Collections ;
1110using Xtensive . Core ;
1211using Xtensive . Orm . Model ;
1312using System . Linq ;
1413
15-
1614namespace Xtensive . Orm . Linq . Expressions
1715{
1816 internal sealed class StructureExpression : ParameterizedExpression ,
1917 IPersistentExpression
2018 {
2119 private List < PersistentFieldExpression > fields ;
20+ private bool isNullable ;
21+
2222 internal Segment < int > Mapping ;
23- public TypeInfo PersistentType { get ; private set ; }
23+ public TypeInfo PersistentType { get ; }
2424
25- public bool IsNullable { get ; set ; }
25+ public bool IsNullable => isNullable ;
2626
2727 public List < PersistentFieldExpression > Fields
2828 {
29- get { return fields ; }
30- private set
31- {
29+ get => fields ;
30+ private set {
3231 fields = value ;
33- foreach ( var fieldExpression in fields . OfType < FieldExpression > ( ) )
32+ foreach ( var fieldExpression in fields . OfType < FieldExpression > ( ) ) {
3433 fieldExpression . Owner = this ;
34+ }
3535 }
3636 }
3737
3838 public Expression Remap ( int offset , Dictionary < Expression , Expression > processedExpressions )
3939 {
40- if ( ! CanRemap )
40+ if ( ! CanRemap ) {
4141 return this ;
42+ }
4243
43- Expression value ;
44- if ( processedExpressions . TryGetValue ( this , out value ) )
44+ if ( processedExpressions . TryGetValue ( this , out var value ) ) {
4545 return value ;
46+ }
4647
4748 var mapping = new Segment < int > ( Mapping . Offset + offset , Mapping . Length ) ;
4849 var result = new StructureExpression ( PersistentType , mapping ) ;
4950 processedExpressions . Add ( this , result ) ;
50- var processedFields = Fields
51- . Select ( f => f . Remap ( offset , processedExpressions ) )
52- . Cast < PersistentFieldExpression > ( )
53- . ToList ( ) ;
51+ var processedFields = new List < PersistentFieldExpression > ( fields . Count ) ;
52+ foreach ( var field in fields ) {
53+ // Do not convert to LINQ. We intentionally avoiding closure creation here
54+ processedFields . Add ( ( PersistentFieldExpression ) field . Remap ( offset , processedExpressions ) ) ;
55+ }
5456 result . Fields = processedFields ;
55- result . IsNullable = IsNullable ;
57+ result . isNullable = isNullable ;
5658 return result ;
5759 }
5860
5961
6062 public Expression Remap ( int [ ] map , Dictionary < Expression , Expression > processedExpressions )
6163 {
62- if ( ! CanRemap )
64+ if ( ! CanRemap ) {
6365 return this ;
66+ }
6467
65- Expression value ;
66- if ( processedExpressions . TryGetValue ( this , out value ) )
68+ if ( processedExpressions . TryGetValue ( this , out var value ) ) {
6769 return value ;
70+ }
6871
69- var result = new StructureExpression ( PersistentType , default ( Segment < int > ) ) ;
72+ var result = new StructureExpression ( PersistentType , default ) ;
7073 processedExpressions . Add ( this , result ) ;
71- var processedFields = Fields
72- . Select ( f => f . Remap ( map , processedExpressions ) )
73- . Where ( f => f != null )
74- . Cast < PersistentFieldExpression > ( )
75- . ToList ( ) ;
74+ var processedFields = new List < PersistentFieldExpression > ( fields . Count ) ;
75+ var offset = int . MaxValue ;
76+ foreach ( var field in fields ) {
77+ var mappedField = ( PersistentFieldExpression ) field . Remap ( map , processedExpressions ) ;
78+ if ( mappedField == null ) {
79+ continue ;
80+ }
81+
82+ var mappingOffset = mappedField . Mapping . Offset ;
83+ if ( mappingOffset < offset ) {
84+ offset = mappingOffset ;
85+ }
86+
87+ processedFields . Add ( mappedField ) ;
88+ }
89+
7690 if ( processedFields . Count == 0 ) {
7791 processedExpressions [ this ] = null ;
7892 return null ;
7993 }
80- var length = processedFields . Select ( f => f . Mapping . Offset ) . Distinct ( ) . Count ( ) ;
81- var offset = processedFields . Min ( f => f . Mapping . Offset ) ;
82- result . Mapping = new Segment < int > ( offset , length ) ;
83- result . Fields = processedFields ;
84- result . IsNullable = IsNullable ;
94+
95+ result . Mapping = new Segment < int > ( offset , processedFields . Count ) ;
96+ result . Fields = processedFields ;
97+ result . isNullable = isNullable ;
8598 return result ;
8699 }
87100
88101 public Expression BindParameter ( ParameterExpression parameter , Dictionary < Expression , Expression > processedExpressions )
89102 {
90- Expression value ;
91- if ( processedExpressions . TryGetValue ( this , out value ) )
103+ if ( processedExpressions . TryGetValue ( this , out var value ) ) {
92104 return value ;
105+ }
93106
94107 var result = new StructureExpression ( PersistentType , Mapping ) ;
95108 processedExpressions . Add ( this , result ) ;
96- var processedFields = Fields
97- . Select ( f => f . BindParameter ( parameter , processedExpressions ) )
98- . Cast < PersistentFieldExpression > ( )
99- . ToList ( ) ;
109+ var processedFields = new List < PersistentFieldExpression > ( fields . Count ) ;
110+ foreach ( var field in fields ) {
111+ // Do not convert to LINQ. We intentionally avoiding closure creation here
112+ processedFields . Add ( ( PersistentFieldExpression ) field . BindParameter ( parameter , processedExpressions ) ) ;
113+ }
100114 result . Fields = processedFields ;
101115 return result ;
102116 }
103117
104118 public Expression RemoveOuterParameter ( Dictionary < Expression , Expression > processedExpressions )
105119 {
106- Expression value ;
107- if ( processedExpressions . TryGetValue ( this , out value ) )
120+ if ( processedExpressions . TryGetValue ( this , out var value ) ) {
108121 return value ;
122+ }
109123
110124 var result = new StructureExpression ( PersistentType , Mapping ) ;
111125 processedExpressions . Add ( this , result ) ;
112- var processedFields = Fields
113- . Select ( f => f . RemoveOuterParameter ( processedExpressions ) )
114- . Cast < PersistentFieldExpression > ( )
115- . ToList ( ) ;
126+ var processedFields = new List < PersistentFieldExpression > ( fields . Count ) ;
127+ foreach ( var field in fields ) {
128+ // Do not convert to LINQ. We intentionally avoiding closure creation here
129+ processedFields . Add ( ( PersistentFieldExpression ) field . RemoveOuterParameter ( processedExpressions ) ) ;
130+ }
131+
116132 result . Fields = processedFields ;
117133 return result ;
118134 }
@@ -127,12 +143,12 @@ public static StructureExpression CreateLocalCollectionStructure(TypeInfo typeIn
127143 var destinationFields = new List < PersistentFieldExpression > ( sourceFields . Count ) ;
128144 var result = new StructureExpression ( typeInfo , mapping ) { Fields = destinationFields } ;
129145 foreach ( var field in sourceFields ) {
146+ // Do not convert to LINQ. We intentionally avoiding closure creation here
130147 destinationFields . Add ( BuildNestedFieldExpression ( field , mapping . Offset ) ) ;
131148 }
132149 return result ;
133150 }
134151
135- // ReSharper disable RedundantNameQualifier
136152 private static PersistentFieldExpression BuildNestedFieldExpression ( FieldInfo nestedField , int offset )
137153 {
138154 if ( nestedField . IsPrimitive )
@@ -143,8 +159,6 @@ private static PersistentFieldExpression BuildNestedFieldExpression(FieldInfo ne
143159 return EntityFieldExpression . CreateEntityField ( nestedField , offset ) ;
144160 throw new NotSupportedException ( string . Format ( Strings . ExNestedFieldXIsNotSupported , nestedField . Attributes ) ) ;
145161 }
146- // ReSharper restore RedundantNameQualifier
147-
148162
149163 // Constructors
150164
@@ -153,7 +167,7 @@ private StructureExpression(
153167 in Segment < int > mapping )
154168 : base ( ExtendedExpressionType . Structure , persistentType . UnderlyingType , null , false )
155169 {
156- this . Mapping = mapping ;
170+ Mapping = mapping ;
157171 PersistentType = persistentType ;
158172 }
159173 }
0 commit comments