Skip to content

Commit 1564561

Browse files
authored
Merge branch 'master' into WIP_groupJoin
2 parents a971797 + 0fb8160 commit 1564561

File tree

75 files changed

+3070
-293
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+3070
-293
lines changed

releasenotes.txt

+61-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,36 @@
1-
Build 5.3.2
1+
Build 5.3.3
2+
=============================
3+
4+
Release notes - NHibernate - Version 5.3.3
5+
6+
16 issues were resolved in this release.
7+
8+
** Bug
9+
10+
* #2519 Fix parameter caching for Linq provider
11+
* #2515 InvalidCastException for Linq query with subquery
12+
* #2514 Entity with field interceptor are not correctly passed as Linq parameters
13+
* #2512 Linq queries with a condition after a projection on a collection fail
14+
* #2511 Linq Fetch over component after fetching a many-to-one throws exception
15+
* #2508 OnPreUpdateCollection - Passed entity instance X is not of expected type Y
16+
* #2499 Cast operation fails when an enum is mapped as an AnsiString
17+
* #2490 Unnecessary cast in sql with Linq are causing performance issues
18+
* #2488 Fix parameter detection for Equals and CompareTo methods for Linq provider
19+
* #2485 Throw entity not mapped exception for entity join in hql if possible
20+
* #2484 Entity Joins are not polymorphic in hql
21+
* #2476 Hashset add returns true instead of false
22+
* #2474 Fetch all lazy properties when entity is already loaded fails
23+
* #2471 AsQueryable() on collection throws if applied after Where statement
24+
25+
** Task
26+
27+
* #2482 Add missing possible breaking changes for #2010
28+
* #2527 Release 5.3.3
29+
30+
As part of releasing 5.3.3, two missing 5.3.0 possible breaking changes have been added, about
31+
uninitialized extra lazy collections and SQLite schema validation. See 5.3.0 possible breaking changes.
32+
33+
Build 5.3.2
234
=============================
335

436
Release notes - NHibernate - Version 5.3.2
@@ -69,12 +101,40 @@ Release notes - NHibernate - Version 5.3.0
69101
stored as `REAL` instead of `NUMERIC`. Both are binary floating point types, excepted that `NUMERIC`
70102
stores integral values as `INTEGER`. This change may cause big integral decimal values to lose more
71103
precision in SQLite.
104+
* SQLite: non supported SQL type names previously used by NHibernate, resulting in unexpected actual typing,
105+
have been fixed. This causes databases generated by a previous NHibernate version to fail schema validation
106+
by 5.3 or higher versions. See #2507 for more information.
72107
* Custom dialects used for databases that do not support cross join will have to override
73108
`SupportsCrossJoin` property and set it to `false`.
74109
* `VisitorParameters.ConstantToParameterMap` may contain the same parameter for multiple constant
75110
expressions.
76111
* `ICache` caches yielded by the session factory will be `CacheBase` wrappers around the cache actually
77112
provided by the cache provider, if it was not deriving from `CacheBase`.
113+
* Calling `IList.RemoveAt` or `IList<>.RemoveAt` on an uninitialized list with a negative number
114+
will now throw an `ArgumentOutOfRangeException`.
115+
* Calling `IList.RemoveAt` or `IList<>.RemoveAt` on an uninitialized list mapped as `lazy="extra"`
116+
with a number that is equal or higher that the current collection size will now throw an
117+
`ArgumentOutOfRangeException`.
118+
* Calling `IList.Insert` or `IList<>.Insert` on an uninitialized list with a negative number will
119+
now throw an `ArgumentOutOfRangeException`.
120+
* Calling `IList.Insert` or `IList<>.Insert` on an uninitialized list mapped as `lazy="extra"`
121+
with a number that is higher that the current collection size will now throw an
122+
`ArgumentOutOfRangeException`.
123+
* Getting or setting a value with `IList.this[int index]` or `IList<>.this[int index]` on an uninitialized
124+
list with a negative number will now throw an `ArgumentOutOfRangeException`.
125+
* Setting a value with `IList.this[int index]` or `IList<>.this[int index]` on an uninitialized list
126+
mapped as `lazy="extra"` with a number that is equal or higher that the current collection size will now
127+
throw an `ArgumentOutOfRangeException`.
128+
* Calling `IDictionary<,>.Add` or `ICollection<>.Add` on an uninitialized map mapped as `lazy="extra"` with
129+
a key that already exists will now throw an `ArgumentException`.
130+
* Calling `IDictionary<,>.Remove` or `ICollection<>.Remove` on an uninitialized map mapped as `lazy="extra"`
131+
with a key that does not exist will now return false.
132+
* Map dirtiness is now evaluated by `EqualityComparer<TValue>.Default` when setting an existing key value
133+
with `IDictionary<,>.this[]` on an initialized map.
134+
* Calling `ISet<>.Add` on an uninitialized set mapped as `lazy="extra"` with a transient element that
135+
already exists in the set will now return false.
136+
* Calling `ISet<>.Add` or `ICollection<>.Add` on an uninitialized set mapped as `lazy="true"` with a
137+
transient element that does not override `Equals` method will not initialize the collection.
78138

79139
** Bug
80140

src/NHibernate.DomainModel/Northwind/Entities/AnotherEntityRequired.cs

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ public class AnotherEntityRequired
2222

2323
public virtual ISet<AnotherEntity> RelatedItems { get; set; } = new HashSet<AnotherEntity>();
2424

25+
public virtual ISet<AnotherEntityRequired> RequiredRelatedItems { get; set; } = new HashSet<AnotherEntityRequired>();
26+
2527
public virtual bool? NullableBool { get; set; }
2628
}
2729

src/NHibernate.DomainModel/Northwind/Entities/Northwind.cs

+5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ public IQueryable<User> Users
6969
get { return _session.Query<User>(); }
7070
}
7171

72+
public IQueryable<NumericEntity> NumericEntities
73+
{
74+
get { return _session.Query<NumericEntity>(); }
75+
}
76+
7277
public IQueryable<DynamicUser> DynamicUsers
7378
{
7479
get { return _session.Query<DynamicUser>(); }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
namespace NHibernate.DomainModel.Northwind.Entities
2+
{
3+
public class NumericEntity
4+
{
5+
public virtual short Short { get; set; }
6+
7+
public virtual short? NullableShort { get; set; }
8+
9+
public virtual int Integer { get; set; }
10+
11+
public virtual int? NullableInteger { get; set; }
12+
13+
public virtual long Long { get; set; }
14+
15+
public virtual long? NullableLong { get; set; }
16+
17+
public virtual decimal Decimal { get; set; }
18+
19+
public virtual decimal? NullableDecimal { get; set; }
20+
21+
public virtual float Single { get; set; }
22+
23+
public virtual float? NullableSingle { get; set; }
24+
25+
public virtual double Double { get; set; }
26+
27+
public virtual double? NullableDouble { get; set; }
28+
}
29+
}

src/NHibernate.DomainModel/Northwind/Mappings/AnotherEntityRequired.hbm.xml

+4
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,9 @@
1919
<key column="Id"/>
2020
<one-to-many class="AnotherEntity"/>
2121
</set>
22+
<set name="RequiredRelatedItems" lazy="true" inverse="true">
23+
<key column="Id"/>
24+
<one-to-many class="AnotherEntityRequired"/>
25+
</set>
2226
</class>
2327
</hibernate-mapping>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" namespace="NHibernate.DomainModel.Northwind.Entities" assembly="NHibernate.DomainModel">
3+
<class name="NumericEntity">
4+
<id name="Short">
5+
<generator class="assigned" />
6+
</id>
7+
8+
<property name="NullableShort" />
9+
<property name="Integer" not-null="true" column="`Integer`" />
10+
<property name="NullableInteger" />
11+
<property name="Long" not-null="true" column="`Long`" />
12+
<property name="NullableLong" />
13+
<property name="Decimal" not-null="true" column="`Decimal`" />
14+
<property name="NullableDecimal" />
15+
<property name="Single" not-null="true" column="`Single`" />
16+
<property name="NullableSingle" />
17+
<property name="Double" not-null="true" column="`Double`" />
18+
<property name="NullableDouble" />
19+
</class>
20+
</hibernate-mapping>

src/NHibernate.Test/Async/Extralazy/ExtraLazyFixture.cs

+46
Original file line numberDiff line numberDiff line change
@@ -1326,6 +1326,52 @@ public async Task SetAddAsync(bool initialize)
13261326
}
13271327
}
13281328

1329+
[Test]
1330+
public async Task SetAddWithOverrideEqualsAsync()
1331+
{
1332+
User gavin;
1333+
User robert;
1334+
User tom;
1335+
1336+
using (var s = OpenSession())
1337+
using (var t = s.BeginTransaction())
1338+
{
1339+
gavin = new User("gavin", "secret");
1340+
robert = new User("robert", "secret");
1341+
tom = new User("tom", "secret");
1342+
await (s.PersistAsync(gavin));
1343+
await (s.PersistAsync(robert));
1344+
await (s.PersistAsync(tom));
1345+
1346+
gavin.Followers.Add(new UserFollower(gavin, robert));
1347+
gavin.Followers.Add(new UserFollower(gavin, tom));
1348+
robert.Followers.Add(new UserFollower(robert, tom));
1349+
1350+
Assert.That(gavin.Followers.Count, Is.EqualTo(2), "Gavin's documents count after adding 2");
1351+
Assert.That(robert.Followers.Count, Is.EqualTo(1), "Robert's followers count after adding one");
1352+
1353+
await (t.CommitAsync());
1354+
}
1355+
1356+
using (var s = OpenSession())
1357+
using (var t = s.BeginTransaction())
1358+
{
1359+
gavin = await (s.GetAsync<User>("gavin"));
1360+
robert = await (s.GetAsync<User>("robert"));
1361+
tom = await (s.GetAsync<User>("tom"));
1362+
1363+
// Re-add
1364+
Assert.That(gavin.Followers.Add(new UserFollower(gavin, robert)), Is.False, "Re-adding element");
1365+
Assert.That(NHibernateUtil.IsInitialized(gavin.Followers), Is.True, "Documents initialization status after re-adding");
1366+
Assert.That(gavin.Followers, Has.Count.EqualTo(2), "Gavin's followers count after re-adding");
1367+
1368+
// Add new
1369+
Assert.That(robert.Followers.Add(new UserFollower(robert, gavin)), Is.True, "Adding element");
1370+
Assert.That(NHibernateUtil.IsInitialized(gavin.Followers), Is.True, "Documents initialization status after adding");
1371+
Assert.That(gavin.Followers, Has.Count.EqualTo(2), "Robert's followers count after re-adding");
1372+
}
1373+
}
1374+
13291375
[TestCase(false, false)]
13301376
[TestCase(false, true)]
13311377
[TestCase(true, false)]

src/NHibernate.Test/Async/FetchLazyProperties/FetchLazyPropertiesFixture.cs

+54
Original file line numberDiff line numberDiff line change
@@ -666,6 +666,40 @@ private static void AssertFetchComponentManyToOne(Person person)
666666

667667
#endregion
668668

669+
#region TestHqlFetchManyToOneAndComponentManyToOne
670+
671+
[Test]
672+
public async Task TestHqlFetchManyToOneAndComponentManyToOneAsync()
673+
{
674+
Person person;
675+
using (var s = OpenSession())
676+
{
677+
person = await (s.CreateQuery("from Person p fetch p.Address left join fetch p.Address.Continent left join fetch p.BestFriend where p.Id = 1").UniqueResultAsync<Person>());
678+
}
679+
680+
AssertFetchManyToOneAndComponentManyToOne(person);
681+
}
682+
683+
[Test]
684+
public async Task TestLinqFetchManyToOneAndComponentManyToOneAsync()
685+
{
686+
Person person;
687+
using (var s = OpenSession())
688+
{
689+
person = await (s.Query<Person>().Fetch(o => o.BestFriend).Fetch(o => o.Address).ThenFetch(o => o.Continent).FirstOrDefaultAsync(o => o.Id == 1));
690+
}
691+
692+
AssertFetchManyToOneAndComponentManyToOne(person);
693+
}
694+
695+
private static void AssertFetchManyToOneAndComponentManyToOne(Person person)
696+
{
697+
AssertFetchComponentManyToOne(person);
698+
Assert.That(NHibernateUtil.IsInitialized(person.BestFriend), Is.True);
699+
}
700+
701+
#endregion
702+
669703
#region FetchSubClassFormula
670704

671705
[Test]
@@ -945,6 +979,26 @@ public async Task TestFetchAfterEntityIsInitializedAsync(bool readOnly)
945979
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Formula"), Is.True);
946980
}
947981

982+
[TestCase(true)]
983+
[TestCase(false)]
984+
public async Task TestFetchAllPropertiesAfterEntityIsInitializedAsync(bool readOnly)
985+
{
986+
Person person;
987+
using(var s = OpenSession())
988+
using(var tx = s.BeginTransaction())
989+
{
990+
person = await (s.CreateQuery("from Person where Id = 1").SetReadOnly(readOnly).UniqueResultAsync<Person>());
991+
var image = person.Image;
992+
person = await (s.CreateQuery("from Person fetch all properties where Id = 1").SetReadOnly(readOnly).UniqueResultAsync<Person>());
993+
994+
await (tx.CommitAsync());
995+
}
996+
997+
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Image"), Is.True);
998+
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Address"), Is.True);
999+
Assert.That(NHibernateUtil.IsPropertyInitialized(person, "Formula"), Is.True);
1000+
}
1001+
9481002
[Test]
9491003
public async Task TestHqlCrossJoinFetchFormulaAsync()
9501004
{

src/NHibernate.Test/Async/Linq/ByMethod/JoinTests.cs

+8
Original file line numberDiff line numberDiff line change
@@ -140,5 +140,13 @@ from o2 in db.Orders.Where(x => x.Freight > 50)
140140
Assert.That(GetTotalOccurrences(sql, "inner join"), Is.EqualTo(useCrossJoin ? 0 : 1));
141141
}
142142
}
143+
144+
[Test]
145+
public async Task CanJoinOnEntityWithSubclassesAsync()
146+
{
147+
var result = await ((from o in db.Animals
148+
from o2 in db.Animals.Where(x => x.BodyWeight > 50)
149+
select new {o, o2}).Take(1).ToListAsync());
150+
}
143151
}
144152
}

src/NHibernate.Test/Async/Linq/ConstantTest.cs

+24
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
namespace NHibernate.Test.Linq
2323
{
2424
using System.Threading.Tasks;
25+
using System.Threading;
2526
// Mainly adapted from tests contributed by Nicola Tuveri on NH-2500 (NH-2500.patch file)
2627
[TestFixture]
2728
public class ConstantTestAsync : LinqTestCase
@@ -118,6 +119,29 @@ public async Task ConstantNonCachedInMemberInitExpressionAsync()
118119
Assert.That(s2, Has.All.Property("Name").EqualTo("shipper2"), "s2 Names");
119120
}
120121

122+
[Test]
123+
public async Task ConstantNonCachedInMemberInitExpressionWithConditionAsync()
124+
{
125+
var shipper1 = await (GetShipperAsync(1));
126+
var shipper2 = await (GetShipperAsync(2));
127+
128+
Assert.That(shipper1.Number, Is.EqualTo(1));
129+
Assert.That(shipper2.Number, Is.EqualTo(2));
130+
}
131+
132+
private Task<ShipperDto> GetShipperAsync(int id, CancellationToken cancellationToken = default(CancellationToken))
133+
{
134+
try
135+
{
136+
return db.Shippers.Where(o => o.ShipperId == id)
137+
.Select(o => new ShipperDto {Number = id, CompanyName = o.CompanyName}).SingleAsync(cancellationToken);
138+
}
139+
catch (System.Exception ex)
140+
{
141+
return Task.FromException<ShipperDto>(ex);
142+
}
143+
}
144+
121145
[Test]
122146
public async Task ConstantInNewArrayExpressionAsync()
123147
{

0 commit comments

Comments
 (0)