Skip to content

Fix caching of OneToOneType from second level cache. #2576

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 21 commits into from
Mar 20, 2021
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
e6df6f4
GH2552 Add basic OneToOneType persistence test.
Oct 9, 2020
e5e54b2
GH2552 Add basic async OneToOneType persistence test.
Oct 14, 2020
b639fc5
GH2552 Add tests for GitHub issue #2552
Oct 2, 2020
6e73422
GH2552 Add async tests for GitHub issue #2552
Oct 5, 2020
957740d
GH2552 Fix caching of OneToOneType from second level cache.
Oct 1, 2020
f947722
GH2552 Fix async caching of OneToOneType from second level cache.
Oct 5, 2020
d428898
GH2552 Implement isDirty for OneToOneType and always check if it is d…
Oct 14, 2020
137090f
GH2552 Implement async version of isDirty for OneToOneType.
Oct 14, 2020
04b140a
Test case for session.Update
bahusoid Nov 13, 2020
964faa7
GH2552 Async test for one-to-one session update.
Nov 17, 2020
b327a47
GH2552 Implement OneToOneType.IsModified based on the ManyToOneType.
Nov 17, 2020
e2b56ed
GH2552 Update acsync version of OneToOneType.IsModified.
Nov 17, 2020
551d170
GH2552 Only check if the OneToOneType is dirty when it is nullable.
Nov 17, 2020
9e6944a
GH2552 Rename tests to identifiy their purpose of testing fetching da…
Nov 17, 2020
ab23e13
GH2552 Add tests to verify that the cache is updated on delete.
Nov 18, 2020
65a12ea
GH2552 Add async version of tests to verify cache updated on delete.
Nov 18, 2020
57a5ed2
Small test fixes
bahusoid Nov 18, 2020
ffd4429
Merge branch 'master' into bug-2552
bahusoid Nov 18, 2020
b229332
Merge branch 'master' into bug-2552
deAtog Nov 19, 2020
6080660
Merge branch 'master' into bug-2552
deAtog Feb 24, 2021
26e370c
Fix minor formatting issues
fredericDelaporte Feb 25, 2021
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
141 changes: 141 additions & 0 deletions src/NHibernate.Test/Async/NHSpecificTest/GH2552/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
//------------------------------------------------------------------------------
// <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.Collections.Generic;
using System.Reflection;
using NHibernate.Cache;
using NHibernate.Stat;
using NHibernate.Test.CacheTest.Caches;
using NUnit.Framework;
using NHCfg = NHibernate.Cfg;

namespace NHibernate.Test.NHSpecificTest.GH2552
{
using System.Threading.Tasks;
using System.Threading;
[TestFixture]
public class FixtureAsync : BugTestCase
{
protected override string CacheConcurrencyStrategy => null;

protected override void Configure(NHCfg.Configuration configuration)
{
configuration.SetProperty(NHCfg.Environment.UseSecondLevelCache, "true");
configuration.SetProperty(NHCfg.Environment.GenerateStatistics, "true");
}

protected override void OnTearDown()
{
using (var s = OpenSession())
using (var tx = s.BeginTransaction())
{
s.CreateQuery("delete from DetailsByFK").ExecuteUpdate();
s.CreateQuery("delete from PersonByFK").ExecuteUpdate();
s.CreateQuery("delete from DetailsByRef").ExecuteUpdate();
s.CreateQuery("delete from PersonByRef").ExecuteUpdate();

tx.Commit();
}

Sfi.Evict(typeof(PersonByFK));
Sfi.Evict(typeof(DetailsByFK));
Sfi.Evict(typeof(PersonByRef));
Sfi.Evict(typeof(DetailsByRef));
}

private async Task OneToOneTestAsync<TPerson, TDetails>(CancellationToken cancellationToken = default(CancellationToken)) where TPerson : Person, new() where TDetails : Details, new()
{
List<object> ids = await (this.CreatePersonAndDetailsAsync<TPerson, TDetails>(cancellationToken));

IStatistics statistics = Sfi.Statistics;

// Clear the second level cache and the statistics
await (Sfi.EvictEntityAsync(typeof(TPerson).FullName, cancellationToken));
await (Sfi.EvictEntityAsync(typeof(TDetails).FullName, cancellationToken));
await (Sfi.EvictQueriesAsync(cancellationToken));

statistics.Clear();

// Fill the empty caches with data.
await (this.FetchPeopleByIdAsync<TPerson>(ids, cancellationToken));

// Verify that no data was retrieved from the cache.
Assert.AreEqual(0, statistics.SecondLevelCacheHitCount, "Second level cache hit count");

statistics.Clear();

await (this.FetchPeopleByIdAsync<TPerson>(ids, cancellationToken));

Assert.AreEqual(0, statistics.SecondLevelCacheMissCount, "Second level cache miss count");
}

private async Task<List<object>> CreatePersonAndDetailsAsync<TPerson, TDetails>(CancellationToken cancellationToken = default(CancellationToken)) where TPerson : Person, new() where TDetails : Details, new()
{
List<object> ids = new List<object>();

using (ISession s = Sfi.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
for (int i = 0; i < 6; i++)
{
Person person = new TPerson();

if (i % 2 == 0)
{
Details details = new TDetails();

details.Data = String.Format("{0}{1}", typeof(TDetails).Name, i);

person.Details = details;
}

person.Name = String.Format("{0}{1}", typeof(TPerson).Name, i);

ids.Add(await (s.SaveAsync(person, cancellationToken)));
}

await (tx.CommitAsync(cancellationToken));
}

return ids;
}

public async Task<IList<TPerson>> FetchPeopleByIdAsync<TPerson>(List<object> ids, CancellationToken cancellationToken = default(CancellationToken)) where TPerson : Person
{
IList<TPerson> people = new List<TPerson>();

using (ISession s = Sfi.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
foreach (object id in ids)
{
people.Add(await (s.GetAsync<TPerson>(id, cancellationToken)));
}

await (tx.CommitAsync(cancellationToken));
}

return people;
}

[Test]
public async Task OneToOneCacheByForeignKeyAsync()
{
await (OneToOneTestAsync<PersonByFK, DetailsByFK>());
}

[Test]
public async Task OneToOneCacheByRefAsync()
{
await (OneToOneTestAsync<PersonByRef, DetailsByRef>());
}
}
}
114 changes: 114 additions & 0 deletions src/NHibernate.Test/Async/OneToOneType/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
//------------------------------------------------------------------------------
// <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.Test.NHSpecificTest;
using NUnit.Framework;

namespace NHibernate.Test.OneToOneType
{
using System.Threading.Tasks;
[TestFixture]
public class FixtureAsync : BugTestCase
{
protected override void OnTearDown()
{
using (var s = Sfi.OpenSession())
using (var tx = s.BeginTransaction())
{
s.CreateQuery("delete from Details").ExecuteUpdate();
s.CreateQuery("delete from Owner").ExecuteUpdate();

tx.Commit();
}
}

[Test]
public async Task OneToOnePersistedOnOwnerUpdateAsync()
{
object ownerId;

using (var s = Sfi.OpenSession())
using (var tx = s.BeginTransaction())
{
var owner = new Owner()
{
Name = "Owner",
};

ownerId = await (s.SaveAsync(owner));

await (tx.CommitAsync());
}

using (var s = Sfi.OpenSession())
using (var tx = s.BeginTransaction())
{
Owner owner = await (s.LoadAsync<Owner>(ownerId));

owner.Details = new Details()
{
Data = "Owner Details"
};

await (tx.CommitAsync());
}

using (var s = Sfi.OpenSession())
using (var tx = s.BeginTransaction())
{
Owner owner = await (s.GetAsync<Owner>(ownerId));

Assert.NotNull(owner.Details);
}
}

[Test]
public async Task OneToOnePersistedOnOwnerUpdateForSessionUpdateAsync()
{
Owner owner;

using (var s = Sfi.OpenSession())
using (var tx = s.BeginTransaction())
{
owner = new Owner()
{
Name = "Owner",
};

await (s.SaveAsync(owner));
await (tx.CommitAsync());
}

using (var s = Sfi.OpenSession())
{
owner = await (s.GetAsync<Owner>(owner.Id));
}

using (var s = Sfi.OpenSession())
using (var tx = s.BeginTransaction())
{
await (s.SaveOrUpdateAsync(owner));
owner.Details = new Details()
{
Data = "Owner Details"
};

await (tx.CommitAsync());
}

using (var s = Sfi.OpenSession())
{
owner = await (s.GetAsync<Owner>(owner.Id));

Assert.IsNotNull(owner.Details);
}
}
}
}
11 changes: 11 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2552/Details.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
namespace NHibernate.Test.NHSpecificTest.GH2552
{
public abstract class Details
{
public virtual int Id { get; protected set; }
public virtual Person Person { get; set; }
public virtual string Data { get; set; }
}
public class DetailsByFK : Details { }
public class DetailsByRef : Details { }
}
129 changes: 129 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH2552/Fixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using NHibernate.Cache;
using NHibernate.Stat;
using NHibernate.Test.CacheTest.Caches;
using NUnit.Framework;
using NHCfg = NHibernate.Cfg;

namespace NHibernate.Test.NHSpecificTest.GH2552
{
[TestFixture]
public class Fixture : BugTestCase
{
protected override string CacheConcurrencyStrategy => null;

protected override void Configure(NHCfg.Configuration configuration)
{
configuration.SetProperty(NHCfg.Environment.UseSecondLevelCache, "true");
configuration.SetProperty(NHCfg.Environment.GenerateStatistics, "true");
}

protected override void OnTearDown()
{
using (var s = OpenSession())
using (var tx = s.BeginTransaction())
{
s.CreateQuery("delete from DetailsByFK").ExecuteUpdate();
s.CreateQuery("delete from PersonByFK").ExecuteUpdate();
s.CreateQuery("delete from DetailsByRef").ExecuteUpdate();
s.CreateQuery("delete from PersonByRef").ExecuteUpdate();

tx.Commit();
}

Sfi.Evict(typeof(PersonByFK));
Sfi.Evict(typeof(DetailsByFK));
Sfi.Evict(typeof(PersonByRef));
Sfi.Evict(typeof(DetailsByRef));
}

private void OneToOneTest<TPerson, TDetails>() where TPerson : Person, new() where TDetails : Details, new()
{
List<object> ids = this.CreatePersonAndDetails<TPerson, TDetails>();

IStatistics statistics = Sfi.Statistics;

// Clear the second level cache and the statistics
Sfi.EvictEntity(typeof(TPerson).FullName);
Sfi.EvictEntity(typeof(TDetails).FullName);
Sfi.EvictQueries();

statistics.Clear();

// Fill the empty caches with data.
this.FetchPeopleById<TPerson>(ids);

// Verify that no data was retrieved from the cache.
Assert.AreEqual(0, statistics.SecondLevelCacheHitCount, "Second level cache hit count");

statistics.Clear();

this.FetchPeopleById<TPerson>(ids);

Assert.AreEqual(0, statistics.SecondLevelCacheMissCount, "Second level cache miss count");
}

private List<object> CreatePersonAndDetails<TPerson, TDetails>() where TPerson : Person, new() where TDetails : Details, new()
{
List<object> ids = new List<object>();

using (ISession s = Sfi.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
for (int i = 0; i < 6; i++)
{
Person person = new TPerson();

if (i % 2 == 0)
{
Details details = new TDetails();

details.Data = String.Format("{0}{1}", typeof(TDetails).Name, i);

person.Details = details;
}

person.Name = String.Format("{0}{1}", typeof(TPerson).Name, i);

ids.Add(s.Save(person));
}

tx.Commit();
}

return ids;
}

public IList<TPerson> FetchPeopleById<TPerson>(List<object> ids) where TPerson : Person
{
IList<TPerson> people = new List<TPerson>();

using (ISession s = Sfi.OpenSession())
using (ITransaction tx = s.BeginTransaction())
{
foreach (object id in ids)
{
people.Add(s.Get<TPerson>(id));
}

tx.Commit();
}

return people;
}

[Test]
public void OneToOneCacheByForeignKey()
{
OneToOneTest<PersonByFK, DetailsByFK>();
}

[Test]
public void OneToOneCacheByRef()
{
OneToOneTest<PersonByRef, DetailsByRef>();
}
}
}
Loading