Skip to content

Commit c581a6a

Browse files
committed
Improve performance of EntityExpression class
1 parent d076a71 commit c581a6a

File tree

1 file changed

+88
-58
lines changed

1 file changed

+88
-58
lines changed

Orm/Xtensive.Orm/Orm/Linq/Expressions/EntityExpression.cs

Lines changed: 88 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -19,94 +19,115 @@ internal class EntityExpression : ParameterizedExpression,
1919
{
2020
private List<PersistentFieldExpression> fields;
2121

22-
public TypeInfo PersistentType { get; private set; }
22+
public TypeInfo PersistentType { get; }
2323

24-
public KeyExpression Key { get; private set; }
24+
public KeyExpression Key { get; }
2525

2626
public List<PersistentFieldExpression> Fields
2727
{
28-
get { return fields; }
29-
private set
30-
{
28+
get => fields;
29+
private set {
3130
fields = value;
32-
var fieldExpressions = fields.OfType<FieldExpression>();
33-
foreach (var fieldExpression in fieldExpressions)
31+
foreach (var fieldExpression in fields.OfType<FieldExpression>()) {
3432
fieldExpression.Owner = this;
33+
}
3534
}
3635
}
3736

3837
public bool IsNullable { get; set; }
3938

4039
public Expression Remap(int offset, Dictionary<Expression, Expression> processedExpressions)
4140
{
42-
if (!CanRemap)
41+
if (!CanRemap) {
4342
return this;
44-
Expression value;
45-
if (processedExpressions.TryGetValue(this, out value))
43+
}
44+
45+
if (processedExpressions.TryGetValue(this, out var value)) {
4646
return value;
47+
}
4748

4849
var keyExpression = (KeyExpression) Key.Remap(offset, processedExpressions);
4950
var result = new EntityExpression(PersistentType, keyExpression, OuterParameter, DefaultIfEmpty);
5051
processedExpressions.Add(this, result);
5152
result.IsNullable = IsNullable;
52-
result.Fields = Fields
53-
.Select(f => f.Remap(offset, processedExpressions))
54-
.Cast<PersistentFieldExpression>()
55-
.ToList();
53+
var processedFields = new List<PersistentFieldExpression>(fields.Count);
54+
foreach (var field in fields) {
55+
// Do not convert to LINQ. We want to avoid a closure creation here.
56+
processedFields.Add((PersistentFieldExpression) field.Remap(offset, processedExpressions));
57+
}
58+
59+
result.Fields = processedFields;
5660
return result;
5761
}
5862

5963
public Expression Remap(int[] map, Dictionary<Expression, Expression> processedExpressions)
6064
{
61-
if (!CanRemap)
65+
if (!CanRemap) {
6266
return this;
63-
Expression value;
64-
if (processedExpressions.TryGetValue(this, out value))
67+
}
68+
69+
if (processedExpressions.TryGetValue(this, out var value)) {
6570
return value;
71+
}
6672

6773
var keyExpression = (KeyExpression) Key.Remap(map, processedExpressions);
68-
if (keyExpression==null)
74+
if (keyExpression==null) {
6975
return null;
76+
}
77+
7078
var result = new EntityExpression(PersistentType, keyExpression, OuterParameter, DefaultIfEmpty);
7179
processedExpressions.Add(this, result);
7280
result.IsNullable = IsNullable;
73-
result.Fields = Fields
74-
.Select(f => f.Remap(map, processedExpressions))
75-
.Where(f => f!=null)
76-
.Cast<PersistentFieldExpression>()
77-
.ToList();
81+
var processedFields = new List<PersistentFieldExpression>(fields.Count);
82+
foreach (var field in fields) {
83+
// Do not convert to LINQ. We want to avoid a closure creation here.
84+
var mappedField = (PersistentFieldExpression) field.Remap(map, processedExpressions);
85+
if (mappedField == null) {
86+
continue;
87+
}
88+
89+
processedFields.Add(mappedField);
90+
}
91+
92+
result.Fields = processedFields;
7893
return result;
7994
}
8095

8196
public Expression BindParameter(ParameterExpression parameter, Dictionary<Expression, Expression> processedExpressions)
8297
{
83-
Expression value;
84-
if (processedExpressions.TryGetValue(this, out value))
98+
if (processedExpressions.TryGetValue(this, out var value)) {
8599
return value;
100+
}
86101

87102
var keyExpression = (KeyExpression) Key.BindParameter(parameter, processedExpressions);
88103
var result = new EntityExpression(PersistentType, keyExpression, parameter, DefaultIfEmpty);
89104
processedExpressions.Add(this, result);
90-
result.Fields = Fields
91-
.Select(f => f.BindParameter(parameter, processedExpressions))
92-
.Cast<PersistentFieldExpression>()
93-
.ToList();
105+
var processedFields = new List<PersistentFieldExpression>(fields.Count);
106+
foreach (var field in fields) {
107+
// Do not convert to LINQ. We want to avoid a closure creation here.
108+
processedFields.Add((PersistentFieldExpression) field.BindParameter(parameter, processedExpressions));
109+
}
110+
111+
result.Fields = processedFields;
94112
return result;
95113
}
96114

97115
public Expression RemoveOuterParameter(Dictionary<Expression, Expression> processedExpressions)
98116
{
99-
Expression value;
100-
if (processedExpressions.TryGetValue(this, out value))
117+
if (processedExpressions.TryGetValue(this, out var value)) {
101118
return value;
119+
}
102120

103121
var keyExpression = (KeyExpression) Key.RemoveOuterParameter(processedExpressions);
104122
var result = new EntityExpression(PersistentType, keyExpression, null, DefaultIfEmpty);
105123
processedExpressions.Add(this, result);
106-
result.Fields = Fields
107-
.Select(f => f.RemoveOuterParameter(processedExpressions))
108-
.Cast<PersistentFieldExpression>()
109-
.ToList();
124+
var processedFields = new List<PersistentFieldExpression>(fields.Count);
125+
foreach (var field in fields) {
126+
// Do not convert to LINQ. We want to avoid a closure creation here.
127+
processedFields.Add((PersistentFieldExpression) field.RemoveOuterParameter(processedExpressions));
128+
}
129+
130+
result.Fields = processedFields;
110131
return result;
111132
}
112133

@@ -127,41 +148,54 @@ public static void Fill(EntityExpression entityExpression, int offset)
127148

128149
public static EntityExpression Create(TypeInfo typeInfo, int offset, bool keyFieldsOnly)
129150
{
130-
if (!typeInfo.IsEntity && !typeInfo.IsInterface)
131-
throw new ArgumentException(string.Format(Strings.ExPersistentTypeXIsNotEntityOrPersistentInterface, typeInfo.Name), "typeInfo");
132-
var fields = new List<PersistentFieldExpression>();
151+
if (!typeInfo.IsEntity && !typeInfo.IsInterface) {
152+
throw new ArgumentException(
153+
string.Format(Strings.ExPersistentTypeXIsNotEntityOrPersistentInterface, typeInfo.Name), nameof(typeInfo));
154+
}
155+
133156
var keyExpression = KeyExpression.Create(typeInfo, offset);
134-
fields.Add(keyExpression);
157+
158+
List<PersistentFieldExpression> fields;
135159
var result = new EntityExpression(typeInfo, keyExpression, null, false);
136160
if (keyFieldsOnly) {
161+
fields = new List<PersistentFieldExpression>(keyExpression.KeyFields.Count + 1) {keyExpression};
137162
// Add key fields to field collection
138-
var keyFieldClones = keyExpression
139-
.KeyFields
140-
.Select(kf=>FieldExpression.CreateField(kf.Field, offset))
141-
.Cast<PersistentFieldExpression>();
142-
fields.AddRange(keyFieldClones);
143-
}
144-
else
145-
foreach (var nestedField in typeInfo.Fields)
163+
foreach (var keyField in keyExpression.KeyFields) {
164+
// Do not convert to LINQ. We want to avoid a closure creation here.
165+
fields.Add(FieldExpression.CreateField(keyField.Field, offset));
166+
}
167+
}
168+
else {
169+
fields = new List<PersistentFieldExpression>(typeInfo.Fields.Count + 1) {keyExpression};
170+
foreach (var nestedField in typeInfo.Fields) {
171+
// Do not convert to LINQ. We want to avoid a closure creation here.
146172
fields.Add(BuildNestedFieldExpression(nestedField, offset));
173+
}
174+
}
175+
147176
result.Fields = fields;
148177
return result;
149178
}
150179

151180
public static EntityExpression Create(EntityFieldExpression entityFieldExpression, int offset)
152181
{
153182
var typeInfo = entityFieldExpression.PersistentType;
154-
var fields = new List<PersistentFieldExpression>();
155183
var keyExpression = KeyExpression.Create(typeInfo, offset);
156-
fields.Add(keyExpression);
157-
foreach (var nestedField in typeInfo.Fields)
158-
fields.Add(BuildNestedFieldExpression(nestedField, offset));
184+
var fields = new List<PersistentFieldExpression>(typeInfo.Fields.Count + 1) {keyExpression};
185+
foreach (var nestedField in typeInfo.Fields) {
186+
// Do not convert to LINQ. We want to avoid a closure creation here.
187+
fields.Add(BuildNestedFieldExpression(nestedField, offset));
188+
}
189+
159190
var result = new EntityExpression(typeInfo, keyExpression, null, entityFieldExpression.DefaultIfEmpty) {
160191
Fields = fields
161192
};
162-
if (entityFieldExpression.OuterParameter==null)
193+
if (entityFieldExpression.OuterParameter == null) {
163194
return result;
164-
return (EntityExpression) result.BindParameter(entityFieldExpression.OuterParameter, new Dictionary<Expression, Expression>());
195+
}
196+
197+
return (EntityExpression) result.BindParameter(
198+
entityFieldExpression.OuterParameter, new Dictionary<Expression, Expression>());
165199
}
166200

167201
private static PersistentFieldExpression BuildNestedFieldExpression(FieldInfo nestedField, int offset)
@@ -177,11 +211,7 @@ private static PersistentFieldExpression BuildNestedFieldExpression(FieldInfo ne
177211
throw new NotSupportedException(string.Format(Strings.ExNestedFieldXIsNotSupported, nestedField.Attributes));
178212
}
179213

180-
public override string ToString()
181-
{
182-
return string.Format("{0} {1}", base.ToString(), PersistentType.Name);
183-
}
184-
214+
public override string ToString() => $"{base.ToString()} {PersistentType.Name}";
185215

186216
// Constructors
187217

0 commit comments

Comments
 (0)