Skip to content

Commit 7e8e40c

Browse files
authored
Optimization: Convert QueryEndpoint to readonly struct (#388)
* Convert `QueryEndpoint` to `readonly struct`; * Bump version * Implement IEquatable<> * Remove session field * Correct `Equals()` * optimize * optimize * Bump version
1 parent 21a1161 commit 7e8e40c

File tree

2 files changed

+37
-39
lines changed

2 files changed

+37
-39
lines changed

Orm/Xtensive.Orm/Orm/QueryEndpoint.cs

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,29 @@ namespace Xtensive.Orm
2727
/// and finally, resolve <see cref="Key"/>s to <see cref="Entity">entities</see>.
2828
/// </summary>
2929
[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)]
30-
public sealed class QueryEndpoint
30+
public readonly struct QueryEndpoint : IEquatable<QueryEndpoint>
3131
{
32-
private readonly Session session;
33-
34-
/// <summary>
35-
/// Gets outer <see cref="QueryEndpoint"/>.
36-
/// For root <see cref="QueryEndpoint"/> returns <see langword="null"/>.
37-
/// </summary>
38-
public QueryEndpoint Outer { get; private set; }
39-
4032
/// <summary>
4133
/// Gets <see cref="IQueryProvider"/> implementation
4234
/// for this session.
4335
/// </summary>
4436
public QueryProvider Provider { get; }
4537

38+
private Session Session => Provider.Session;
39+
4640
/// <summary>
4741
/// Gets <see cref="IQueryRootBuilder"/> associated with this instance.
4842
/// If <see cref="IQueryRootBuilder"/> is not set for this instance
4943
/// returns <see langword="null"/>.
5044
/// </summary>
51-
public IQueryRootBuilder RootBuilder { get; private set; }
45+
public IQueryRootBuilder RootBuilder { get; }
46+
47+
public bool Equals(QueryEndpoint other) =>
48+
Provider == other.Provider && RootBuilder == other.RootBuilder;
49+
50+
public override bool Equals(object obj) => obj is QueryEndpoint other && Equals(other);
51+
52+
public override int GetHashCode() => HashCode.Combine(Provider, RootBuilder);
5253

5354
/// <summary>
5455
/// The "starting point" for any LINQ query -
@@ -256,7 +257,7 @@ public IQueryable<FullTextMatch<T>> ContainsTable<T>(
256257

257258
/// <summary>
258259
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="key"/>
259-
/// in the current <see cref="session"/>.
260+
/// in the current <see cref="Session"/>.
260261
/// </summary>
261262
/// <param name="key">The key to resolve.</param>
262263
/// <returns>
@@ -277,7 +278,7 @@ public Entity Single(Key key)
277278

278279
/// <summary>
279280
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="key"/>
280-
/// in the current <see cref="session"/>.
281+
/// in the current <see cref="Session"/>.
281282
/// </summary>
282283
/// <param name="key">The key to resolve.</param>
283284
/// <returns>
@@ -298,7 +299,7 @@ public async ValueTask<Entity> SingleAsync(Key key, CancellationToken ct = defau
298299

299300
/// <summary>
300301
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="key"/>
301-
/// in the current <see cref="session"/>.
302+
/// in the current <see cref="Session"/>.
302303
/// </summary>
303304
/// <param name="key">The key to resolve.</param>
304305
/// <returns>
@@ -311,6 +312,7 @@ public Entity SingleOrDefault(Key key)
311312
if (key == null) {
312313
return null;
313314
}
315+
var session = Session;
314316
using var tx = session.OpenAutoTransaction();
315317
EntityState state;
316318
if (!session.LookupStateInCache(key, out state)) {
@@ -338,7 +340,7 @@ public Entity SingleOrDefault(Key key)
338340

339341
/// <summary>
340342
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="key"/>
341-
/// in the current <see cref="session"/>.
343+
/// in the current <see cref="Session"/>.
342344
/// </summary>
343345
/// <param name="key">The key to resolve.</param>
344346
/// <returns>
@@ -350,7 +352,8 @@ public async ValueTask<Entity> SingleOrDefaultAsync(Key key, CancellationToken c
350352
if (key == null) {
351353
return null;
352354
}
353-
using var tx = session.OpenAutoTransaction();
355+
var session = Session;
356+
await using var tx = session.OpenAutoTransaction();
354357
EntityState state;
355358
if (!session.LookupStateInCache(key, out state)) {
356359
if (session.IsDebugEventLoggingEnabled) {
@@ -377,7 +380,7 @@ public async ValueTask<Entity> SingleOrDefaultAsync(Key key, CancellationToken c
377380

378381
/// <summary>
379382
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="key"/>
380-
/// in the current <see cref="session"/>.
383+
/// in the current <see cref="Session"/>.
381384
/// </summary>
382385
/// <typeparam name="T">Type of the entity.</typeparam>
383386
/// <param name="key">The key to resolve.</param>
@@ -393,7 +396,7 @@ public T Single<T>(Key key)
393396

394397
/// <summary>
395398
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="keyValues"/>
396-
/// in the current <see cref="session"/>.
399+
/// in the current <see cref="Session"/>.
397400
/// </summary>
398401
/// <typeparam name="T">Type of the entity.</typeparam>
399402
/// <param name="keyValues">Key values.</param>
@@ -409,7 +412,7 @@ public T Single<T>(params object[] keyValues)
409412

410413
/// <summary>
411414
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="key"/>
412-
/// in the current <see cref="session"/>.
415+
/// in the current <see cref="Session"/>.
413416
/// </summary>
414417
/// <typeparam name="T">Type of the entity.</typeparam>
415418
/// <param name="key">The key to resolve.</param>
@@ -424,7 +427,7 @@ [CanBeNull] public T SingleOrDefault<T>(Key key)
424427

425428
/// <summary>
426429
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="keyValues"/>
427-
/// in the current <see cref="session"/>.
430+
/// in the current <see cref="Session"/>.
428431
/// </summary>
429432
/// <typeparam name="T">Type of the entity.</typeparam>
430433
/// <param name="keyValues">Key values.</param>
@@ -439,7 +442,7 @@ [CanBeNull] public T SingleOrDefault<T>(params object[] keyValues)
439442

440443
/// <summary>
441444
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="key"/>
442-
/// in the current <see cref="session"/>.
445+
/// in the current <see cref="Session"/>.
443446
/// </summary>
444447
/// <typeparam name="T">Type of the entity.</typeparam>
445448
/// <param name="key">The key to resolve.</param>
@@ -452,7 +455,7 @@ public async ValueTask<T> SingleAsync<T>(Key key, CancellationToken ct = default
452455

453456
/// <summary>
454457
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="keyValues"/>
455-
/// in the current <see cref="session"/>.
458+
/// in the current <see cref="Session"/>.
456459
/// </summary>
457460
/// <typeparam name="T">Type of the entity.</typeparam>
458461
/// <param name="keyValues">Key values.</param>
@@ -468,7 +471,7 @@ public async ValueTask<T> SingleAsync<T>(object key1, object key2, CancellationT
468471

469472
/// <summary>
470473
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="key"/>
471-
/// in the current <see cref="session"/>.
474+
/// in the current <see cref="Session"/>.
472475
/// </summary>
473476
/// <typeparam name="T">Type of the entity.</typeparam>
474477
/// <param name="key">The key to resolve.</param>
@@ -480,7 +483,7 @@ public async ValueTask<T> SingleOrDefaultAsync<T>(Key key, CancellationToken ct
480483

481484
/// <summary>
482485
/// Resolves (gets) the <see cref="Entity"/> by the specified <paramref name="keyValues"/>
483-
/// in the current <see cref="session"/>.
486+
/// in the current <see cref="Session"/>.
484487
/// </summary>
485488
/// <typeparam name="T">Type of the entity.</typeparam>
486489
/// <param name="keyValues">Key values.</param>
@@ -501,7 +504,7 @@ public async ValueTask<T> SingleOrDefaultAsync<T>(object key1, object key2, Canc
501504
public PrefetchQuery<T> Many<T>(IEnumerable<Key> keys)
502505
where T : class, IEntity
503506
{
504-
return new PrefetchQuery<T>(session, keys);
507+
return new PrefetchQuery<T>(Session, keys);
505508
}
506509

507510
/// <summary>
@@ -516,16 +519,13 @@ public PrefetchQuery<T> Many<T, TElement>(IEnumerable<TElement> keys)
516519
where T : class, IEntity
517520
{
518521
var elementType = typeof (TElement);
519-
Func<TElement, Key> selector;
520-
if (elementType==WellKnownTypes.ObjectArray) {
521-
selector = e => Key.Create(session.Domain, session.StorageNodeId, typeof (T), TypeReferenceAccuracy.BaseType, (object[]) (object) e);
522-
}
523-
else if (WellKnownOrmTypes.Tuple.IsAssignableFrom(elementType)) {
524-
selector = e => Key.Create(session.Domain, session.StorageNodeId, typeof (T), TypeReferenceAccuracy.BaseType, (Tuple) (object) e);
525-
}
526-
else {
527-
selector = e => Key.Create(session.Domain, session.StorageNodeId, typeof (T), TypeReferenceAccuracy.BaseType, new object[] {e});
528-
}
522+
var session = Session;
523+
Func<TElement, Key> selector =
524+
elementType == WellKnownTypes.ObjectArray
525+
? e => Key.Create(session.Domain, session.StorageNodeId, typeof(T), TypeReferenceAccuracy.BaseType, (object[]) (object) e)
526+
: WellKnownOrmTypes.Tuple.IsAssignableFrom(elementType)
527+
? e => Key.Create(session.Domain, session.StorageNodeId, typeof(T), TypeReferenceAccuracy.BaseType, (Tuple) (object) e)
528+
: e => Key.Create(session.Domain, session.StorageNodeId, typeof(T), TypeReferenceAccuracy.BaseType, new object[] { e });
529529

530530
return new PrefetchQuery<T>(session, keys.Select(selector));
531531
}
@@ -968,14 +968,15 @@ private Key GetKeyByValues<T>(object[] keyValues)
968968
return entity.Key;
969969
}
970970
}
971+
var session = Session;
971972
return Key.Create(session.Domain, session.StorageNodeId, typeof(T), TypeReferenceAccuracy.BaseType, keyValues);
972973
}
973974

974975
private Expression BuildRootExpression(Type elementType)
975976
{
976977
return RootBuilder!=null
977978
? RootBuilder.BuildRootExpression(elementType)
978-
: session.Domain.RootCallExpressionsCache.GetOrAdd(elementType, (t) => Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(t)));
979+
: Session.Domain.RootCallExpressionsCache.GetOrAdd(elementType, (t) => Expression.Call(null, WellKnownMembers.Query.All.MakeGenericMethod(t)));
979980
}
980981

981982
private static void ThrowKeyNotFoundException(Key key) =>
@@ -990,15 +991,12 @@ internal QueryEndpoint(QueryProvider provider)
990991
{
991992
ArgumentNullException.ThrowIfNull(provider);
992993
Provider = provider;
993-
session = provider.Session;
994994
}
995995

996996
internal QueryEndpoint(QueryEndpoint outerEndpoint, IQueryRootBuilder queryRootBuilder)
997997
{
998-
ArgumentNullException.ThrowIfNull(outerEndpoint);
999998
ArgumentNullException.ThrowIfNull(queryRootBuilder);
1000999
Provider = outerEndpoint.Provider;
1001-
session = outerEndpoint.session;
10021000
RootBuilder = queryRootBuilder;
10031001
}
10041002
}

Version.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
33

44
<PropertyGroup>
5-
<DoVersion>7.2.181</DoVersion>
5+
<DoVersion>7.2.184</DoVersion>
66
<DoVersionSuffix>servicetitan</DoVersionSuffix>
77
</PropertyGroup>
88

0 commit comments

Comments
 (0)