Skip to content

Commit a2f9a27

Browse files
Fix NotNullUnique not taken into account for single column (nhibernate#1855)
And rename it, because it was originally meant for another usage
1 parent 7f3dec8 commit a2f9a27

File tree

8 files changed

+204
-7
lines changed

8 files changed

+204
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
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.MappingSchema;
12+
using NHibernate.Dialect;
13+
using NHibernate.Mapping.ByCode;
14+
using NUnit.Framework;
15+
16+
namespace NHibernate.Test.DialectTest.SchemaTests
17+
{
18+
using System.Threading.Tasks;
19+
[TestFixture]
20+
public class NullInUniqueFixtureAsync: TestCaseMappingByCode
21+
{
22+
protected override HbmMapping GetMappings()
23+
{
24+
var mapper = new ModelMapper();
25+
mapper.Class<Entity>(
26+
rc =>
27+
{
28+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
29+
rc.Property(x => x.Name, m => m.Unique(true));
30+
rc.Property(
31+
x => x.Name1,
32+
m =>
33+
{
34+
m.NotNullable(true);
35+
m.UniqueKey("Test");
36+
});
37+
rc.Property(x => x.Name2, m => m.UniqueKey("Test"));
38+
});
39+
40+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
41+
}
42+
43+
protected override void OnTearDown()
44+
{
45+
using (var session = Sfi.OpenSession())
46+
using (var transaction = session.BeginTransaction())
47+
{
48+
session.CreateQuery("delete from Entity").ExecuteUpdate();
49+
transaction.Commit();
50+
}
51+
}
52+
53+
[Test]
54+
public async Task InsertNullInUniqueAsync()
55+
{
56+
using (var session = OpenSession())
57+
using (var transaction = session.BeginTransaction())
58+
{
59+
await (session.SaveAsync(new Entity { Name1 = "1" }));
60+
await (session.SaveAsync(new Entity { Name = "N", Name1 = "1", Name2 = "2"}));
61+
await (session.SaveAsync(new Entity { Name = "Na", Name1 = "2", Name2 = "1"}));
62+
await (session.SaveAsync(new Entity { Name = "Nam", Name1 = "2"}));
63+
await (transaction.CommitAsync());
64+
}
65+
}
66+
}
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
using NHibernate.Cfg.MappingSchema;
2+
using NHibernate.Dialect;
3+
using NHibernate.Mapping.ByCode;
4+
using NUnit.Framework;
5+
6+
namespace NHibernate.Test.DialectTest.SchemaTests
7+
{
8+
public class DialectNotSupportingNullInUnique : GenericDialect
9+
{
10+
public override bool SupportsNullInUnique => false;
11+
}
12+
13+
[TestFixture]
14+
public class DialectNotSupportingNullInUniqueFixture
15+
{
16+
protected HbmMapping GetMappings()
17+
{
18+
var mapper = new ModelMapper();
19+
mapper.Class<Entity>(
20+
rc =>
21+
{
22+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
23+
rc.Property(x => x.Name, m => m.Unique(true));
24+
rc.Property(
25+
x => x.Name1,
26+
m =>
27+
{
28+
m.NotNullable(true);
29+
m.UniqueKey("Test");
30+
});
31+
rc.Property(x => x.Name2, m => m.UniqueKey("Test"));
32+
});
33+
34+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
35+
}
36+
37+
[Test]
38+
public void ScriptGenerationForDialectNotSupportingNullInUnique()
39+
{
40+
var configuration = TestConfigurationHelper.GetDefaultConfiguration();
41+
configuration.AddMapping(GetMappings());
42+
43+
var script = configuration.GenerateSchemaCreationScript(new DialectNotSupportingNullInUnique());
44+
45+
Assert.That(script, Has.None.Contains("unique"));
46+
}
47+
}
48+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
3+
namespace NHibernate.Test.DialectTest.SchemaTests
4+
{
5+
public class Entity
6+
{
7+
public virtual Guid Id { get; set; }
8+
public virtual string Name { get; set; }
9+
public virtual string Name1 { get; set; }
10+
public virtual string Name2 { get; set; }
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
using NHibernate.Cfg.MappingSchema;
2+
using NHibernate.Dialect;
3+
using NHibernate.Mapping.ByCode;
4+
using NUnit.Framework;
5+
6+
namespace NHibernate.Test.DialectTest.SchemaTests
7+
{
8+
[TestFixture]
9+
public class NullInUniqueFixture: TestCaseMappingByCode
10+
{
11+
protected override HbmMapping GetMappings()
12+
{
13+
var mapper = new ModelMapper();
14+
mapper.Class<Entity>(
15+
rc =>
16+
{
17+
rc.Id(x => x.Id, m => m.Generator(Generators.GuidComb));
18+
rc.Property(x => x.Name, m => m.Unique(true));
19+
rc.Property(
20+
x => x.Name1,
21+
m =>
22+
{
23+
m.NotNullable(true);
24+
m.UniqueKey("Test");
25+
});
26+
rc.Property(x => x.Name2, m => m.UniqueKey("Test"));
27+
});
28+
29+
return mapper.CompileMappingForAllExplicitlyAddedEntities();
30+
}
31+
32+
protected override void OnTearDown()
33+
{
34+
using (var session = Sfi.OpenSession())
35+
using (var transaction = session.BeginTransaction())
36+
{
37+
session.CreateQuery("delete from Entity").ExecuteUpdate();
38+
transaction.Commit();
39+
}
40+
}
41+
42+
[Test]
43+
public void InsertNullInUnique()
44+
{
45+
using (var session = OpenSession())
46+
using (var transaction = session.BeginTransaction())
47+
{
48+
session.Save(new Entity { Name1 = "1" });
49+
session.Save(new Entity { Name = "N", Name1 = "1", Name2 = "2"});
50+
session.Save(new Entity { Name = "Na", Name1 = "2", Name2 = "1"});
51+
session.Save(new Entity { Name = "Nam", Name1 = "2"});
52+
transaction.Commit();
53+
}
54+
}
55+
}
56+
}

src/NHibernate.Test/NHSpecificTest/NH3749/TestDialect.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ namespace NHibernate.Test.NHSpecificTest.NH3749
33
{
44
public class TestDialect : Dialect.Dialect
55
{
6-
public override bool SupportsNotNullUnique
6+
public override bool SupportsNullInUnique
77
{
88
get { return false; }
99
}
1010
}
11-
}
11+
}

src/NHibernate/Dialect/Dialect.cs

+14
Original file line numberDiff line numberDiff line change
@@ -468,11 +468,25 @@ public virtual bool SupportsCascadeDelete
468468
get { return true; }
469469
}
470470

471+
// Since v5.2
472+
[Obsolete("Use or override SupportsNullInUnique instead")]
471473
public virtual bool SupportsNotNullUnique
472474
{
473475
get { return true; }
474476
}
475477

478+
/// <summary>
479+
/// Does this dialect supports <c>null</c> values in columns belonging to an unique constraint/index?
480+
/// </summary>
481+
/// <remarks>Some databases do not accept <c>null</c> in unique constraints at all. In such case,
482+
/// this property should be overriden for yielding <c>false</c>. This property is not meant for distinguishing
483+
/// databases ignoring <c>null</c> when checking uniqueness (ANSI behavior) from those considering <c>null</c>
484+
/// as a value and checking for its uniqueness.</remarks>
485+
public virtual bool SupportsNullInUnique
486+
#pragma warning disable 618
487+
=> SupportsNotNullUnique;
488+
#pragma warning restore 618
489+
476490
public virtual IDataBaseSchema GetDataBaseSchema(DbConnection connection)
477491
{
478492
throw new NotSupportedException();

src/NHibernate/Mapping/Table.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -406,7 +406,7 @@ public string SqlCreateString(Dialect.Dialect dialect, IMapping p, string defaul
406406

407407
if (col.IsUnique)
408408
{
409-
if (dialect.SupportsUnique)
409+
if (dialect.SupportsUnique && (!col.IsNullable || dialect.SupportsNullInUnique))
410410
{
411411
buf.Append(" unique");
412412
}
@@ -669,7 +669,7 @@ public string[] SqlAlterStrings(Dialect.Dialect dialect, IMapping p, ITableMetad
669669
}
670670

671671
bool useUniqueConstraint = column.Unique && dialect.SupportsUnique
672-
&& (!column.IsNullable || dialect.SupportsNotNullUnique);
672+
&& (!column.IsNullable || dialect.SupportsNullInUnique);
673673
if (useUniqueConstraint)
674674
{
675675
alter.Append(" unique");

src/NHibernate/Mapping/UniqueKey.cs

+3-3
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public string SqlConstraintString(Dialect.Dialect dialect)
3232
buf.Append(column.GetQuotedName(dialect));
3333
}
3434
//do not add unique constraint on DB not supporting unique and nullable columns
35-
return !nullable || dialect.SupportsNotNullUnique ? buf.Append(StringHelper.ClosedParen).ToString() : null;
35+
return !nullable || dialect.SupportsNullInUnique ? buf.Append(StringHelper.ClosedParen).ToString() : null;
3636
}
3737

3838
/// <summary>
@@ -63,7 +63,7 @@ public override string SqlConstraintString(Dialect.Dialect dialect, string const
6363
}
6464

6565
return
66-
!nullable || dialect.SupportsNotNullUnique
66+
!nullable || dialect.SupportsNullInUnique
6767
? StringHelper.Replace(buf.Append(StringHelper.ClosedParen).ToString(), "primary key", "unique")
6868
: null;
6969
}
@@ -103,7 +103,7 @@ public override string SqlDropString(Dialect.Dialect dialect, string defaultCata
103103

104104
public override bool IsGenerated(Dialect.Dialect dialect)
105105
{
106-
if (dialect.SupportsNotNullUnique)
106+
if (dialect.SupportsNullInUnique)
107107
return true;
108108
foreach (Column column in ColumnIterator)
109109
{

0 commit comments

Comments
 (0)