diff --git a/src/NHibernate.Test/Async/Linq/FunctionTests.cs b/src/NHibernate.Test/Async/Linq/FunctionTests.cs index f65b9dc9854..e47e3d22c37 100644 --- a/src/NHibernate.Test/Async/Linq/FunctionTests.cs +++ b/src/NHibernate.Test/Async/Linq/FunctionTests.cs @@ -367,16 +367,6 @@ where item.Id.Equals(-1) await (ObjectDumper.WriteAsync(query)); } - [Test] - public async Task WhereShortEqualAsync() - { - var query = from item in session.Query() - where item.Short.Equals(-1) - select item; - - await (ObjectDumper.WriteAsync(query)); - } - [Test] public async Task WhereBoolConstantEqualAsync() { @@ -458,36 +448,6 @@ where item.BodyWeight.Equals(-1) await (ObjectDumper.WriteAsync(query)); } - - [Test] - public async Task WhereFloatEqualAsync() - { - var query = from item in session.Query() - where item.Float.Equals(-1) - select item; - - await (ObjectDumper.WriteAsync(query)); - } - - [Test] - public async Task WhereCharEqualAsync() - { - var query = from item in session.Query() - where item.Char.Equals('A') - select item; - - await (ObjectDumper.WriteAsync(query)); - } - - [Test] - public async Task WhereByteEqualAsync() - { - var query = from item in session.Query() - where item.Byte.Equals(1) - select item; - - await (ObjectDumper.WriteAsync(query)); - } [Test] public async Task WhereDecimalEqualAsync() diff --git a/src/NHibernate.Test/Async/Linq/LinqQuerySamples.cs b/src/NHibernate.Test/Async/Linq/LinqQuerySamples.cs index 9b8d04f2c6c..24091d1fc3d 100644 --- a/src/NHibernate.Test/Async/Linq/LinqQuerySamples.cs +++ b/src/NHibernate.Test/Async/Linq/LinqQuerySamples.cs @@ -13,9 +13,10 @@ using System.Collections.Generic; using System.Linq; using NHibernate.DomainModel.Northwind.Entities; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Linq; using NSubstitute; using NUnit.Framework; -using NHibernate.Linq; namespace NHibernate.Test.Linq { @@ -23,6 +24,43 @@ namespace NHibernate.Test.Linq [TestFixture] public class LinqQuerySamplesAsync : LinqTestCase { + class NotMappedEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Test] + public void ShouldThrowForQueryOnNotMappedEntityAsync() + { + var querySyntaxException = Assert.ThrowsAsync(() => session.Query().Select(x => x.Id).ToListAsync()); + Assert.That(querySyntaxException.Message, Does.Contain(nameof(NotMappedEntity))); + } + + [Test] + public void ShouldThrowForQueryOnNotMappedEntityNameAsync() + { + var entityName = "SomeNamespace.NotMappedEntityName"; + var querySyntaxException = Assert.ThrowsAsync(() => session.Query(entityName).ToListAsync()); + Assert.That(querySyntaxException.Message, Does.Contain(entityName)); + } + + [Test] + public void ShouldThrowForDmlQueryOnNotMappedEntityAsync() + { + Assert.Multiple( + () => + { + var querySyntaxException = Assert.ThrowsAsync(() => session.Query().DeleteAsync()); + Assert.That(querySyntaxException.Message, Does.Contain(nameof(NotMappedEntity))); + + var entityName = "SomeNamespace.NotMappedEntityName"; + querySyntaxException = Assert.ThrowsAsync(() => session.DeleteAsync($"from {entityName}")); + Assert.That(querySyntaxException.Message, Does.Contain(entityName)); + return Task.CompletedTask; + }); + } + [Test] public async Task GroupTwoQueriesAndSumAsync() { diff --git a/src/NHibernate.Test/Linq/FunctionTests.cs b/src/NHibernate.Test/Linq/FunctionTests.cs index 127429d11b8..b92e7b3ece9 100644 --- a/src/NHibernate.Test/Linq/FunctionTests.cs +++ b/src/NHibernate.Test/Linq/FunctionTests.cs @@ -356,6 +356,7 @@ where item.Id.Equals(-1) } [Test] + [Ignore("Not mapped entity")] public void WhereShortEqual() { var query = from item in session.Query() @@ -448,6 +449,7 @@ where item.BodyWeight.Equals(-1) } [Test] + [Ignore("Not mapped entity")] public void WhereFloatEqual() { var query = from item in session.Query() @@ -458,6 +460,7 @@ where item.Float.Equals(-1) } [Test] + [Ignore("Not mapped entity")] public void WhereCharEqual() { var query = from item in session.Query() @@ -468,6 +471,7 @@ where item.Char.Equals('A') } [Test] + [Ignore("Not mapped entity")] public void WhereByteEqual() { var query = from item in session.Query() diff --git a/src/NHibernate.Test/Linq/LinqQuerySamples.cs b/src/NHibernate.Test/Linq/LinqQuerySamples.cs index 393d55ccf0a..f29fa18dd92 100755 --- a/src/NHibernate.Test/Linq/LinqQuerySamples.cs +++ b/src/NHibernate.Test/Linq/LinqQuerySamples.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Linq; using NHibernate.DomainModel.Northwind.Entities; +using NHibernate.Hql.Ast.ANTLR; +using NHibernate.Linq; using NSubstitute; using NUnit.Framework; @@ -11,6 +13,42 @@ namespace NHibernate.Test.Linq [TestFixture] public class LinqQuerySamples : LinqTestCase { + class NotMappedEntity + { + public virtual int Id { get; set; } + public virtual string Name { get; set; } + } + + [Test] + public void ShouldThrowForQueryOnNotMappedEntity() + { + var querySyntaxException = Assert.Throws(() => session.Query().Select(x => x.Id).ToList()); + Assert.That(querySyntaxException.Message, Does.Contain(nameof(NotMappedEntity))); + } + + [Test] + public void ShouldThrowForQueryOnNotMappedEntityName() + { + var entityName = "SomeNamespace.NotMappedEntityName"; + var querySyntaxException = Assert.Throws(() => session.Query(entityName).ToList()); + Assert.That(querySyntaxException.Message, Does.Contain(entityName)); + } + + [Test] + public void ShouldThrowForDmlQueryOnNotMappedEntity() + { + Assert.Multiple( + () => + { + var querySyntaxException = Assert.Throws(() => session.Query().Delete()); + Assert.That(querySyntaxException.Message, Does.Contain(nameof(NotMappedEntity))); + + var entityName = "SomeNamespace.NotMappedEntityName"; + querySyntaxException = Assert.Throws(() => session.Delete($"from {entityName}")); + Assert.That(querySyntaxException.Message, Does.Contain(entityName)); + }); + } + [Test] public void GroupTwoQueriesAndSum() { diff --git a/src/NHibernate.Test/TestCase.cs b/src/NHibernate.Test/TestCase.cs index f1d04a96640..e3f4124bd0a 100644 --- a/src/NHibernate.Test/TestCase.cs +++ b/src/NHibernate.Test/TestCase.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Data; using System.Data.Common; +using System.Linq; using System.Reflection; using log4net; using NHibernate.Cfg; @@ -230,13 +231,20 @@ private string GetCombinedFailureMessage(TestContext.ResultAdapter result, strin protected virtual bool CheckDatabaseWasCleaned() { - if (Sfi.GetAllClassMetadata().Count == 0) + var allClassMetadata = Sfi.GetAllClassMetadata(); + if (allClassMetadata.Count == 0) { // Return early in the case of no mappings, also avoiding // a warning when executing the HQL below. return true; } + var explicitPolymorphismEntities = allClassMetadata.Values.Where(x => x is NHibernate.Persister.Entity.IQueryable queryable && queryable.IsExplicitPolymorphism).ToArray(); + + //TODO: Maybe add explicit load query checks + if (explicitPolymorphismEntities.Length == allClassMetadata.Count) + return true; + bool empty; using (ISession s = OpenSession()) { diff --git a/src/NHibernate/Hql/Ast/ANTLR/AstPolymorphicProcessor.cs b/src/NHibernate/Hql/Ast/ANTLR/AstPolymorphicProcessor.cs index 9b92315de48..259e6d203d4 100644 --- a/src/NHibernate/Hql/Ast/ANTLR/AstPolymorphicProcessor.cs +++ b/src/NHibernate/Hql/Ast/ANTLR/AstPolymorphicProcessor.cs @@ -1,7 +1,7 @@ using System.Collections.Generic; -using System.Linq; using NHibernate.Engine; using NHibernate.Hql.Ast.ANTLR.Tree; +using NHibernate.Util; namespace NHibernate.Hql.Ast.ANTLR { @@ -9,7 +9,7 @@ public class AstPolymorphicProcessor { private readonly IASTNode _ast; private readonly ISessionFactoryImplementor _factory; - private IEnumerable> _nodeMapping; + private Dictionary _nodeMapping; private AstPolymorphicProcessor(IASTNode ast, ISessionFactoryImplementor factory) { @@ -29,28 +29,27 @@ private IASTNode[] Process() // Find all the polymorphic query sources _nodeMapping = new PolymorphicQuerySourceDetector(_factory).Process(_ast); - if (_nodeMapping.Count() > 0) - { - return DuplicateTree().ToArray(); - } - else + if (_nodeMapping.Count == 0) + return new[] {_ast}; + + var parsers = DuplicateTree(); + + if (parsers.Length == 0) { - return new[] { _ast }; + var entityNames = _nodeMapping.Keys.ToArray(x => PolymorphicQuerySourceDetector.GetClassName(x)); + throw new QuerySyntaxException( + entityNames.Length == 1 + ? entityNames[0] + " is not mapped" + : string.Join(", ", entityNames) + " are not mapped"); } + + return parsers; } - private IEnumerable DuplicateTree() + private IASTNode[] DuplicateTree() { var replacements = CrossJoinDictionaryArrays.PerformCrossJoin(_nodeMapping); - - var dups = new IASTNode[replacements.Count()]; - - for (var i = 0; i < replacements.Count(); i++) - { - dups[i] = DuplicateTree(_ast, replacements[i]); - } - - return dups; + return replacements.ToArray(x => DuplicateTree(_ast, x)); } private static IASTNode DuplicateTree(IASTNode ast, IDictionary nodeMapping) @@ -72,4 +71,4 @@ private static IASTNode DuplicateTree(IASTNode ast, IDictionary MakeIdent(querySource, implementor))); } - private static string GetClassName(IASTNode querySource) + internal static string GetClassName(IASTNode querySource) { switch (querySource.Type) {