Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 26f8d35

Browse files
authored
Fix empty dynamic components causing a phantom update (#3600)
Fix #3421
1 parent b4f8b01 commit 26f8d35

File tree

5 files changed

+227
-32
lines changed

5 files changed

+227
-32
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
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 System.Collections.Generic;
12+
using System.Linq;
13+
using NHibernate.Cfg;
14+
using NHibernate.Cfg.MappingSchema;
15+
using NHibernate.Mapping.ByCode;
16+
using NHibernate.SqlCommand;
17+
using NUnit.Framework;
18+
using NHibernate.Linq;
19+
20+
namespace NHibernate.Test.NHSpecificTest.GH3421
21+
{
22+
using System.Threading.Tasks;
23+
[TestFixture]
24+
public class ByCodeFixtureAsync : TestCaseMappingByCode
25+
{
26+
private SqlInterceptor _interceptor;
27+
28+
protected override HbmMapping GetMappings()
29+
{
30+
var mapper = new ModelMapper();
31+
mapper.Class<Entity>(rc =>
32+
{
33+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
34+
rc.Property(x => x.Name);
35+
rc.Component(x => x.Attributes, new {
36+
Sku = (string)null
37+
}, dc => {
38+
dc.Property(x => x.Sku);
39+
});
40+
});
41+
42+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
43+
}
44+
45+
protected override void Configure(Configuration configuration)
46+
{
47+
base.Configure(configuration);
48+
49+
_interceptor = new SqlInterceptor();
50+
51+
configuration.SetInterceptor(_interceptor);
52+
}
53+
54+
protected override void OnSetUp()
55+
{
56+
using (var session = OpenSession())
57+
using (var transaction = session.BeginTransaction())
58+
{
59+
var e1 = new Entity { Name = "Bob" };
60+
session.Save(e1);
61+
62+
var e2 = new Entity { Name = "Sally", Attributes = new Dictionary<string, object>() {
63+
{ "Sku", "AAA" }
64+
} };
65+
session.Save(e2);
66+
67+
transaction.Commit();
68+
}
69+
}
70+
71+
protected override void OnTearDown()
72+
{
73+
using (var session = OpenSession())
74+
using (var transaction = session.BeginTransaction())
75+
{
76+
session.CreateQuery("delete from Entity").ExecuteUpdate();
77+
transaction.Commit();
78+
}
79+
}
80+
81+
[Test]
82+
public async Task TestFlushDoesNotTriggerAnUpdateAsync()
83+
{
84+
using (var session = OpenSession())
85+
using (var transaction = session.BeginTransaction())
86+
{
87+
var foo = await (session.Query<Entity>().ToListAsync());
88+
89+
await (session.FlushAsync());
90+
91+
var updateStatements = _interceptor.SqlStatements.Where(s => s.ToString().ToUpper().Contains("UPDATE")).ToList();
92+
93+
Assert.That(updateStatements, Has.Count.EqualTo(0));
94+
}
95+
}
96+
97+
public class SqlInterceptor : EmptyInterceptor
98+
{
99+
public IList<SqlString> SqlStatements = new List<SqlString>();
100+
101+
public override SqlString OnPrepareStatement(SqlString sql)
102+
{
103+
SqlStatements.Add(sql);
104+
105+
return base.OnPrepareStatement(sql);
106+
}
107+
}
108+
}
109+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using System;
2+
using System.Collections.Generic;
3+
4+
namespace NHibernate.Test.NHSpecificTest.GH3421
5+
{
6+
class Entity
7+
{
8+
public virtual Guid Id { get; set; }
9+
public virtual string Name { get; set; }
10+
11+
private IDictionary<string, object> _attributes;
12+
public virtual IDictionary<string, object> Attributes {
13+
get {
14+
if (_attributes == null)
15+
_attributes = new Dictionary<string, object>();
16+
return _attributes;
17+
}
18+
set => _attributes = value;
19+
}
20+
}
21+
}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using NHibernate.Cfg;
4+
using NHibernate.Cfg.MappingSchema;
5+
using NHibernate.Mapping.ByCode;
6+
using NHibernate.SqlCommand;
7+
using NUnit.Framework;
8+
9+
namespace NHibernate.Test.NHSpecificTest.GH3421
10+
{
11+
[TestFixture]
12+
public class ByCodeFixture : TestCaseMappingByCode
13+
{
14+
private SqlInterceptor _interceptor;
15+
16+
protected override HbmMapping GetMappings()
17+
{
18+
var mapper = new ModelMapper();
19+
mapper.Class<Entity>(rc =>
20+
{
21+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
22+
rc.Property(x => x.Name);
23+
rc.Component(x => x.Attributes, new {
24+
Sku = (string)null
25+
}, dc => {
26+
dc.Property(x => x.Sku);
27+
});
28+
});
29+
30+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
31+
}
32+
33+
protected override void Configure(Configuration configuration)
34+
{
35+
base.Configure(configuration);
36+
37+
_interceptor = new SqlInterceptor();
38+
39+
configuration.SetInterceptor(_interceptor);
40+
}
41+
42+
protected override void OnSetUp()
43+
{
44+
using (var session = OpenSession())
45+
using (var transaction = session.BeginTransaction())
46+
{
47+
var e1 = new Entity { Name = "Bob" };
48+
session.Save(e1);
49+
50+
var e2 = new Entity { Name = "Sally", Attributes = new Dictionary<string, object>() {
51+
{ "Sku", "AAA" }
52+
} };
53+
session.Save(e2);
54+
55+
transaction.Commit();
56+
}
57+
}
58+
59+
protected override void OnTearDown()
60+
{
61+
using (var session = OpenSession())
62+
using (var transaction = session.BeginTransaction())
63+
{
64+
session.CreateQuery("delete from Entity").ExecuteUpdate();
65+
transaction.Commit();
66+
}
67+
}
68+
69+
[Test]
70+
public void TestFlushDoesNotTriggerAnUpdate()
71+
{
72+
using (var session = OpenSession())
73+
using (var transaction = session.BeginTransaction())
74+
{
75+
var foo = session.Query<Entity>().ToList();
76+
77+
session.Flush();
78+
79+
var updateStatements = _interceptor.SqlStatements.Where(s => s.ToString().ToUpper().Contains("UPDATE")).ToList();
80+
81+
Assert.That(updateStatements, Has.Count.EqualTo(0));
82+
}
83+
}
84+
85+
public class SqlInterceptor : EmptyInterceptor
86+
{
87+
public IList<SqlString> SqlStatements = new List<SqlString>();
88+
89+
public override SqlString OnPrepareStatement(SqlString sql)
90+
{
91+
SqlStatements.Add(sql);
92+
93+
return base.OnPrepareStatement(sql);
94+
}
95+
}
96+
}
97+
}

‎src/NHibernate/Async/Type/ComponentType.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,6 @@ public override async Task<bool> IsDirtyAsync(object x, object y, ISessionImplem
3333
{
3434
return false;
3535
}
36-
/*
37-
* NH Different behavior : we don't use the shortcut because NH-1101
38-
* let the tuplizer choose how cosiderer properties when the component is null.
39-
*/
40-
if (EntityMode != EntityMode.Poco && (x == null || y == null))
41-
{
42-
return true;
43-
}
4436
object[] xvalues = GetPropertyValues(x);
4537
object[] yvalues = GetPropertyValues(y);
4638
for (int i = 0; i < xvalues.Length; i++)
@@ -60,14 +52,6 @@ public override async Task<bool> IsDirtyAsync(object x, object y, bool[] checkab
6052
{
6153
return false;
6254
}
63-
/*
64-
* NH Different behavior : we don't use the shortcut because NH-1101
65-
* let the tuplizer choose how cosiderer properties when the component is null.
66-
*/
67-
if (EntityMode != EntityMode.Poco && (x == null || y == null))
68-
{
69-
return true;
70-
}
7155
object[] xvalues = GetPropertyValues(x);
7256
object[] yvalues = GetPropertyValues(y);
7357
int loc = 0;

‎src/NHibernate/Type/ComponentType.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -156,14 +156,6 @@ public override bool IsDirty(object x, object y, ISessionImplementor session)
156156
{
157157
return false;
158158
}
159-
/*
160-
* NH Different behavior : we don't use the shortcut because NH-1101
161-
* let the tuplizer choose how cosiderer properties when the component is null.
162-
*/
163-
if (EntityMode != EntityMode.Poco && (x == null || y == null))
164-
{
165-
return true;
166-
}
167159
object[] xvalues = GetPropertyValues(x);
168160
object[] yvalues = GetPropertyValues(y);
169161
for (int i = 0; i < xvalues.Length; i++)
@@ -182,14 +174,6 @@ public override bool IsDirty(object x, object y, bool[] checkable, ISessionImple
182174
{
183175
return false;
184176
}
185-
/*
186-
* NH Different behavior : we don't use the shortcut because NH-1101
187-
* let the tuplizer choose how cosiderer properties when the component is null.
188-
*/
189-
if (EntityMode != EntityMode.Poco && (x == null || y == null))
190-
{
191-
return true;
192-
}
193177
object[] xvalues = GetPropertyValues(x);
194178
object[] yvalues = GetPropertyValues(y);
195179
int loc = 0;

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /