Skip to content

Commit c311e8c

Browse files
committed
Small improvements
- ExpressionComparer uses zipping without Funcs, ValueTuple used instead - SubqueryDefalutResultRewriter uses type cast only when needed - Translator.ConstructQueryable is optimized to not have making generic type, it uses already given type by methodcallexpression. Additionally, by having overload that gets element type, we skip MethodCallExpression construction. - Small improvements in Translator.VisitSequence. Less operations for checking for entity set and no double search for type - typeof (Func<>) is cached within Translator - Small improvement for Union/Concat/Intersect/etc. operations by getting rid of extra enumerations - RecordSetHeader.Add(IReadOnlyList<Column>) substitutes counterpart with IEnumerable<Column> which produce less memory fluctuations. - RecordSetHeader.Add(Column) also doesn't use IEnumerable
1 parent f2283c9 commit c311e8c

File tree

6 files changed

+90
-40
lines changed

6 files changed

+90
-40
lines changed

Orm/Xtensive.Orm/Linq/Internals/ExpressionComparer.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ private bool VisitListInit(ListInitExpression x, ListInitExpression y)
111111
return VisitNew(x.NewExpression, y.NewExpression)
112112
&& x.Initializers.Count==y.Initializers.Count
113113
&& x.Initializers
114-
.Zip(y.Initializers, (first, second) => new Pair<ElementInit>(first, second))
114+
.Zip(y.Initializers)
115115
.All(p => VisitElementInit(p.First, p.Second));
116116
}
117117

@@ -126,7 +126,7 @@ private bool VisitMemberInit(MemberInitExpression x, MemberInitExpression y)
126126
return VisitNew(x.NewExpression, y.NewExpression)
127127
&& x.Bindings.Count==y.Bindings.Count
128128
&& x.Bindings
129-
.Zip(y.Bindings, (first, second) => new Pair<MemberBinding>(first, second))
129+
.Zip(y.Bindings)
130130
.All(p => VisitMemberBinding(p.First, p.Second));
131131
}
132132

@@ -145,14 +145,14 @@ private bool VisitMemberBinding(MemberBinding x, MemberBinding y)
145145
var mby = (MemberMemberBinding)y;
146146
return mbx.Bindings.Count==mby.Bindings.Count
147147
&& mbx.Bindings
148-
.Zip(mby.Bindings, (first, second) => new Pair<MemberBinding>(first, second))
148+
.Zip(mby.Bindings)
149149
.All(p => VisitMemberBinding(p.First, p.Second));
150150
case MemberBindingType.ListBinding:
151151
var mlx = (MemberListBinding)x;
152152
var mly = (MemberListBinding)y;
153153
return mlx.Initializers.Count==mly.Initializers.Count
154154
&& mlx.Initializers
155-
.Zip(mly.Initializers, (first, second) => new Pair<ElementInit>(first, second))
155+
.Zip(mly.Initializers)
156156
.All(p => VisitElementInit(p.First, p.Second));
157157
default:
158158
throw new ArgumentOutOfRangeException();
@@ -189,7 +189,7 @@ private bool VisitNew(NewExpression x, NewExpression y)
189189
return false;
190190
if (x.Members.Count != y.Members.Count)
191191
return false;
192-
for (int i = 0; i < x.Members.Count; i++)
192+
for (int i = 0, count = x.Members.Count; i < count; i++)
193193
if (x.Members[i] != y.Members[i])
194194
return false;
195195
return true;
@@ -253,7 +253,7 @@ private bool CompareExpressionSequences<T>(
253253
{
254254
if (x.Count != y.Count)
255255
return false;
256-
for (int i = 0; i < x.Count; i++)
256+
for (int i = 0, count = x.Count; i < count; i++)
257257
if (!Visit(x[i], y[i]))
258258
return false;
259259
return true;

Orm/Xtensive.Orm/Orm/Linq/Rewriters/SubqueryDefaultResultRewriter.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,11 @@ private static Expression ApplyCorrection(Expression originalExpression)
3333
if (expression.NodeType == ExpressionType.Convert) {
3434
expression = ((UnaryExpression) expression).Operand;
3535
}
36+
if (expression.NodeType is not ExpressionType.Call)
37+
return originalExpression;
3638

3739
var methodCall = expression as MethodCallExpression;
38-
if (methodCall == null || !IsDefaultingMethod(methodCall.Method) || !HasNonNullDefault(methodCall.Type)) {
40+
if (!IsDefaultingMethod(methodCall.Method) || !HasNonNullDefault(methodCall.Type)) {
3941
return originalExpression;
4042
}
4143

Orm/Xtensive.Orm/Orm/Linq/Translator.Expressions.cs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1274,13 +1274,23 @@ private static bool ContainsEntityExpression(Expression expression)
12741274
private Expression ConstructQueryable(MethodCallExpression mc)
12751275
{
12761276
var elementType = mc.Method.GetGenericArguments()[0];
1277-
TypeInfo type;
1278-
if (!context.Model.Types.TryGetValue(elementType, out type))
1279-
throw new InvalidOperationException(String.Format(Strings.ExTypeNotFoundInModel, elementType.FullName));
1277+
if (!context.Model.Types.TryGetValue(elementType, out var type))
1278+
throw new InvalidOperationException(string.Format(Strings.ExTypeNotFoundInModel, elementType.FullName));
12801279
var index = type.Indexes.PrimaryIndex;
12811280
var entityExpression = EntityExpression.Create(type, 0, false);
12821281
var itemProjector = new ItemProjectorExpression(entityExpression, index.GetQuery(), context);
1283-
return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType), itemProjector, new Dictionary<Parameter<Tuple>, Tuple>());
1282+
return new ProjectionExpression(mc.Type, itemProjector, new Dictionary<Parameter<Tuple>, Tuple>());
1283+
}
1284+
1285+
private Expression ConstructQueryable(Type elementType)
1286+
{
1287+
if (!context.Model.Types.TryGetValue(elementType, out var type))
1288+
throw new InvalidOperationException(string.Format(Strings.ExTypeNotFoundInModel, elementType.FullName));
1289+
var index = type.Indexes.PrimaryIndex;
1290+
var entityExpression = EntityExpression.Create(type, 0, false);
1291+
var itemProjector = new ItemProjectorExpression(entityExpression, index.GetQuery(), context);
1292+
return new ProjectionExpression(WellKnownInterfaces.QueryableOfT.MakeGenericType(elementType),
1293+
itemProjector, new Dictionary<Parameter<Tuple>, Tuple>());
12841294
}
12851295

12861296
private Expression BuildSubqueryResult(ProjectionExpression subQuery, Type resultType)

Orm/Xtensive.Orm/Orm/Linq/Translator.Materialization.cs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -212,10 +212,9 @@ private ProjectionExpression GetIndexBinding(LambdaExpression le, ref Projection
212212
private Expression VisitQuerySingle(MethodCallExpression mc)
213213
{
214214
var returnType = mc.Method.ReturnType;
215-
216215
var argument = mc.Arguments[0];
217-
var queryAll = Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(returnType));
218-
var source = ConstructQueryable(queryAll);
216+
217+
var source = ConstructQueryable(returnType);
219218
var parameter = Expression.Parameter(returnType, "entity");
220219
var keyAccessor = Expression.MakeMemberAccess(parameter, WellKnownMembers.IEntityKey);
221220
var equility = Expression.Equal(keyAccessor, argument);

Orm/Xtensive.Orm/Orm/Linq/Translator.Queryable.cs

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ namespace Xtensive.Orm.Linq
2727
internal sealed partial class Translator : QueryableVisitor
2828
{
2929
private static readonly Type IEnumerableOfKeyType = typeof(IEnumerable<Key>);
30+
private static readonly Type GenericFuncDefType = typeof(Func<>);
3031

3132
public TranslatorState state;
3233
private readonly TranslatorContext context;
@@ -1570,22 +1571,27 @@ private Expression VisitSetOperations(Expression outerSource, Expression innerSo
15701571
var innerItemProjector = inner.ItemProjector.RemoveOwner();
15711572
var outerColumnList = outerItemProjector.GetColumns(ColumnExtractionModes.Distinct);
15721573
var innerColumnList = innerItemProjector.GetColumns(ColumnExtractionModes.Distinct);
1574+
1575+
int[] outerColumns, innerColumns;
15731576
if (!outerColumnList.Except(innerColumnList).Any() && outerColumnList.Count == innerColumnList.Count) {
1574-
var outerColumnListCopy = outerColumnList.ToList();
1575-
outerColumnListCopy.Sort();
1576-
outerColumnList = outerColumnListCopy;
1577+
var outerColumnListCopy = outerColumnList.ToArray();
1578+
Array.Sort(outerColumnListCopy);
1579+
outerColumns = outerColumnListCopy;
15771580

1578-
var innerColumnListCopy = innerColumnList.ToList();
1579-
innerColumnListCopy.Sort();
1580-
innerColumnList = innerColumnListCopy;
1581+
var innerColumnListCopy = innerColumnList.ToArray();
1582+
Array.Sort(innerColumnListCopy);
1583+
innerColumns = innerColumnListCopy;
1584+
}
1585+
else {
1586+
outerColumns = outerColumnList.ToArray();
1587+
innerColumns = innerColumnList.ToArray();
15811588
}
15821589

1583-
var outerColumns = outerColumnList.ToArray();
1584-
var outerRecordSet = ShouldWrapDataSourceWithSelect(outerItemProjector, outerColumnList)
1590+
var outerRecordSet = ShouldWrapDataSourceWithSelect(outerItemProjector, outerColumns)
15851591
? outerItemProjector.DataSource.Select(outerColumns)
15861592
: outerItemProjector.DataSource;
1587-
var innerRecordSet = ShouldWrapDataSourceWithSelect(innerItemProjector, innerColumnList)
1588-
? innerItemProjector.DataSource.Select(innerColumnList.ToArray())
1593+
var innerRecordSet = ShouldWrapDataSourceWithSelect(innerItemProjector, innerColumns)
1594+
? innerItemProjector.DataSource.Select(innerColumns)
15891595
: innerItemProjector.DataSource;
15901596

15911597
var recordSet = outerItemProjector.DataSource;
@@ -1647,24 +1653,21 @@ private ProjectionExpression VisitSequence(Expression sequenceExpression, Expres
16471653
Strings.ExDirectQueryingForEntitySetInCompiledQueriesIsNotSupportedUseQueryEndpointItemsInstead);
16481654
}
16491655

1650-
if (sequence.GetMemberType() == MemberType.EntitySet) {
1656+
if (WellKnownOrmTypes.EntitySetBase.IsAssignableFrom(sequence.StripMarkers().Type)) {
16511657
if (sequence.NodeType == ExpressionType.MemberAccess) {
16521658
var memberAccess = (MemberExpression) sequence;
16531659
if (memberAccess.Member is PropertyInfo propertyInfo
16541660
&& memberAccess.Expression != null
1655-
&& context.Model.Types.Contains(memberAccess.Expression.Type)) {
1656-
var field = context
1657-
.Model
1658-
.Types[memberAccess.Expression.Type]
1661+
&& context.Model.Types.TryGetValue(memberAccess.Expression.Type, out var ti)) {
1662+
var field = ti
16591663
.Fields[context.Domain.Handlers.NameBuilder.BuildFieldName(propertyInfo)];
16601664
sequenceExpression = QueryHelper.CreateEntitySetQuery(memberAccess.Expression, field, context.Domain);
16611665
}
16621666
}
16631667
}
16641668

16651669
if (sequence.IsLocalCollection(context)) {
1666-
var sequenceType = (sequence.Type.IsGenericType
1667-
&& sequence.Type.GetGenericTypeDefinition() == typeof(Func<>))
1670+
var sequenceType = sequence.Type.IsGenericType && sequence.Type.IsOfGenericType(GenericFuncDefType)
16681671
? sequence.Type.GetGenericArguments()[0]
16691672
: sequence.Type;
16701673

Orm/Xtensive.Orm/Orm/Rse/RecordSetHeader.cs

Lines changed: 45 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,18 @@ public RecordSetHeader Alias(string alias)
9696
/// <returns>The constructed header.</returns>
9797
public RecordSetHeader Add(Column column)
9898
{
99-
return Add(EnumerableUtils.One(column));
99+
var newColumns = new List<Column>(Columns.Count + 1);
100+
newColumns.AddRange(Columns);
101+
newColumns.Add(column);
102+
103+
var newTupleDescriptor = CreateTupleDescriptor(newColumns);
104+
105+
return new RecordSetHeader(
106+
newTupleDescriptor,
107+
newColumns,
108+
ColumnGroups,
109+
OrderTupleDescriptor,
110+
Order);
100111
}
101112

102113
/// <summary>
@@ -109,10 +120,28 @@ public RecordSetHeader Add(IEnumerable<Column> columns)
109120
var newColumns = new List<Column>(Columns);
110121
newColumns.AddRange(columns);
111122

112-
var newFieldTypes = new Type[newColumns.Count];
113-
for (var i = 0; i < newColumns.Count; i++)
114-
newFieldTypes[i] = newColumns[i].Type;
115-
var newTupleDescriptor = TupleDescriptor.Create(newFieldTypes);
123+
var newTupleDescriptor = CreateTupleDescriptor(newColumns);
124+
125+
return new RecordSetHeader(
126+
newTupleDescriptor,
127+
newColumns,
128+
ColumnGroups,
129+
OrderTupleDescriptor,
130+
Order);
131+
}
132+
133+
/// <summary>
134+
/// Adds the specified columns to header.
135+
/// </summary>
136+
/// <param name="columns">The columns to add.</param>
137+
/// <returns>The constructed header.</returns>
138+
public RecordSetHeader Add(IReadOnlyList<Column> columns)
139+
{
140+
var newColumns = new List<Column>(Columns.Count + columns.Count);
141+
newColumns.AddRange(Columns);
142+
newColumns.AddRange(columns);
143+
144+
var newTupleDescriptor = CreateTupleDescriptor(newColumns);
116145

117146
return new RecordSetHeader(
118147
newTupleDescriptor,
@@ -136,10 +165,7 @@ public RecordSetHeader Join(RecordSetHeader joined)
136165
newColumns.Add(c.Clone(columnCount + c.Index));
137166
}
138167

139-
var newFieldTypes = new Type[newColumns.Count];
140-
for (var i = 0; i < newColumns.Count; i++)
141-
newFieldTypes[i] = newColumns[i].Type;
142-
var newTupleDescriptor = TupleDescriptor.Create(newFieldTypes);
168+
var newTupleDescriptor = CreateTupleDescriptor(newColumns);
143169

144170
var columnGroupCount = ColumnGroups.Count;
145171
var groups = new List<ColumnGroup>(columnGroupCount + joined.ColumnGroups.Count);
@@ -282,6 +308,16 @@ private static RecordSetHeader CreateHeader(IndexInfo indexInfo)
282308
order);
283309
}
284310

311+
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
312+
private static TupleDescriptor CreateTupleDescriptor(List<Column> newColumns)
313+
{
314+
var newFieldTypes = new Type[newColumns.Count];
315+
for (var i = 0; i < newColumns.Count; i++) {
316+
newFieldTypes[i] = newColumns[i].Type;
317+
}
318+
return TupleDescriptor.Create(newFieldTypes);
319+
}
320+
285321
/// <inheritdoc/>
286322
public override string ToString()
287323
{

0 commit comments

Comments
 (0)