Skip to content

Commit 1d762b2

Browse files
Aggregate named queries validation exceptions.
They were only logged, which is unpractical for applications not having NHibernate logs enabled, and is also unpractical when debugging.
1 parent f0644cf commit 1d762b2

File tree

4 files changed

+167
-1
lines changed

4 files changed

+167
-1
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections;
3+
using NHibernate.Cfg;
4+
using NHibernate.Exceptions;
5+
using NUnit.Framework;
6+
7+
namespace NHibernate.Test.QueryTest
8+
{
9+
[TestFixture]
10+
public class BadNamedQueriesFixture : TestCase
11+
{
12+
protected override IList Mappings => new[] { "QueryTest.BadNamedQueriesFixture.hbm.xml" };
13+
14+
protected override string MappingsAssembly => "NHibernate.Test";
15+
16+
protected override void Configure(Configuration configuration)
17+
{
18+
// Allow building of default session factory
19+
configuration.SetProperty(Cfg.Environment.QueryStartupChecking, "false");
20+
}
21+
22+
protected override void OnSetUp()
23+
{
24+
cfg.SetProperty(Cfg.Environment.QueryStartupChecking, "true");
25+
}
26+
27+
protected override void OnTearDown()
28+
{
29+
cfg.SetProperty(Cfg.Environment.QueryStartupChecking, "false");
30+
}
31+
32+
[Test]
33+
public void StartupCheck()
34+
{
35+
Assert.That(
36+
BuildSessionFactory,
37+
Throws
38+
.InstanceOf<AggregateHibernateException>()
39+
.And.Property(nameof(AggregateHibernateException.InnerExceptions)).Count.EqualTo(2));
40+
}
41+
}
42+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2"
3+
namespace="NHibernate.Test.QueryTest"
4+
assembly="NHibernate.Test">
5+
<query name="Bad1">
6+
from NonExistent
7+
</query>
8+
<query name="Bad2">
9+
blah
10+
</query>
11+
</hibernate-mapping>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
4+
using System.Linq;
5+
using System.Runtime.Serialization;
6+
using System.Security;
7+
using System.Text;
8+
9+
namespace NHibernate.Exceptions
10+
{
11+
/// <summary>
12+
/// Exception aggregating exceptions that occurs in the O-R persistence layer.
13+
/// </summary>
14+
[Serializable]
15+
public class AggregateHibernateException : HibernateException
16+
{
17+
public ReadOnlyCollection<Exception> InnerExceptions { get; }
18+
19+
/// <summary>
20+
/// Initializes a new instance of the <see cref="AggregateHibernateException"/> class.
21+
/// </summary>
22+
/// <param name="innerExceptions">The exceptions to aggregate.</param>
23+
public AggregateHibernateException(IEnumerable<Exception> innerExceptions) :
24+
this(
25+
$"Exceptions occurred in the persistence layer, check {nameof(InnerExceptions)} property.",
26+
innerExceptions)
27+
{
28+
}
29+
30+
/// <summary>
31+
/// Initializes a new instance of the <see cref="AggregateHibernateException"/> class.
32+
/// </summary>
33+
/// <param name="innerExceptions">The exceptions to aggregate.</param>
34+
public AggregateHibernateException(params Exception[] innerExceptions) :
35+
this(innerExceptions?.ToList())
36+
{
37+
}
38+
39+
/// <summary>
40+
/// Initializes a new instance of the <see cref="HibernateException"/> class.
41+
/// </summary>
42+
/// <param name="message">The message that describes the error.</param>
43+
/// <param name="innerExceptions">The exceptions to aggregate.</param>
44+
public AggregateHibernateException(string message, IEnumerable<Exception> innerExceptions) :
45+
this(message, innerExceptions?.ToList())
46+
{
47+
}
48+
49+
/// <summary>
50+
/// Initializes a new instance of the <see cref="HibernateException"/> class.
51+
/// </summary>
52+
/// <param name="message">The message that describes the error.</param>
53+
/// <param name="innerExceptions">The exceptions to aggregate.</param>
54+
public AggregateHibernateException(string message, params Exception[] innerExceptions) :
55+
this(message, innerExceptions?.ToList())
56+
{
57+
}
58+
59+
private AggregateHibernateException(string message, IList<Exception> innerExceptions) :
60+
base(
61+
message,
62+
innerExceptions?.FirstOrDefault())
63+
{
64+
if (innerExceptions == null)
65+
throw new ArgumentNullException(nameof(innerExceptions));
66+
if (innerExceptions.Count == 0)
67+
throw new ArgumentException("Exceptions list to aggregate is empty", nameof(innerExceptions));
68+
if (innerExceptions.Any(e => e == null))
69+
throw new ArgumentException("Exceptions list to aggregate contains a null exception", nameof(innerExceptions));
70+
InnerExceptions = new ReadOnlyCollection<Exception>(innerExceptions);
71+
}
72+
73+
/// <summary>
74+
/// Initializes a new instance of the <see cref="AggregateHibernateException"/> class
75+
/// with serialized data.
76+
/// </summary>
77+
/// <param name="info">
78+
/// The <see cref="SerializationInfo"/> that holds the serialized object
79+
/// data about the exception being thrown.
80+
/// </param>
81+
/// <param name="context">
82+
/// The <see cref="StreamingContext"/> that contains contextual information about the source or destination.
83+
/// </param>
84+
protected AggregateHibernateException(SerializationInfo info, StreamingContext context) : base(info, context)
85+
{
86+
InnerExceptions = (ReadOnlyCollection<Exception>) info.GetValue("InnerExceptions", typeof(ReadOnlyCollection<Exception>));
87+
}
88+
89+
[SecurityCritical]
90+
public override void GetObjectData(SerializationInfo info, StreamingContext context)
91+
{
92+
base.GetObjectData(info, context);
93+
info.AddValue("InnerExceptions", InnerExceptions);
94+
}
95+
96+
/// <summary>
97+
/// Return a string representation of the aggregate exception.
98+
/// </summary>
99+
/// <returns>A string representation with inner exceptions.</returns>
100+
public override string ToString()
101+
{
102+
var str = new StringBuilder(base.ToString());
103+
for (var i = 0; i < InnerExceptions.Count; i++)
104+
{
105+
str
106+
.AppendLine()
107+
.Append("---> (Inner exception #").Append(i).Append(") ")
108+
.Append(InnerExceptions[i]).AppendLine("<---");
109+
}
110+
return str.ToString();
111+
}
112+
}
113+
}

src/NHibernate/Impl/SessionFactoryImpl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,7 @@ public SessionFactoryImpl(Configuration cfg, IMapping mapping, Settings settings
402402
failingQueries.Append('{').Append(pair.Key).Append('}');
403403
log.Error(pair.Value, "Error in named query: {0}", pair.Key);
404404
}
405-
throw new HibernateException(failingQueries.ToString());
405+
throw new AggregateHibernateException(failingQueries.ToString(), errors.Values);
406406
}
407407
}
408408
#endregion

0 commit comments

Comments
 (0)