Skip to content

Commit

Permalink
Use table group joins for many-to-many in Criteria and Entity loaders (
Browse files Browse the repository at this point in the history
…#2687)

Possible breaking change: Default not-found behavior now works correctly for many-to-many in Criteria so now it throws ObjectNotFoundException exception on many-to-many Criteria fetch for not found records.
  • Loading branch information
bahusoid committed Aug 1, 2023
1 parent d6fd1dc commit 4949174
Show file tree
Hide file tree
Showing 20 changed files with 581 additions and 279 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@

using System.Linq;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.Linq;
using NHibernate.SqlCommand;
using NHibernate.Transform;
Expand All @@ -20,7 +19,7 @@ namespace NHibernate.Test.NHSpecificTest.GH1994
{
using System.Threading.Tasks;
[TestFixture]
public class FixtureAsync : BugTestCase
public class ManyToManyFilteredFixtureAsync : BugTestCase
{
protected override void OnSetUp()
{
Expand All @@ -41,14 +40,7 @@ protected override void OnTearDown()
using (var session = OpenSession())
using (var transaction = session.BeginTransaction())
{
// The HQL delete does all the job inside the database without loading the entities, but it does
// not handle delete order for avoiding violating constraints if any. Use
// session.Delete("from System.Object");
// instead if in need of having NHibernate ordering the deletes, but this will cause
// loading the entities in the session.

session.Delete("from System.Object");

transaction.Commit();
}
}
Expand All @@ -70,9 +62,6 @@ public async Task TestUnfilteredLinqQueryAsync()
[Test]
public async Task TestFilteredByWhereCollectionLinqQueryAsync()
{
if(Dialect is PostgreSQLDialect)
Assert.Ignore("Dialect doesn't support 0/1 to bool implicit cast");

using (var s = OpenSession())
{
var query = await (s.Query<Asset>()
Expand Down Expand Up @@ -150,5 +139,31 @@ public async Task TestQueryOverRestrictionWithClauseAsync()
Assert.That(query[0].Documents.Count, Is.EqualTo(1), "filtered asset documents");
}
}

[Test]
public async Task LazyLoadAsync()
{
using (var s = OpenSession())
{
var asset = await (s.Query<Asset>().FirstAsync());
Assert.That(asset.Documents.Count, Is.EqualTo(2));
Assert.That(asset.DocumentsBag.Count, Is.EqualTo(2));
Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1));
}
}

[Test]
public async Task LazyLoadFilteredAsync()
{
using (var s = OpenSession())
{
s.EnableFilter("deletedFilter").SetParameter("deletedParam", false);

var asset = await (s.Query<Asset>().FirstAsync());
Assert.That(asset.Documents.Count, Is.EqualTo(1));
Assert.That(asset.DocumentsBag.Count, Is.EqualTo(1));
Assert.That(asset.DocumentsFiltered.Count, Is.EqualTo(1));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,78 +10,72 @@

using System;
using NHibernate.Cfg;
using NHibernate.Criterion;
using NHibernate.Transform;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.NH750
{
using System.Threading.Tasks;
[TestFixture]
public class FixtureAsync : BugTestCase
public class ManyToManyNotFoundIgnoreFixtureAsync : BugTestCase
{
protected override void OnTearDown()
{
using (ISession s = Sfi.OpenSession())
{
s.Delete("from Device");
s.Delete("from Drive");
s.Flush();
}
}
private int id1;
private int id2;

protected override void Configure(Configuration configuration)
protected override void OnSetUp()
{
configuration.SetProperty(Cfg.Environment.UseSecondLevelCache, "false");
base.Configure(configuration);
}

[Test]
public async Task DeviceOfDriveAsync()
{
int[] dvSavedId = new int[2];
Drive dr1 = new Drive("Drive 1");
Drive dr2 = new Drive("Drive 2");
Drive dr3 = new Drive("Drive 3");
Device dv1 = new Device("Device 1");
Device dv2 = new Device("Device 2");
using (ISession s = Sfi.OpenSession())
using (var s = Sfi.OpenSession())
using (var t = s.BeginTransaction())
{
await (s.SaveAsync(dr1));
await (s.SaveAsync(dr2));
await (s.SaveAsync(dr3));
dvSavedId[0] = (int) await (s.SaveAsync(dv1));
dvSavedId[1] = (int) await (s.SaveAsync(dv2));
await (s.FlushAsync());
s.Save(dr1);
s.Save(dr2);
s.Save(dr3);
dv1.Drives.Add(dr1);
dv1.Drives.Add(dr2);
dv2.Drives.Add(dr1);
dv2.Drives.Add(dr3);

id1 = (int) s.Save(dv1);
id2 = (int) s.Save(dv2);
s.Flush();

s.Clear();
s.Delete(dr3);
t.Commit();
}
}

dv1.Drives.Add(dr1);
dv1.Drives.Add(dr2);
dv2.Drives.Add(dr1);
dv2.Drives.Add(dr3);
protected override void OnTearDown()
{
using (ISession s = Sfi.OpenSession())
using (var t = s.BeginTransaction())
{
dvSavedId[0] = (int) await (s.SaveAsync(dv1));
dvSavedId[1] = (int) await (s.SaveAsync(dv2));
await (s.FlushAsync());
s.Delete("from Device");
s.Delete("from Drive");
t.Commit();
}
dv1 = null;
dv2 = null;
}

[Test]
public async Task DeviceOfDriveAsync()
{
Device dv1;
Device dv2;
using (ISession s = Sfi.OpenSession())
{
await (s.DeleteAsync(dr3));
await (s.FlushAsync());
dv1 = (Device) await (s.LoadAsync(typeof(Device), dvSavedId[0]));
dv2 = (Device) await (s.LoadAsync(typeof(Device), dvSavedId[1]));
dv1 = (Device) await (s.LoadAsync(typeof(Device), id1));
dv2 = (Device) await (s.LoadAsync(typeof(Device), id2));
}
Assert.AreEqual(2, dv1.Drives.Count);
// Verify one is missing
Assert.AreEqual(1, dv2.Drives.Count);
// Verify dv1 unchanged
Assert.IsTrue(dv1.Drives.Contains(dr1));
Assert.IsTrue(dv1.Drives.Contains(dr2));

// Verify dv2
Assert.IsTrue(dv2.Drives.Contains(dr1));
Assert.IsFalse(dv2.Drives.Contains(dr3));
Assert.That(dv1.Drives, Has.Count.EqualTo(2).And.None.Null);
// Verify one is missing
Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null);

//Make sure that flush didn't touch not-found="ignore" records for not modified collection
using (var s = Sfi.OpenSession())
Expand All @@ -99,7 +93,7 @@ public async Task DeviceOfDriveAsync()
using (var t = s.BeginTransaction())
{
dv2 = await (s.GetAsync<Device>(dv2.Id));
dv2.Drives.Add(dr2);
dv2.Drives.Add(dv1.Drives[1]);
await (t.CommitAsync());
}

Expand All @@ -120,5 +114,49 @@ async Task VerifyResultAsync(int expectedInCollection, int expectedInDb, string
}
}
}

[Test]
public async Task QueryOverFetchAsync()
{
using (var s = OpenSession())
{
var dv2 = await (s.QueryOver<Device>()
.Fetch(SelectMode.Fetch, x => x.Drives)
.Where(Restrictions.IdEq(id2))
.TransformUsing(Transformers.DistinctRootEntity)
.SingleOrDefaultAsync());

Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True);
Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null);
}
}

[Test]
public async Task HqlFetchAsync()
{
using (var s = OpenSession())
{
var dv2 = await (s.CreateQuery("from Device d left join fetch d.Drives where d.id = :id")
.SetResultTransformer(Transformers.DistinctRootEntity)
.SetParameter("id", id2)
.UniqueResultAsync<Device>());

Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True);
Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null);
}
}

[Test]
public async Task LazyLoadAsync()
{
using (var s = OpenSession())
{
var dv2 = await (s.GetAsync<Device>(id2));
await (NHibernateUtil.InitializeAsync(dv2.Drives));

Assert.That(NHibernateUtil.IsInitialized(dv2.Drives), Is.True);
Assert.That(dv2.Drives, Has.Count.EqualTo(1).And.None.Null);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
//------------------------------------------------------------------------------
// <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.Linq;
using NHibernate.Criterion;
using NHibernate.Linq;
using NHibernate.Transform;
using NUnit.Framework;

namespace NHibernate.Test.NHSpecificTest.NH750
{
using System.Threading.Tasks;
[TestFixture]
public class ManyToManyThrowsForNotFoundFixtureAsync : BugTestCase
{
private int _id;

protected override void OnSetUp()
{
using (var s = Sfi.OpenSession())
using (var t = s.BeginTransaction())
{
Device dv = new Device("Device");
Drive dr = new Drive("Drive");
s.Save(dr);
dv.DrivesNotIgnored.Add(dr);

_id = (int) s.Save(dv);
s.Flush();

s.Clear();
s.Delete(dr);
t.Commit();
}
}

protected override void OnTearDown()
{
using (var s = OpenSession())
using (var t = s.BeginTransaction())
{
s.Delete("from Device");
s.Delete("from Drive");
t.Commit();
}
}

[Test]
public async Task LazyLoadAsync()
{
using var s = OpenSession();
var device = await (s.GetAsync<Device>(_id));
Assert.ThrowsAsync<ObjectNotFoundException>(() => NHibernateUtil.InitializeAsync(device.DrivesNotIgnored));
}

[Test]
public void QueryOverFetchAsync()
{
using var s = OpenSession();
var queryOver = s.QueryOver<Device>()
.Fetch(SelectMode.Fetch, x => x.DrivesNotIgnored)
.Where(Restrictions.IdEq(_id))
.TransformUsing(Transformers.DistinctRootEntity);
Assert.ThrowsAsync<ObjectNotFoundException>(async () => await (NHibernateUtil.InitializeAsync(await (queryOver.SingleOrDefaultAsync()))));
}

[Test]
public void LinqFetchAsync()
{
using var s = OpenSession();
var query = s.Query<Device>()

.Fetch(x => x.DrivesNotIgnored)
.Where(x => x.Id == _id);
Assert.ThrowsAsync<ObjectNotFoundException>(async () => await (NHibernateUtil.InitializeAsync(await (query.SingleOrDefaultAsync()))));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,22 @@
//------------------------------------------------------------------------------


using System.Linq;
using NHibernate.Criterion;
using NHibernate.Linq;
using NUnit.Framework;

namespace NHibernate.Test.PropertyRef
{
using System.Threading.Tasks;
[TestFixture]
[TestFixture(Description = "NH-2180 (GH-1214)")]
public class ManyToManyPropertyRefFixtureAsync : TestCase
{
protected override string[] Mappings => new[] { "PropertyRef.ManyToManyWithPropertyRef.hbm.xml" };

protected override string MappingsAssembly => "NHibernate.Test";

private object _manyAId;
private long _manyAId;

protected override void OnSetUp()
{
Expand All @@ -34,7 +36,7 @@ protected override void OnSetUp()
var manyB2 = new ManyB { Number = 8, Value = "a value of b2" };
var manyB3 = new ManyB { Number = 12, Value = "a value of b3" };

_manyAId = session.Save(manyA);
_manyAId = (long) session.Save(manyA);
session.Save(manyB1);
session.Save(manyB2);
session.Save(manyB3);
Expand Down Expand Up @@ -144,5 +146,20 @@ bei System.ThrowHelper.ThrowKeyNotFoundException()

Assert.That(loadedManyA.ManyBs, Has.Count.EqualTo(3).And.None.Null);
}

[Test]
public async Task LinqFetchAsync()
{
using (var session = OpenSession())
{
var manyA = (await (session
.Query<ManyA>()
.Where(a => a.Id == _manyAId)
.FetchMany(a => a.ManyBs)
.ToListAsync()))
.First();
Assert.That(manyA.ManyBs, Has.Count.EqualTo(3).And.None.Null);
}
}
}
}
Loading

0 comments on commit 4949174

Please sign in to comment.