Skip to content

Fix loop detection for associations with fetch="join" mapping #2718

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 32 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
be2d9f8
GH2201: Refactor JoinWalker and related subclasses to traverse the en…
Apr 9, 2021
d33d453
GH2201: Correct failing tests due to change in how objects are loaded.
Apr 7, 2021
a37e278
GH2201: Add tests for checking if fetch loops is enabled/disabled.
Apr 5, 2021
cda10f6
GH2201: Add option to disable loop detection during query fetches.
Apr 5, 2021
15d580a
GH2201: Disable loop detection in query fetches to fix tests.
Apr 6, 2021
6258361
GH2201: Add async versions of fetch loop detection tests.
Apr 6, 2021
0a4790a
GH2201: Add 'detect_fetch_loops' option to nhibernate-configuration X…
Apr 6, 2021
4a12457
GH2201: Remove unused currentDepth parameter from private WalkCollect…
Apr 13, 2021
be70574
GH2201: Remove unused currentDepth parameter from AddAssociationToJoi…
Apr 13, 2021
d86bbd9
GH2201: Replace currentDepth parameter in WalkCompositeElementTree wi…
Apr 13, 2021
023b022
GH2201: Remove uses of the now obsolete version of WalkComponentTree.
Apr 13, 2021
975b977
GH2201: Remove currentDepth parameter from private WalkEntityAssociat…
Apr 13, 2021
e99caef
GH2201: Replace uses of currentDepth parameter in obsolete version of…
Apr 13, 2021
20c1491
Merge branch 'master' into GH-2201
bahusoid Aug 18, 2022
dc9f500
More tests; Failing test for entity join
bahusoid Aug 20, 2022
fc4aa68
Fix entity join fetching
bahusoid Aug 21, 2022
a7cd433
Undo not needed change
bahusoid Aug 21, 2022
21b39ab
More tests
bahusoid Aug 21, 2022
cb8eff3
Avoid QueueEntry type casting
bahusoid Aug 21, 2022
d2785cd
missing readonly modifier
bahusoid Aug 21, 2022
63ac31b
Do no use obsolete members
bahusoid Aug 21, 2022
6adeee0
Make CodeFactor happy
bahusoid Aug 21, 2022
4ba63f7
Merge branch 'master' into GH-2201
bahusoid Aug 21, 2022
109233e
Simplify
bahusoid Aug 21, 2022
8bb4e59
clean up
bahusoid Aug 21, 2022
5043ea4
Minor
hazzik Aug 21, 2022
5b563f5
Code cleanup & format
hazzik Aug 21, 2022
e928c78
Simplify QueueEntry hierarchy
hazzik Aug 22, 2022
4a93c13
Rename depth to _depth
hazzik Aug 22, 2022
7ce6da3
Marked Obsolete members instead of new one
bahusoid Aug 22, 2022
9438f8f
Merge branch 'master' into GH-2201
hazzik Aug 26, 2022
7bb8782
Merge branch 'master' into GH-2201
bahusoid Sep 6, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1234,7 +1234,6 @@ public virtual async Task OneToManyCollectionOptimisticLockingWithUpdateAsync()

s = OpenSession();
t = s.BeginTransaction();
c = await (s.CreateCriteria<Contract>().UniqueResultAsync<Contract>());
// If the entity uses a join mapping, DML queries require temp tables.
if (Dialect.SupportsTemporaryTables)
await (s.CreateQuery("delete from Party").ExecuteUpdateAsync());
Expand All @@ -1251,7 +1250,7 @@ public virtual async Task OneToManyCollectionOptimisticLockingWithUpdateAsync()
await (s.DeleteAsync(partyOrig));
await (s.DeleteAsync(newParty));
}

c = await (s.CreateCriteria<Contract>().UniqueResultAsync<Contract>());
await (s.DeleteAsync(c));
Assert.That(await (s.CreateCriteria<Contract>().SetProjection(Projections.RowCountInt64()).UniqueResultAsync<long>()), Is.EqualTo(0L));
Assert.That(await (s.CreateCriteria<Party>().SetProjection(Projections.RowCountInt64()).UniqueResultAsync<long>()), Is.EqualTo(0L));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using NHibernate.Cfg;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH2201
{
using System.Threading.Tasks;
[TestFixture]
public class CircularReferenceFetchDepth0FixtureAsync : BaseFetchFixture
{
private int _id2;

public CircularReferenceFetchDepth0FixtureAsync() : base(0)
{
}

protected override void Configure(Configuration configuration)
{
configuration.SetProperty("max_fetch_depth", "0");
base.Configure(configuration);
}

protected override void OnSetUp()
{
base.OnSetUp();
_id2 = _id;
//Generate another test entity
base.OnSetUp();
}

[Test]
public async Task QueryOverAsync()
{
using (var session = OpenSession())
{
Entity e1 = null;
Entity e2 = null;
var result = await (session.QueryOver<Entity>(() => e1)
.JoinEntityAlias(() => e2, () => e2.EntityNumber == e1.EntityNumber && e2.EntityId != _id)
.Where(e => e.EntityId == _id).SingleOrDefaultAsync());

VerifyChildrenNotInitialized(result);
VerifyChildrenNotInitialized(await (session.LoadAsync<Entity>(_id2)));
}
}

[Test]
public async Task GetAsync()
{
using (var session = OpenSession())
{
var result = await (session.GetAsync<Entity>(_id));
VerifyChildrenNotInitialized(result);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using NHibernate.Cfg;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH2201
{
using System.Threading.Tasks;
[TestFixture(1)]
[TestFixture(2)]
public class CircularReferenceFetchDepthFixtureAsync : BaseFetchFixture
{
private int _id2;
private int _id3;

public CircularReferenceFetchDepthFixtureAsync(int depth) : base(depth)
{
}

protected override void Configure(Configuration configuration)
{
configuration.SetProperty("max_fetch_depth", _depth.ToString());
base.Configure(configuration);
}

protected override void OnSetUp()
{
base.OnSetUp();
_id2 = _id;

//Generate another test entities
base.OnSetUp();
_id3 = _id;
base.OnSetUp();
}

[Test]
public async Task QueryOverAsync()
{
using (var session = OpenSession())
{
Entity e1 = null;
Entity e2 = null;
Entity e3 = null;
var result = await (session.QueryOver<Entity>(() => e1)
.JoinEntityAlias(() => e2, () => e2.EntityNumber == e1.EntityNumber && e2.EntityId == _id2)
.JoinEntityAlias(() => e3, () => e3.EntityNumber == e1.EntityNumber && e3.EntityId == _id3)
.Where(e => e.EntityId == _id).SingleOrDefaultAsync());

Verify(result);

Verify(await (session.LoadAsync<Entity>(_id2)));
Verify(await (session.LoadAsync<Entity>(_id3)));
}
}

[Test]
public async Task GetAsync()
{
using (var session = OpenSession())
{
var result = await (session.GetAsync<Entity>(_id));
Verify(result);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using System;
using System.Linq;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.GH2201
{
using System.Threading.Tasks;
[TestFixture]
public class CircularReferenceFetchFixtureAsync : BaseFetchFixture
{
public CircularReferenceFetchFixtureAsync() : base(-1)
{
}

[Test]
public async Task QueryOverAsync()
{
using (var session = OpenSession())
{
var result = await (session.QueryOver<Entity>().Where(e => e.EntityNumber == "Bob").SingleOrDefaultAsync());

Verify(result);
}
}

[Test]
public async Task GetAsync()
{
using (var session = OpenSession())
{
var result = await (session.GetAsync<Entity>(_id));

Verify(result);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by AsyncGenerator.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------


using NUnit.Framework;
using NHCfg = NHibernate.Cfg;

namespace NHibernate.Test.NHSpecificTest.GH2201
{
using System.Threading.Tasks;
[TestFixture]
public class DetectFetchLoopsFalseFixtureAsync : BugTestCase
{
protected override void Configure(NHCfg.Configuration configuration)
{
configuration.SetProperty(NHCfg.Environment.GenerateStatistics, "true");
configuration.SetProperty(NHCfg.Environment.DetectFetchLoops, "false");
}

protected override void OnTearDown()
{
using (var s = OpenSession())
using (var tx = s.BeginTransaction())
{
s.Delete("from Person");

tx.Commit();
}
}

protected override void OnSetUp()
{
using (var s = OpenSession())
using (var tx = s.BeginTransaction())
{
string[] names = { "Alice", "Bob" };

for (int i = 0; i < names.Length; i++)
{
var name = names[i];

var parent = new Person()
{
Name = name,
Details = new Detail()
{
Data = $"Details for ${name}"
}
};

for (int j = 1; j <= 3; j++)
{
var child = new Person()
{
Name = $"Child ${j} of ${parent.Name}",
Parent = parent,
Details = new Detail()
{
Data = $"Details for child ${j} of ${name}"
}
};

parent.Children.Add(child);
}

s.Save(parent);
}

tx.Commit();
}
}

[Test]
public async Task QueryOverPersonWithParentAsync()
{
var stats = Sfi.Statistics;

stats.Clear();

using (var s = OpenSession())
using (var tx = s.BeginTransaction())
{
var people = await (s.QueryOver<Person>()
.Fetch(SelectMode.Fetch, p => p.Parent)
.Where(p => p.Parent != null)
.ListAsync());

foreach (Person p in people)
{
Assert.That(p.Parent, Is.Not.Null);
Assert.That(p.Parent.Details, Is.Not.Null);
}

Assert.That(people.Count, Is.EqualTo(6));
Assert.That(stats.QueryExecutionCount, Is.EqualTo(1));
Assert.That(stats.EntityFetchCount, Is.EqualTo(0));
Assert.That(stats.EntityLoadCount, Is.EqualTo(16));
}
}

[Test]
public async Task QueryOverSinglePersonWithParentAsync()
{
var stats = Sfi.Statistics;

stats.Clear();

using (var s = OpenSession())
using (var tx = s.BeginTransaction())
{
var person = await (s.QueryOver<Person>()
.Where(p => p.Parent != null)
.Fetch(SelectMode.Fetch, p => p.Parent)
.Take(1)
.SingleOrDefaultAsync());

Assert.That(person, Is.Not.Null);
Assert.That(stats.QueryExecutionCount, Is.EqualTo(1));
Assert.That(stats.EntityFetchCount, Is.EqualTo(0));
Assert.That(stats.EntityLoadCount, Is.EqualTo(4));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,6 @@ public virtual void OneToManyCollectionOptimisticLockingWithUpdate()

s = OpenSession();
t = s.BeginTransaction();
c = s.CreateCriteria<Contract>().UniqueResult<Contract>();
// If the entity uses a join mapping, DML queries require temp tables.
if (Dialect.SupportsTemporaryTables)
s.CreateQuery("delete from Party").ExecuteUpdate();
Expand All @@ -1240,7 +1239,7 @@ public virtual void OneToManyCollectionOptimisticLockingWithUpdate()
s.Delete(partyOrig);
s.Delete(newParty);
}

c = s.CreateCriteria<Contract>().UniqueResult<Contract>();
s.Delete(c);
Assert.That(s.CreateCriteria<Contract>().SetProjection(Projections.RowCountInt64()).UniqueResult<long>(), Is.EqualTo(0L));
Assert.That(s.CreateCriteria<Party>().SetProjection(Projections.RowCountInt64()).UniqueResult<long>(), Is.EqualTo(0L));
Expand Down
Loading