Skip to content

Commit 4faebd0

Browse files
committed
Merge branch 'master' into tuple-transform-refactoring
# Conflicts: # ChangeLog/7.2.2-dev.txt
2 parents f3f1763 + b95dff8 commit 4faebd0

10 files changed

Lines changed: 68 additions & 54 deletions

File tree

.github/workflows/reusable-storage-dependant-tests.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,18 +116,20 @@ jobs:
116116
timeout-minutes: 10
117117
run: '${{ vars[env.DOCKER_SCRIPT_KEY] }}'
118118

119-
- name: Build Orm
120-
if: ${{ success() }}
121-
timeout-minutes: 5
122-
run: dotnet build Orm.sln -c ${{ inputs.build_config }}
123-
124119
- name: Setup .NETs
125120
if: ${{ success() }}
126121
timeout-minutes: 2
127122
uses: ./.github/actions/setup-dotnets
128123
with:
129124
target_framework: ${{ env.DO_TargetFrameworks }}
130125

126+
- name: Build Orm
127+
if: ${{ success() }}
128+
timeout-minutes: 5
129+
run: dotnet build Orm.sln -c ${{ inputs.build_config }}
130+
131+
132+
131133
# Since composite action syntax does not allow to define step timeout
132134
# we have to run Reprocessing project here, because it may stuck in forever-loop
133135
- name: Test Reprocessing extension set of tests

.github/workflows/reusable-storage-independant-tests.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,18 +84,18 @@ jobs:
8484
if: ${{ inputs.specific_sha != '' && github.reg_type == 'branch' }}
8585
run: git checkout ${{ inputs.specific_sha }}
8686

87-
- name: Build Orm
88-
if: ${{ success() }}
89-
timeout-minutes: 5
90-
run: dotnet build Orm.sln -c ${{ inputs.build_config }}
91-
9287
- name: Setup .NETs
9388
if: ${{ success() }}
9489
timeout-minutes: 2
9590
uses: ./.github/actions/setup-dotnets
9691
with:
9792
target_framework: ${{ env.DO_TargetFrameworks }}
9893

94+
- name: Build Orm
95+
if: ${{ success() }}
96+
timeout-minutes: 5
97+
run: dotnet build Orm.sln -c ${{ inputs.build_config }}
98+
9999
- name: Run tests
100100
id: complex_tests
101101
if: ${{ success() }}

Orm/Xtensive.Orm.Manual/Prefetch/PrefetchTest.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ public async Task MainAsyncTest()
180180
.Prefetch(p => p.Photo) // Lazy load field
181181
.Prefetch(p => p.Employees.Prefetch(e => e.Photo)) // EntitySet Employees and lazy load field of each of its items with the limit on number of items to be loaded
182182
.Prefetch(p => p.Manager.Photo); // Referenced entity and lazy load field for each of them
183-
await foreach (var person in people.AsAsyncEnumerable()) {
183+
await foreach (var person in people) {
184184
var accessor = DirectStateAccessor.Get(person);
185185
Assert.That(accessor.GetFieldState("Photo"), Is.EqualTo(PersistentFieldState.Loaded));
186186
Assert.That(accessor.GetFieldState("Manager"), Is.EqualTo(PersistentFieldState.Loaded));
@@ -275,7 +275,7 @@ orderby person.Name
275275
.Prefetch(p => p.Employees // EntitySet Employees
276276
.Prefetch(e => e.Photo)) // and lazy load field of each of its items
277277
.Prefetch(p => p.Manager); // Referenced entity
278-
await foreach (var person in prefetchedPeople.AsAsyncEnumerable()) {
278+
await foreach (var person in prefetchedPeople) {
279279
var accessor = DirectStateAccessor.Get(person);
280280
Assert.That(accessor.GetFieldState("Photo"), Is.EqualTo(PersistentFieldState.Loaded));
281281
Assert.That(accessor.GetFieldState("Manager"), Is.EqualTo(PersistentFieldState.Loaded));
@@ -362,7 +362,7 @@ public async Task DelayedQueryAsyncTest()
362362
.Prefetch(p => p.Photo) // Lazy load field
363363
.Prefetch(p => p.Employees.Prefetch(e => e.Photo)) // EntitySet Employees and lazy load field of each of its items with the limit on number of items to be loaded
364364
.Prefetch(p => p.Manager.Photo); // Referenced entity and lazy load field for each of them
365-
await foreach (var person in people.AsAsyncEnumerable()) {
365+
await foreach (var person in people) {
366366
var accessor = DirectStateAccessor.Get(person);
367367
Assert.That(accessor.GetFieldState("Photo"), Is.EqualTo(PersistentFieldState.Loaded));
368368
Assert.That(accessor.GetFieldState("Manager"), Is.EqualTo(PersistentFieldState.Loaded));
@@ -450,7 +450,7 @@ public async Task CachedQueryAsyncTest()
450450
.Prefetch(p => p.Photo) // Lazy load field
451451
.Prefetch(p => p.Employees.Prefetch(e => e.Photo)) // EntitySet Employees and lazy load field of each of its items with the limit on number of items to be loaded
452452
.Prefetch(p => p.Manager.Photo); // Referenced entity and lazy load field for each of them
453-
await foreach (var person in people.AsAsyncEnumerable()) {
453+
await foreach (var person in people) {
454454
var accessor = DirectStateAccessor.Get(person);
455455
Assert.That(accessor.GetFieldState("Photo"), Is.EqualTo(PersistentFieldState.Loaded));
456456
Assert.That(accessor.GetFieldState("Manager"), Is.EqualTo(PersistentFieldState.Loaded));

Orm/Xtensive.Orm.Tests.FSharp/Model.fs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,4 @@ type X() =
9393
[<Field>]
9494
member this.TimeSpanField
9595
with get() = this.GetFieldValue<System.TimeSpan> (nameof this.TimeSpanField)
96-
and set(v: System.TimeSpan) = this.SetFieldValue (nameof this.TimeSpanField, v)
96+
and set(v: System.TimeSpan) = this.SetFieldValue (nameof this.TimeSpanField, v)

Orm/Xtensive.Orm.Tests.FSharp/QueryEntityBackTest.fs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,4 +32,5 @@ type Fixture() =
3232
let list = query |> Seq.toArray
3333
Assert.That(list.Length, Is.EqualTo(1))
3434
let fetched = list.[0]
35-
Assert.That(fetched.Name, Is.EqualTo("John"))
35+
Assert.That(fetched.Name, Is.EqualTo("John"))
36+

Orm/Xtensive.Orm.Tests.FSharp/Xtensive.Orm.Tests.FSharp.fsproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,11 @@
2828
<ProjectReference Include="..\Xtensive.Orm\Xtensive.Orm.csproj" />
2929
</ItemGroup>
3030
<ItemGroup>
31+
<!-- Keep it before any tests -->
3132
<Compile Include="FsUnit.fs" />
3233
<Compile Include="Model.fs" />
34+
</ItemGroup>
35+
<ItemGroup>
3336
<Compile Include="ArithmeticOperationsCompilersTest.fs" />
3437
<Compile Include="ComparisonCompilersTest.fs" />
3538
<Compile Include="DateTimeCompilersTest.fs" />

Orm/Xtensive.Orm.Tests/Storage/Prefetch/PrefetchTest.cs

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -181,8 +181,7 @@ public async Task PrefetchGraphPerformanceAsyncTest()
181181
.Prefetch(i => i.InvoiceLines
182182
.Prefetch(id => id.Track)
183183
.Prefetch(id => id.Track.Album)
184-
.Prefetch(id => id.Track.Bytes))
185-
.AsAsyncEnumerable();
184+
.Prefetch(id => id.Track.Bytes));
186185
await foreach (var invoice in invoices) {
187186
var id = invoice.InvoiceId;
188187
var name = invoice.Customer.CompanyName;
@@ -247,7 +246,7 @@ public async Task EnumerableOfNonEntityAsyncTest()
247246
await using (var session = await Domain.OpenSessionAsync())
248247
await using (var tx = session.OpenTransaction()) {
249248
var invoices = session.Query.Many<Invoice>(keys)
250-
.Prefetch(o => o.DesignatedEmployee).AsAsyncEnumerable();
249+
.Prefetch(o => o.DesignatedEmployee);
251250
var invoiceType = Domain.Model.Types[typeof(Invoice)];
252251
var employeeField = invoiceType.Fields[nameof(Invoice.DesignatedEmployee)];
253252
var employeeType = Domain.Model.Types[typeof(Employee)];
@@ -361,7 +360,7 @@ public async Task PrefetchManyNotFullBatchAsyncTest()
361360
var invoicesField = Domain.Model.Types[typeof (Track)].Fields["Playlists"];
362361
var invoiceLinesField = Domain.Model.Types[typeof (Playlist)].Fields["Tracks"];
363362
var tracks = session.Query.All<Track>().Take(50)
364-
.Prefetch(t => t.Playlists.Prefetch(il => il.Tracks)).AsAsyncEnumerable();
363+
.Prefetch(t => t.Playlists.Prefetch(il => il.Tracks));
365364
int count1 = 0, count2 = 0;
366365
await foreach (var track in tracks) {
367366
count1++;
@@ -413,7 +412,7 @@ public async Task PrefetchManySeveralBatchesAsyncTest()
413412
var trackField = Domain.Model.Types[typeof(InvoiceLine)].Fields[nameof(InvoiceLine.Track)];
414413
var invoices = session.Query.All<Invoice>()
415414
.Take(90)
416-
.Prefetch(o => o.InvoiceLines.Prefetch(od => od.Track)).AsAsyncEnumerable();
415+
.Prefetch(o => o.InvoiceLines.Prefetch(od => od.Track));
417416
int count1 = 0, count2 = 0;
418417
await foreach (var invoice in invoices) {
419418
count1++;
@@ -483,7 +482,7 @@ public async Task PrefetchSingleAsyncTest()
483482
var employeeType = Domain.Model.Types[typeof(Employee)];
484483
var invoiceType = Domain.Model.Types[typeof(Invoice)];
485484
var invoices = session.Query.Many<Invoice>(keys)
486-
.Prefetch(o => o.DesignatedEmployee.Invoices).AsAsyncEnumerable();
485+
.Prefetch(o => o.DesignatedEmployee.Invoices);
487486
var count = 0;
488487
await foreach (var invoice in invoices) {
489488
Assert.That(invoice.Key, Is.EqualTo(keys[count]));
@@ -674,7 +673,7 @@ public async Task SimultaneouslyUsageOfMultipleEnumeratorsAsyncTest()
674673
await using (var session = await Domain.OpenSessionAsync())
675674
await using (var tx = session.OpenTransaction()) {
676675
var source = session.Query.All<Invoice>().ToList();
677-
var prefetchQuery = source.Prefetch(i => i.InvoiceLines).AsAsyncEnumerable();
676+
var prefetchQuery = source.Prefetch(i => i.InvoiceLines);
678677
await using (var enumerator0 = prefetchQuery.GetAsyncEnumerator()) {
679678
_ = await enumerator0.MoveNextAsync();
680679
_ = await enumerator0.MoveNextAsync();
@@ -729,7 +728,7 @@ public async Task RootElementIsNullPrefetchAsyncTest()
729728

730729
await using (var tx = session.OpenTransaction()) {
731730
var books = session.Query.All<PrefetchModel.Book>().AsEnumerable()
732-
.Concat(Enumerable.Repeat<PrefetchModel.Book>(null, 1)).Prefetch(b => b.Title).AsAsyncEnumerable();
731+
.Concat(Enumerable.Repeat<PrefetchModel.Book>(null, 1)).Prefetch(b => b.Title);
733732
var titleField = Domain.Model.Types[typeof(PrefetchModel.Book)].Fields[nameof(PrefetchModel.Book.Title)];
734733
var titleType = Domain.Model.Types[typeof(PrefetchModel.Title)];
735734
var count = 0;
@@ -783,7 +782,7 @@ public async Task NestedPrefetchWhenChildElementIsNullAsyncTest()
783782

784783
await using (var tx = session.OpenTransaction()) {
785784
var prefetcher = session.Query.All<PrefetchModel.Book>()
786-
.Prefetch(b => b.Title.Book).AsAsyncEnumerable();
785+
.Prefetch(b => b.Title.Book);
787786
var titleField = Domain.Model.Types[typeof(PrefetchModel.Book)].Fields[nameof(PrefetchModel.Book.Title)];
788787
var titleType = Domain.Model.Types[typeof(PrefetchModel.Title)];
789788
await foreach (var book in prefetcher) {
@@ -837,7 +836,7 @@ public async Task NestedPrefetchWhenRootElementIsNullAsyncTest()
837836

838837
await using (var tx = session.OpenTransaction()) {
839838
var books = session.Query.All<PrefetchModel.Book>().AsEnumerable().Concat(Enumerable.Repeat<PrefetchModel.Book>(null, 1))
840-
.Prefetch(b => b.Title.Book).AsAsyncEnumerable();
839+
.Prefetch(b => b.Title.Book);
841840
var titleField = Domain.Model.Types[typeof(PrefetchModel.Book)].Fields[nameof(PrefetchModel.Book.Title)];
842841
var titleType = Domain.Model.Types[typeof(PrefetchModel.Title)];
843842
var count = 0;
@@ -883,7 +882,7 @@ public async Task StructureFieldsPrefetchAsyncTest()
883882
await using (var tx = session.OpenTransaction()) {
884883
var containers = session.Query.Many<PrefetchModel.OfferContainer>(Enumerable.Repeat(containerKey, 1))
885884
.Prefetch(oc => oc.RealOffer.Book)
886-
.Prefetch(oc => oc.IntermediateOffer.RealOffer.BookShop).AsAsyncEnumerable();
885+
.Prefetch(oc => oc.IntermediateOffer.RealOffer.BookShop);
887886
await foreach (var key in containers) {
888887
PrefetchTestHelper.AssertOnlyDefaultColumnsAreLoaded(book0Key, book0Key.TypeInfo, session);
889888
PrefetchTestHelper.AssertOnlyDefaultColumnsAreLoaded(bookShop1Key, bookShop1Key.TypeInfo, session);
@@ -917,7 +916,7 @@ public async Task StructurePrefetchAsyncTest()
917916
await using (var session = await Domain.OpenSessionAsync())
918917
await using (var tx = session.OpenTransaction()) {
919918
var containers = session.Query.Many<PrefetchModel.OfferContainer>(Enumerable.Repeat(containerKey, 1))
920-
.Prefetch(oc => oc.IntermediateOffer).AsAsyncEnumerable();
919+
.Prefetch(oc => oc.IntermediateOffer);
921920
await foreach (var key in containers) {
922921
PrefetchTestHelper.AssertOnlySpecifiedColumnsAreLoaded(containerKey, containerKey.TypeInfo, session,
923922
field => PrefetchTestHelper.IsFieldToBeLoadedByDefault(field) || field.Name.StartsWith("IntermediateOffer"));

Orm/Xtensive.Orm/Orm/PrefetchQuery.cs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,27 @@ namespace Xtensive.Orm
1919
/// initial query result.
2020
/// </summary>
2121
/// <typeparam name="TElement">The type of the queried elements.</typeparam>
22-
public readonly struct PrefetchQuery<TElement> : IEnumerable<TElement>
22+
public readonly struct PrefetchQuery<TElement> : IEnumerable<TElement>, IAsyncEnumerable<TElement>
2323
{
24+
#region Nested types
25+
private class ExecuteAsyncResult : IEnumerable<TElement>
26+
{
27+
private readonly List<TElement> items;
28+
// We need to hold StrongReferenceContainer to prevent loaded entities from being collected
29+
private readonly StrongReferenceContainer referenceContainer;
30+
31+
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
32+
33+
public IEnumerator<TElement> GetEnumerator() => items.GetEnumerator();
34+
35+
public ExecuteAsyncResult(List<TElement> items, StrongReferenceContainer referenceContainer)
36+
{
37+
this.items = items;
38+
this.referenceContainer = referenceContainer;
39+
}
40+
}
41+
#endregion
42+
2443
private readonly Session session;
2544
private readonly IEnumerable<TElement> source;
2645
private readonly SinglyLinkedList<KeyExtractorNode<TElement>> nodes;
@@ -38,38 +57,25 @@ internal PrefetchQuery<TElement> RegisterPath<TValue>(Expression<Func<TElement,
3857
public IEnumerator<TElement> GetEnumerator() =>
3958
new PrefetchQueryEnumerable<TElement>(session, source, nodes).GetEnumerator();
4059

60+
/// <inheritdoc />
61+
public IAsyncEnumerator<TElement> GetAsyncEnumerator(CancellationToken token = default) =>
62+
new PrefetchQueryAsyncEnumerable<TElement>(session, source, nodes).GetAsyncEnumerator(token);
63+
4164
/// <summary>
4265
/// Transforms <see cref="PrefetchQuery{TElement}"/> to an <see cref="IAsyncEnumerable{T}"/> sequence.
4366
/// </summary>
67+
[Obsolete("PrefetchQuery itself is an IAsyncEnumerable implementation")]
4468
public IAsyncEnumerable<TElement> AsAsyncEnumerable() =>
4569
new PrefetchQueryAsyncEnumerable<TElement>(session, source, nodes);
4670

47-
private class ExecuteAsyncResult : IEnumerable<TElement>
48-
{
49-
private readonly List<TElement> items;
50-
// We need to hold StrongReferenceContainer to prevent loaded entities from being collected
51-
private readonly StrongReferenceContainer referenceContainer;
52-
53-
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
54-
55-
public IEnumerator<TElement> GetEnumerator() => items.GetEnumerator();
56-
57-
public ExecuteAsyncResult(List<TElement> items, StrongReferenceContainer referenceContainer)
58-
{
59-
this.items = items;
60-
this.referenceContainer = referenceContainer;
61-
}
62-
}
63-
6471
/// <summary>
6572
/// Asynchronously executes given <see cref="PrefetchQuery{TElement}"/> instance.
6673
/// </summary>
6774
/// <remarks>
6875
/// <para>
6976
/// This method internally puts all elements of the resulting sequence to a list
7077
/// and then it wraps mentioned list as a <see cref="QueryResult{TItem}"/>.
71-
/// As a consequence it is more efficient to use asynchronous enumeration over result of
72-
/// <see cref="AsAsyncEnumerable"/> method call because it can perform lazily
78+
/// As a consequence it is more efficient to use asynchronous enumeration because it can perform lazily
7379
/// not putting everything into intermediate list.
7480
/// </para>
7581
/// <para> Multiple active operations are not supported. Use <see langword="await"/>

Orm/Xtensive.Orm/Orm/Providers/DomainHandler.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,9 @@ protected virtual IEnumerable<Type> GetProviderCompilerContainers()
143143

144144
};
145145
var result = basicCompilerContainers;
146-
var defaultLoadedAssemblies = AssemblyLoadContext.Default.Assemblies;
147-
var currentLoadedAssemblies = AssemblyLoadContext.CurrentContextualReflectionContext.Assemblies;
146+
var allLoadedAssemblies = AssemblyLoadContext.All.SelectMany(static c => c.Assemblies);
148147
// dynamic registration to not cause assembly loading
149-
if (defaultLoadedAssemblies.Any(static a => a.GetName().Name.Equals("FSharp.Core", StringComparison.OrdinalIgnoreCase))
150-
|| defaultLoadedAssemblies.Any(static a => a.GetName().Name.Equals("FSharp.Core", StringComparison.OrdinalIgnoreCase))) {
148+
if (allLoadedAssemblies.Any(static a => a.GetName().Name.Equals("FSharp.Core", StringComparison.OrdinalIgnoreCase))) {
151149
result = result.Concat(new[] {
152150
typeof (FSharpMathOperationsCompilers),
153151
typeof (FSharpOperatorsCompilers),
@@ -156,8 +154,7 @@ protected virtual IEnumerable<Type> GetProviderCompilerContainers()
156154
});
157155
}
158156

159-
if (defaultLoadedAssemblies.Any(static a => a.GetName().Name.Equals("Microsoft.VisualBasic", StringComparison.OrdinalIgnoreCase))
160-
|| defaultLoadedAssemblies.Any(static a => a.GetName().Name.Equals("Microsoft.VisualBasic", StringComparison.OrdinalIgnoreCase))) {
157+
if (allLoadedAssemblies.Any(static a => a.GetName().Name.StartsWith("Microsoft.VisualBasic", StringComparison.OrdinalIgnoreCase))) {
161158
result = result.Concat(new[] {
162159
typeof (VbConversionsCompilers),
163160
typeof (VbStringsCompilers),

global.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"sdk": {
3+
"version": "10.0.100",
4+
"rollForward": "latestMinor"
5+
}
6+
}

0 commit comments

Comments
 (0)