Skip to content

Commit f400ccb

Browse files
Merge branch '5.1.x'
2 parents 684587a + 91cd6e2 commit f400ccb

File tree

16 files changed

+309
-24
lines changed

16 files changed

+309
-24
lines changed

appveyor.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version: 5.1.2.{build}
1+
version: 5.1.3.{build}
22
image: Visual Studio 2017
33
environment:
44
matrix:

build-common/NHibernate.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<VersionMajor Condition="'$(VersionMajor)' == ''">5</VersionMajor>
55
<VersionMinor Condition="'$(VersionMinor)' == ''">1</VersionMinor>
6-
<VersionPatch Condition="'$(VersionPatch)' == ''">2</VersionPatch>
6+
<VersionPatch Condition="'$(VersionPatch)' == ''">3</VersionPatch>
77
<VersionSuffix Condition="'$(VersionSuffix)' == ''"></VersionSuffix>
88

99
<VersionPrefix>$(VersionMajor).$(VersionMinor).$(VersionPatch)</VersionPrefix>

build-common/common.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
<!-- This is used only for build folder -->
1515
<!-- TODO: Either remove or refactor to use NHibernate.props -->
16-
<property name="project.version" value="5.1.2" overwrite="false" />
17-
<property name="project.version.numeric" value="5.1.2" overwrite="false" />
16+
<property name="project.version" value="5.1.3" overwrite="false" />
17+
<property name="project.version.numeric" value="5.1.3" overwrite="false" />
1818

1919
<!-- properties used to connect to database for testing -->
2020
<include buildfile="nhibernate-properties.xml" />

releasenotes.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,20 @@
1+
Build 5.1.3
2+
=============================
3+
4+
Release notes - NHibernate - Version 5.1.3
5+
6+
** Bug
7+
8+
* #1741 Fix DbType.Binary registration in DB2Dialect
9+
* #1732 Dictionary failure in Loader
10+
* #1730 Query cache always missed in session having altered the entities
11+
* #1711 Fix static proxy serialization
12+
13+
** Task
14+
15+
* #1716 Release 5.1.3
16+
17+
118
Build 5.1.2
219
=============================
320

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
//------------------------------------------------------------------------------
2+
// <auto-generated>
3+
// This code was generated by AsyncGenerator.
4+
//
5+
// Changes to this file may cause incorrect behavior and will be lost if
6+
// the code is regenerated.
7+
// </auto-generated>
8+
//------------------------------------------------------------------------------
9+
10+
11+
using NHibernate.Cfg;
12+
using NUnit.Framework;
13+
14+
namespace NHibernate.Test.NHSpecificTest.GH1730
15+
{
16+
using System.Threading.Tasks;
17+
[TestFixture]
18+
public class FixtureAsync : BugTestCase
19+
{
20+
protected override void Configure(Configuration configuration)
21+
{
22+
cfg.SetProperty(Environment.GenerateStatistics, "true");
23+
}
24+
25+
protected override void OnTearDown()
26+
{
27+
using (var session = OpenSession())
28+
using (var transaction = session.BeginTransaction())
29+
{
30+
session.CreateQuery("delete from Entity").ExecuteUpdate();
31+
32+
transaction.Commit();
33+
}
34+
}
35+
36+
[Test]
37+
public async Task HitCacheInSameSessionAsync()
38+
{
39+
await (Sfi.EvictQueriesAsync());
40+
Sfi.Statistics.Clear();
41+
var entities = new System.Collections.Generic.List<Entity>();
42+
43+
using (var session = OpenSession())
44+
{
45+
using (var transaction = session.BeginTransaction())
46+
{
47+
for (int i = 0; i < 3; i++)
48+
{
49+
var e = new Entity { Name = "Name" + i };
50+
entities.Add(e);
51+
await (session.SaveAsync(e));
52+
}
53+
await (transaction.CommitAsync());
54+
}
55+
56+
var queryString = "from Entity";
57+
58+
using (var tx = session.BeginTransaction())
59+
{
60+
// this query will hit the database and create the cache
61+
await (session.CreateQuery(queryString).SetCacheable(true).ListAsync());
62+
await (tx.CommitAsync());
63+
}
64+
65+
using (var transaction = session.BeginTransaction())
66+
{
67+
//and this one SHOULD served by the cache
68+
await (session.CreateQuery(queryString).SetCacheable(true).ListAsync());
69+
await (transaction.CommitAsync());
70+
}
71+
72+
var qs = Sfi.Statistics.GetQueryStatistics(queryString);
73+
Assert.AreEqual(1, qs.CacheHitCount);
74+
Assert.AreEqual(1, qs.CachePutCount);
75+
}
76+
}
77+
}
78+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace NHibernate.Test.NHSpecificTest.GH1730
4+
{
5+
class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
}
10+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
using NHibernate.Cfg;
2+
using NUnit.Framework;
3+
4+
namespace NHibernate.Test.NHSpecificTest.GH1730
5+
{
6+
[TestFixture]
7+
public class Fixture : BugTestCase
8+
{
9+
protected override void Configure(Configuration configuration)
10+
{
11+
cfg.SetProperty(Environment.GenerateStatistics, "true");
12+
}
13+
14+
protected override void OnTearDown()
15+
{
16+
using (var session = OpenSession())
17+
using (var transaction = session.BeginTransaction())
18+
{
19+
session.CreateQuery("delete from Entity").ExecuteUpdate();
20+
21+
transaction.Commit();
22+
}
23+
}
24+
25+
[Test]
26+
public void HitCacheInSameSession()
27+
{
28+
Sfi.EvictQueries();
29+
Sfi.Statistics.Clear();
30+
var entities = new System.Collections.Generic.List<Entity>();
31+
32+
using (var session = OpenSession())
33+
{
34+
using (var transaction = session.BeginTransaction())
35+
{
36+
for (int i = 0; i < 3; i++)
37+
{
38+
var e = new Entity { Name = "Name" + i };
39+
entities.Add(e);
40+
session.Save(e);
41+
}
42+
transaction.Commit();
43+
}
44+
45+
var queryString = "from Entity";
46+
47+
using (var tx = session.BeginTransaction())
48+
{
49+
// this query will hit the database and create the cache
50+
session.CreateQuery(queryString).SetCacheable(true).List();
51+
tx.Commit();
52+
}
53+
54+
using (var transaction = session.BeginTransaction())
55+
{
56+
//and this one SHOULD served by the cache
57+
session.CreateQuery(queryString).SetCacheable(true).List();
58+
transaction.Commit();
59+
}
60+
61+
var qs = Sfi.Statistics.GetQueryStatistics(queryString);
62+
Assert.AreEqual(1, qs.CacheHitCount);
63+
Assert.AreEqual(1, qs.CachePutCount);
64+
}
65+
}
66+
}
67+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
3+
namespace="NHibernate.Test.NHSpecificTest.GH1730">
4+
5+
<class name="Entity">
6+
<id name="Id" generator="guid.comb"/>
7+
<property name="Name"/>
8+
</class>
9+
10+
</hibernate-mapping>

src/NHibernate.Test/StaticProxyTest/StaticProxyFactoryFixture.cs

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ public class PublicInterfaceTestClass : IPublic
4242
public virtual int Id { get; set; }
4343
}
4444

45+
[Serializable]
46+
public class SimpleTestClass
47+
{
48+
public virtual int Id { get; set; }
49+
}
50+
4551
[Serializable]
4652
public class CustomSerializationClass : ISerializable
4753
{
@@ -135,6 +141,58 @@ public void VerifyProxyForClassWithAdditionalInterface()
135141
#endif
136142
}
137143

144+
[Test]
145+
public void InitializedProxyStaysInitializedAfterDeserialization()
146+
{
147+
var factory = new StaticProxyFactory();
148+
factory.PostInstantiate(typeof(SimpleTestClass).FullName, typeof(SimpleTestClass), new HashSet<System.Type> {typeof(INHibernateProxy)}, null, null, null);
149+
var proxy = factory.GetProxy(2, null);
150+
Assert.That(proxy, Is.Not.Null, "proxy");
151+
Assert.That(NHibernateUtil.IsInitialized(proxy), Is.False, "proxy already initialized after creation");
152+
Assert.That(proxy.HibernateLazyInitializer, Is.Not.Null, "HibernateLazyInitializer");
153+
154+
var impl = new SimpleTestClass { Id = 2 };
155+
proxy.HibernateLazyInitializer.SetImplementation(impl);
156+
Assert.That(NHibernateUtil.IsInitialized(proxy), Is.True, "proxy not initialized after setting implementation");
157+
158+
var serializer = GetFormatter();
159+
object deserialized;
160+
using (var memoryStream = new MemoryStream())
161+
{
162+
serializer.Serialize(memoryStream, proxy);
163+
memoryStream.Seek(0L, SeekOrigin.Begin);
164+
deserialized = serializer.Deserialize(memoryStream);
165+
}
166+
Assert.That(deserialized, Is.Not.Null, "deserialized");
167+
Assert.That(deserialized, Is.InstanceOf<INHibernateProxy>());
168+
Assert.That(NHibernateUtil.IsInitialized(deserialized), Is.True, "proxy no more initialized after deserialization");
169+
Assert.That(deserialized, Is.InstanceOf<SimpleTestClass>());
170+
Assert.That(((SimpleTestClass) deserialized).Id, Is.EqualTo(2));
171+
}
172+
173+
[Test]
174+
public void NonInitializedProxyStaysNonInitializedAfterSerialization()
175+
{
176+
var factory = new StaticProxyFactory();
177+
factory.PostInstantiate(typeof(SimpleTestClass).FullName, typeof(SimpleTestClass), new HashSet<System.Type> {typeof(INHibernateProxy)}, null, null, null);
178+
var proxy = factory.GetProxy(2, null);
179+
Assert.That(proxy, Is.Not.Null, "proxy");
180+
Assert.That(NHibernateUtil.IsInitialized(proxy), Is.False, "proxy already initialized after creation");
181+
182+
var serializer = GetFormatter();
183+
object deserialized;
184+
using (var memoryStream = new MemoryStream())
185+
{
186+
serializer.Serialize(memoryStream, proxy);
187+
Assert.That(NHibernateUtil.IsInitialized(proxy), Is.False, "proxy initialized after serialization");
188+
memoryStream.Seek(0L, SeekOrigin.Begin);
189+
deserialized = serializer.Deserialize(memoryStream);
190+
}
191+
Assert.That(deserialized, Is.Not.Null, "deserialized");
192+
Assert.That(deserialized, Is.InstanceOf<INHibernateProxy>());
193+
Assert.That(NHibernateUtil.IsInitialized(deserialized), Is.False, "proxy initialized after deserialization");
194+
}
195+
138196
[Test]
139197
public void CanSerializeFieldInterceptorProxy()
140198
{

src/NHibernate/Async/Cache/StandardQueryCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ public async Task<bool> PutAsync(QueryKey key, ICacheAssembler[] returnTypes, IL
4141
if (isNaturalKeyLookup && result.Count == 0)
4242
return false;
4343

44-
long ts = session.Timestamp;
44+
long ts = session.Factory.Settings.CacheProvider.NextTimestamp();
4545

4646
if (Log.IsDebugEnabled())
4747
Log.Debug("caching query results in region: '{0}'; {1}", _regionName, key);

src/NHibernate/Async/Loader/Loader.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
using System;
1212
using System.Collections;
13+
using System.Collections.Concurrent;
1314
using System.Collections.Generic;
1415
using System.Data;
1516
using System.Data.Common;

src/NHibernate/Cache/StandardQueryCache.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public bool Put(QueryKey key, ICacheAssembler[] returnTypes, IList result, bool
6060
if (isNaturalKeyLookup && result.Count == 0)
6161
return false;
6262

63-
long ts = session.Timestamp;
63+
long ts = session.Factory.Settings.CacheProvider.NextTimestamp();
6464

6565
if (Log.IsDebugEnabled())
6666
Log.Debug("caching query results in region: '{0}'; {1}", _regionName, key);

src/NHibernate/Dialect/DB2Dialect.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ public DB2Dialect()
3232
RegisterColumnType(DbType.AnsiString, "VARCHAR(254)");
3333
RegisterColumnType(DbType.AnsiString, 8000, "VARCHAR($l)");
3434
RegisterColumnType(DbType.AnsiString, 2147483647, "CLOB");
35+
RegisterColumnType(DbType.Binary, "BLOB");
3536
RegisterColumnType(DbType.Binary, 2147483647, "BLOB");
3637
RegisterColumnType(DbType.Boolean, "SMALLINT");
3738
RegisterColumnType(DbType.Byte, "SMALLINT");

src/NHibernate/Loader/Loader.cs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections;
3+
using System.Collections.Concurrent;
34
using System.Collections.Generic;
45
using System.Data;
56
using System.Data.Common;
@@ -31,17 +32,21 @@ namespace NHibernate.Loader
3132
/// Abstract superclass of object loading (and querying) strategies.
3233
/// </summary>
3334
/// <remarks>
34-
/// <p>
35+
/// <para>
3536
/// This class implements useful common functionality that concrete loaders would delegate to.
3637
/// It is not intended that this functionality would be directly accessed by client code (Hence,
3738
/// all methods of this class are declared <c>protected</c> or <c>private</c>.) This class relies heavily upon the
38-
/// <see cref="ILoadable" /> interface, which is the contract between this class and
39+
/// <see cref="ILoadable" /> interface, which is the contract between this class and
3940
/// <see cref="IEntityPersister" />s that may be loaded by it.
40-
/// </p>
41-
/// <p>
42-
/// The present implementation is able to load any number of columns of entities and at most
41+
/// </para>
42+
/// <para>
43+
/// The present implementation is able to load any number of columns of entities and at most
4344
/// one collection role per query.
44-
/// </p>
45+
/// </para>
46+
/// <para>
47+
/// All this class members are thread safe. Entity and collection loaders are held in persisters shared among
48+
/// sessions built from the same session factory. They must be thread safe.
49+
/// </para>
4550
/// </remarks>
4651
/// <seealso cref="NHibernate.Persister.Entity.ILoadable"/>
4752
public abstract partial class Loader
@@ -63,8 +68,8 @@ public abstract partial class Loader
6368
/// <summary>
6469
/// Caches subclass entity aliases for given persister index in <see cref="EntityPersisters"/> and subclass entity name
6570
/// </summary>
66-
private readonly Dictionary<Tuple<int, string>, string[][]> _subclassEntityAliasesMap = new Dictionary<Tuple<int, string>, string[][]>();
67-
71+
private readonly ConcurrentDictionary<Tuple<int, string>, string[][]> _subclassEntityAliasesMap = new ConcurrentDictionary<Tuple<int, string>, string[][]>();
72+
6873
protected Loader(ISessionFactoryImplementor factory)
6974
{
7075
_factory = factory;
@@ -1128,14 +1133,9 @@ private void LoadFromResultSet(DbDataReader rs, int i, object obj, string instan
11281133
private string[][] GetSubclassEntityAliases(int i, ILoadable persister)
11291134
{
11301135
var cacheKey = System.Tuple.Create(i, persister.EntityName);
1131-
if (_subclassEntityAliasesMap.TryGetValue(cacheKey, out string[][] cols))
1132-
{
1133-
return cols;
1134-
}
1135-
1136-
cols = EntityAliases[i].GetSuffixedPropertyAliases(persister);
1137-
_subclassEntityAliasesMap[cacheKey] = cols;
1138-
return cols;
1136+
return _subclassEntityAliasesMap.GetOrAdd(
1137+
cacheKey,
1138+
k => EntityAliases[i].GetSuffixedPropertyAliases(persister));
11391139
}
11401140

11411141
/// <summary>

0 commit comments

Comments
 (0)