Skip to content

Commit 86b9e52

Browse files
NH-3884 - Allow redefining the NHibernate default type for a .Net type.
1 parent 1808caf commit 86b9e52

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace NHibernate.Test.TypesTest
4+
{
5+
public class ChangeDefaultTypeClass
6+
{
7+
public int Id { get; set; }
8+
9+
public DateTime NormalDateTimeValue { get; set; } = DateTime.Today;
10+
}
11+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
3+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-lazy="false">
4+
5+
<class
6+
name="NHibernate.Test.TypesTest.ChangeDefaultTypeClass, NHibernate.Test"
7+
table="bc_datetime"
8+
>
9+
10+
<id name="Id" column="id">
11+
<generator class="assigned"/>
12+
</id>
13+
14+
<property name="NormalDateTimeValue"/>
15+
</class>
16+
</hibernate-mapping>
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Reflection;
4+
using NHibernate.Cfg;
5+
using NHibernate.Engine;
6+
using NHibernate.Impl;
7+
using NHibernate.Type;
8+
using NUnit.Framework;
9+
10+
namespace NHibernate.Test.TypesTest
11+
{
12+
/// <summary>
13+
/// TestFixtures for changing a default .Net type.
14+
/// </summary>
15+
[TestFixture]
16+
public class ChangeDefaultTypeFixture : TypeFixtureBase
17+
{
18+
protected override string TypeName => "ChangeDefaultType";
19+
20+
private IType _originalDefaultDateTimeType;
21+
private IType _testDefaultDateTimeType;
22+
23+
protected override void Configure(Configuration configuration)
24+
{
25+
_originalDefaultDateTimeType = TypeFactory.GetDefaultTypeFor(typeof(DateTime));
26+
Assert.That(_originalDefaultDateTimeType, Is.Not.Null);
27+
_testDefaultDateTimeType = NHibernateUtil.DateTime.Equals(_originalDefaultDateTimeType)
28+
? (IType) NHibernateUtil.Timestamp
29+
: NHibernateUtil.DateTime;
30+
TypeFactory.SetDefaultType<DateTime>(_testDefaultDateTimeType);
31+
base.Configure(configuration);
32+
}
33+
34+
protected override void DropSchema()
35+
{
36+
base.DropSchema();
37+
if (_originalDefaultDateTimeType != null)
38+
TypeFactory.SetDefaultType<DateTime>(_originalDefaultDateTimeType);
39+
}
40+
41+
[Test]
42+
public void DefaultType()
43+
{
44+
Assert.That(TypeFactory.GetDefaultTypeFor(typeof(DateTime)), Is.EqualTo(_testDefaultDateTimeType));
45+
}
46+
47+
[Test]
48+
public void PropertyType()
49+
{
50+
Assert.That(
51+
Sfi.GetClassMetadata(typeof(ChangeDefaultTypeClass))
52+
.GetPropertyType(nameof(ChangeDefaultTypeClass.NormalDateTimeValue)),
53+
Is.EqualTo(_testDefaultDateTimeType));
54+
}
55+
56+
[Test]
57+
public void GuessType()
58+
{
59+
Assert.That(NHibernateUtil.GuessType(typeof(DateTime)), Is.EqualTo(_testDefaultDateTimeType));
60+
}
61+
62+
[Test]
63+
public void ParameterType()
64+
{
65+
var namedParametersField = typeof(AbstractQueryImpl)
66+
.GetField("namedParameters", BindingFlags.Instance | BindingFlags.NonPublic);
67+
Assert.That(namedParametersField, Is.Not.Null, "Missing internal field");
68+
69+
using (var s = OpenSession())
70+
{
71+
// Query where the parameter type cannot be deducted from compared entity property
72+
var q = s.CreateQuery($"from {nameof(ChangeDefaultTypeClass)} where :date1 = :date2 or :date1 = :date3")
73+
.SetParameter("date1", DateTime.Now)
74+
.SetDateTime("date2", DateTime.Now)
75+
.SetTimestamp("date3", DateTime.Now);
76+
77+
var namedParameters = namedParametersField.GetValue(q) as Dictionary<string, TypedValue>;
78+
Assert.That(namedParameters, Is.Not.Null, "Unable to retrieve parameters internal field");
79+
Assert.That(namedParameters["date1"].Type, Is.EqualTo(_testDefaultDateTimeType));
80+
Assert.That(namedParameters["date2"].Type, Is.EqualTo(NHibernateUtil.DateTime));
81+
Assert.That(namedParameters["date3"].Type, Is.EqualTo(NHibernateUtil.Timestamp));
82+
}
83+
}
84+
}
85+
}

src/NHibernate/Type/TypeFactory.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using System.Xml;
77
using System.Xml.Linq;
88
using NHibernate.Bytecode;
9+
using NHibernate.Cfg;
910
using NHibernate.Classic;
1011
using NHibernate.SqlTypes;
1112
using NHibernate.UserTypes;
@@ -313,6 +314,25 @@ private static void RegisterBuiltInTypes()
313314
len => new SerializableType(typeof (object), SqlTypeFactory.GetBinary(len))));
314315
}
315316

317+
/// <summary>
318+
/// <para>Defines which NHibernate type should be chosen by default for handling a given .Net type.</para>
319+
/// <para>This must be done before any operation on NHibernate, including building its
320+
/// <see cref="Configuration" /> and building session factory. Otherwise the behavior will be undefined.</para>
321+
/// </summary>
322+
/// <param name="targetType">The NHibernate type.</param>
323+
/// <typeparam name="T">The .Net type.</typeparam>
324+
public static void SetDefaultType<T>(IType targetType)
325+
{
326+
if (targetType == null)
327+
throw new ArgumentNullException(nameof(targetType));
328+
329+
var type = typeof(T);
330+
foreach (var alias in GetClrTypeAliases(type))
331+
{
332+
typeByTypeOfName[alias] = targetType;
333+
}
334+
}
335+
316336
private static ICollectionTypeFactory CollectionTypeFactory =>
317337
Environment.BytecodeProvider.CollectionTypeFactory;
318338

0 commit comments

Comments
 (0)