Skip to content

Commit 27ccc04

Browse files
committed
Improve performance of EntityFieldExpression class
1 parent c581a6a commit 27ccc04

File tree

1 file changed

+78
-64
lines changed

1 file changed

+78
-64
lines changed

Orm/Xtensive.Orm/Orm/Linq/Expressions/EntityFieldExpression.cs

Lines changed: 78 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,14 @@ namespace Xtensive.Orm.Linq.Expressions
1616
internal sealed class EntityFieldExpression : FieldExpression,
1717
IEntityExpression
1818
{
19-
public TypeInfo PersistentType { get; private set; }
20-
public List<PersistentFieldExpression> Fields { get; private set; }
21-
public KeyExpression Key { get; private set; }
19+
private readonly List<PersistentFieldExpression> fields;
20+
21+
public TypeInfo PersistentType { get; }
22+
public List<PersistentFieldExpression> Fields => fields;
23+
public KeyExpression Key { get; }
2224
public EntityExpression Entity { get; private set; }
2325

24-
public bool IsNullable
25-
{
26-
get { return Owner != null && Owner.IsNullable || Field.IsNullable; }
27-
}
26+
public bool IsNullable => (Owner != null && Owner.IsNullable) || Field.IsNullable;
2827

2928
public void RegisterEntityExpression(int offset)
3029
{
@@ -34,24 +33,27 @@ public void RegisterEntityExpression(int offset)
3433

3534
public override Expression Remap(int offset, Dictionary<Expression, Expression> processedExpressions)
3635
{
37-
if (!CanRemap)
36+
if (!CanRemap) {
3837
return this;
38+
}
3939

40-
Expression result;
41-
if (processedExpressions.TryGetValue(this, out result))
40+
if (processedExpressions.TryGetValue(this, out var result)) {
4241
return result;
42+
}
43+
44+
var newFields = new List<PersistentFieldExpression>(fields.Count);
45+
foreach (var field in fields) {
46+
// Do not convert to LINQ. We want to avoid a closure creation here.
47+
newFields.Add((PersistentFieldExpression) field.Remap(offset, processedExpressions));
48+
}
4349

44-
var fields = Fields
45-
.Select(f => f.Remap(offset, processedExpressions))
46-
.Cast<PersistentFieldExpression>()
47-
.ToList();
4850
var keyExpression = (KeyExpression) Key.Remap(offset, processedExpressions);
49-
var entity = Entity!=null
50-
? (EntityExpression) Entity.Remap(offset, processedExpressions)
51-
: null;
52-
result = new EntityFieldExpression(PersistentType, Field, fields, keyExpression.Mapping, keyExpression, entity, OuterParameter, DefaultIfEmpty);
53-
if (Owner==null)
51+
var entity = (EntityExpression) Entity?.Remap(offset, processedExpressions);
52+
result = new EntityFieldExpression(
53+
PersistentType, Field, newFields, keyExpression.Mapping, keyExpression, entity, OuterParameter, DefaultIfEmpty);
54+
if (Owner==null) {
5455
return result;
56+
}
5557

5658
processedExpressions.Add(this, result);
5759
Owner.Remap(offset, processedExpressions);
@@ -60,57 +62,68 @@ public override Expression Remap(int offset, Dictionary<Expression, Expression>
6062

6163
public override Expression Remap(int[] map, Dictionary<Expression, Expression> processedExpressions)
6264
{
63-
if (!CanRemap)
65+
if (!CanRemap) {
6466
return this;
67+
}
6568

66-
Expression result;
67-
if (processedExpressions.TryGetValue(this, out result))
69+
if (processedExpressions.TryGetValue(this, out var result)) {
6870
return result;
71+
}
6972

70-
List<PersistentFieldExpression> fields;
73+
var newFields = new List<PersistentFieldExpression>(fields.Count);
7174
using (new SkipOwnerCheckScope()) {
72-
fields = Fields
73-
.Select(f => f.Remap(map, processedExpressions))
74-
.Where(f => f!=null)
75-
.Cast<PersistentFieldExpression>()
76-
.ToList();
75+
foreach (var field in fields) {
76+
// Do not convert to LINQ. We want to avoid a closure creation here.
77+
var mappedField = (PersistentFieldExpression) field.Remap(map, processedExpressions);
78+
if (mappedField == null) {
79+
continue;
80+
}
81+
82+
newFields.Add(mappedField);
83+
}
7784
}
78-
if (fields.Count!=Fields.Count) {
85+
86+
if (newFields.Count!=Fields.Count) {
7987
processedExpressions.Add(this, null);
8088
return null;
8189
}
90+
8291
var keyExpression = (KeyExpression) Key.Remap(map, processedExpressions);
8392
EntityExpression entity;
84-
using (new SkipOwnerCheckScope())
85-
entity = Entity!=null
86-
? (EntityExpression) Entity.Remap(map, processedExpressions)
87-
: null;
88-
result = new EntityFieldExpression(PersistentType, Field, fields, keyExpression.Mapping, keyExpression, entity, OuterParameter, DefaultIfEmpty);
89-
if (Owner==null)
93+
using (new SkipOwnerCheckScope()) {
94+
entity = (EntityExpression) Entity?.Remap(map, processedExpressions);
95+
}
96+
97+
result = new EntityFieldExpression(
98+
PersistentType, Field, newFields, keyExpression.Mapping, keyExpression, entity, OuterParameter, DefaultIfEmpty);
99+
if (Owner==null) {
90100
return result;
101+
}
91102

92103
processedExpressions.Add(this, result);
93104
Owner.Remap(map, processedExpressions);
94105
return result;
95106
}
96107

97-
public override Expression BindParameter(ParameterExpression parameter, Dictionary<Expression, Expression> processedExpressions)
108+
public override Expression BindParameter(
109+
ParameterExpression parameter, Dictionary<Expression, Expression> processedExpressions)
98110
{
99-
Expression result;
100-
if (processedExpressions.TryGetValue(this, out result))
111+
if (processedExpressions.TryGetValue(this, out var result)) {
101112
return result;
113+
}
102114

103-
var fields = Fields
104-
.Select(f => f.BindParameter(parameter, processedExpressions))
105-
.Cast<PersistentFieldExpression>()
106-
.ToList();
115+
var newFields = new List<PersistentFieldExpression>(fields.Count);
116+
foreach (var field in fields) {
117+
// Do not convert to LINQ. We want to avoid a closure creation here.
118+
newFields.Add((PersistentFieldExpression) field.BindParameter(parameter, processedExpressions));
119+
}
107120
var keyExpression = (KeyExpression) Key.BindParameter(parameter, processedExpressions);
108-
var entity = Entity!=null
109-
? (EntityExpression) Entity.BindParameter(parameter, processedExpressions)
110-
: null;
111-
result = new EntityFieldExpression(PersistentType, Field, fields, Mapping, keyExpression, entity, parameter, DefaultIfEmpty);
112-
if (Owner==null)
121+
var entity = (EntityExpression) Entity?.BindParameter(parameter, processedExpressions);
122+
result = new EntityFieldExpression(
123+
PersistentType, Field, newFields, Mapping, keyExpression, entity, parameter, DefaultIfEmpty);
124+
if (Owner==null) {
113125
return result;
126+
}
114127

115128
processedExpressions.Add(this, result);
116129
Owner.BindParameter(parameter, processedExpressions);
@@ -119,21 +132,22 @@ public override Expression BindParameter(ParameterExpression parameter, Dictiona
119132

120133
public override Expression RemoveOuterParameter(Dictionary<Expression, Expression> processedExpressions)
121134
{
122-
Expression result;
123-
if (processedExpressions.TryGetValue(this, out result))
135+
if (processedExpressions.TryGetValue(this, out var result)) {
124136
return result;
137+
}
125138

126-
var fields = Fields
127-
.Select(f => f.RemoveOuterParameter(processedExpressions))
128-
.Cast<PersistentFieldExpression>()
129-
.ToList();
139+
var newFields = new List<PersistentFieldExpression>(fields.Count);
140+
foreach (var field in fields) {
141+
// Do not convert to LINQ. We want to avoid a closure creation here.
142+
newFields.Add((PersistentFieldExpression) field.RemoveOuterParameter(processedExpressions));
143+
}
130144
var keyExpression = (KeyExpression) Key.RemoveOuterParameter(processedExpressions);
131-
var entity = Entity!=null
132-
? (EntityExpression) Entity.RemoveOuterParameter(processedExpressions)
133-
: null;
134-
result = new EntityFieldExpression(PersistentType, Field, fields, Mapping, keyExpression, entity, null, DefaultIfEmpty);
135-
if (Owner==null)
145+
var entity = (EntityExpression) Entity?.RemoveOuterParameter(processedExpressions);
146+
result = new EntityFieldExpression(
147+
PersistentType, Field, newFields, Mapping, keyExpression, entity, null, DefaultIfEmpty);
148+
if (Owner==null) {
136149
return result;
150+
}
137151

138152
processedExpressions.Add(this, result);
139153
Owner.RemoveOuterParameter(processedExpressions);
@@ -173,18 +187,18 @@ private static PersistentFieldExpression BuildNestedFieldExpression(FieldInfo ne
173187
// Constructors
174188

175189
private EntityFieldExpression(
176-
TypeInfo persistentType,
177-
FieldInfo field,
190+
TypeInfo persistentType,
191+
FieldInfo field,
178192
List<PersistentFieldExpression> fields,
179193
in Segment<int> mapping,
180-
KeyExpression key,
181-
EntityExpression entity,
182-
ParameterExpression parameterExpression,
194+
KeyExpression key,
195+
EntityExpression entity,
196+
ParameterExpression parameterExpression,
183197
bool defaultIfEmpty)
184198
: base(ExtendedExpressionType.EntityField, field, mapping, parameterExpression, defaultIfEmpty)
185199
{
186200
PersistentType = persistentType;
187-
Fields = fields;
201+
this.fields = fields;
188202
Key = key;
189203
Entity = entity;
190204
}

0 commit comments

Comments
 (0)