diff --git a/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs b/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs index 0791d693640..16fe62d29be 100644 --- a/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs +++ b/src/NHibernate.Test/Async/Linq/PreEvaluationTests.cs @@ -43,195 +43,76 @@ protected override void Configure(Configuration configuration) configuration.SetProperty(Environment.LinqToHqlFallbackOnPreEvaluation, FallbackOnPreEvaluation.ToString()); } - [Test] - public async Task CanQueryByRandomDoubleAsync() - { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = await (db.Orders.CountAsync(o => o.OrderId > random.NextDouble())); - - Assert.That(x, Is.GreaterThan(0)); - AssertFunctionInSql("random", spy); - } - } - - [Test] - public async Task CanSelectRandomDoubleAsync() - { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = - await (db - .Orders.Select(o => new { id = o.OrderId, r = random.NextDouble() }) - .OrderBy(o => o.id).ToListAsync()); - - Assert.That(x, Has.Count.GreaterThan(0)); - var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(1)); - - if (!LegacyPreEvaluation && IsFunctionSupported("random")) - { - // Naïve randomness check - Assert.That( - randomValues, - Has.Length.GreaterThan(x.Count / 2), - "Generated values do not seem very random"); - } - - AssertFunctionInSql("random", spy); - } - } - [Test] public async Task CanQueryByRandomIntAsync() { + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); var idMin = await (db.Orders.MinAsync(o => o.OrderId)); - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - // Dodge a Firebird driver limitation by putting the constants before the order id. - // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not - // knowing the type of the condition. For some reasons the driver considers the casting should not be - // done next to the conditional operator. Having the cast only on one side is enough for avoiding - // Firebird complain, so moving the constants on the left side have been put before the order id, in - // order for these constants to be casted by the driver. - var x = await (db.Orders.CountAsync(o => -idMin - 1 + o.OrderId < random.Next())); - - Assert.That(x, Is.GreaterThan(0)); - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } - } - - [Test] - public async Task CanSelectRandomIntAsync() - { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = - await (db - .Orders.Select(o => new { id = o.OrderId, r = random.Next() }) - .OrderBy(o => o.id).ToListAsync()); - - Assert.That(x, Has.Count.GreaterThan(0)); - var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(int.MaxValue).And.TypeOf()); - - if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + RunTest( + isSupported, + spy => { - // Naïve randomness check - Assert.That( - randomValues, - Has.Length.GreaterThan(x.Count / 2), - "Generated values do not seem very random"); - } - - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + var random = new Random(); + // Dodge a Firebird driver limitation by putting the constants before the order id. + // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not + // knowing the type of the condition. For some reasons the driver considers the casting should not be + // done next to the conditional operator. Having the cast only on one side is enough for avoiding + // Firebird complain, so moving the constants on the left side have been put before the order id, in + // order for these constants to be casted by the driver. + var x = db.Orders.Count(o => -idMin - 1 + o.OrderId < random.Next()); + + Assert.That(x, Is.GreaterThan(0)); + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } [Test] public async Task CanQueryByRandomIntWithMaxAsync() { + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); var idMin = await (db.Orders.MinAsync(o => o.OrderId)); - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - // Dodge a Firebird driver limitation by putting the constants before the order id. - // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not - // knowing the type of the condition. For some reasons the driver considers the casting should not be - // done next to the conditional operator. Having the cast only on one side is enough for avoiding - // Firebird complain, so moving the constants on the left side have been put before the order id, in - // order for these constants to be casted by the driver. - var x = await (db.Orders.CountAsync(o => -idMin + o.OrderId <= random.Next(10))); - - Assert.That(x, Is.GreaterThan(0).And.LessThan(11)); - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } - } - - [Test] - public async Task CanSelectRandomIntWithMaxAsync() - { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = - await (db - .Orders.Select(o => new { id = o.OrderId, r = random.Next(10) }) - .OrderBy(o => o.id).ToListAsync()); - - Assert.That(x, Has.Count.GreaterThan(0)); - var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(10).And.TypeOf()); - - if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + RunTest( + isSupported, + spy => { - // Naïve randomness check - Assert.That( - randomValues, - Has.Length.GreaterThan(Math.Min(10, x.Count) / 2), - "Generated values do not seem very random"); - } - - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + var random = new Random(); + // Dodge a Firebird driver limitation by putting the constants before the order id. + // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not + // knowing the type of the condition. For some reasons the driver considers the casting should not be + // done next to the conditional operator. Having the cast only on one side is enough for avoiding + // Firebird complain, so moving the constants on the left side have been put before the order id, in + // order for these constants to be casted by the driver. + var x = db.Orders.Count(o => -idMin + o.OrderId <= random.Next(10)); + + Assert.That(x, Is.GreaterThan(0).And.LessThan(11)); + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } [Test] public async Task CanQueryByRandomIntWithMinMaxAsync() { + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); var idMin = await (db.Orders.MinAsync(o => o.OrderId)); - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - // Dodge a Firebird driver limitation by putting the constants before the order id. - // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not - // knowing the type of the condition. For some reasons the driver considers the casting should not be - // done next to the conditional operator. Having the cast only on one side is enough for avoiding - // Firebird complain, so moving the constants on the left side have been put before the order id, in - // order for these constants to be casted by the driver. - var x = await (db.Orders.CountAsync(o => -idMin + o.OrderId < random.Next(1, 10))); - - Assert.That(x, Is.GreaterThan(0).And.LessThan(10)); - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } - } - - [Test] - public async Task CanSelectRandomIntWithMinMaxAsync() - { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = - await (db - .Orders.Select(o => new { id = o.OrderId, r = random.Next(1, 11) }) - .OrderBy(o => o.id).ToListAsync()); - - Assert.That(x, Has.Count.GreaterThan(0)); - var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(1).And.LessThan(11).And.TypeOf()); - - if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + RunTest( + isSupported, + spy => { - // Naïve randomness check - Assert.That( - randomValues, - Has.Length.GreaterThan(Math.Min(10, x.Count) / 2), - "Generated values do not seem very random"); - } - - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + var random = new Random(); + // Dodge a Firebird driver limitation by putting the constants before the order id. + // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not + // knowing the type of the condition. For some reasons the driver considers the casting should not be + // done next to the conditional operator. Having the cast only on one side is enough for avoiding + // Firebird complain, so moving the constants on the left side have been put before the order id, in + // order for these constants to be casted by the driver. + var x = db.Orders.Count(o => -idMin + o.OrderId < random.Next(1, 10)); + + Assert.That(x, Is.GreaterThan(0).And.LessThan(10)); + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } private void RunTest(bool isSupported, Action test) diff --git a/src/NHibernate.Test/Linq/PreEvaluationTests.cs b/src/NHibernate.Test/Linq/PreEvaluationTests.cs index 640346345dd..232bc109a21 100644 --- a/src/NHibernate.Test/Linq/PreEvaluationTests.cs +++ b/src/NHibernate.Test/Linq/PreEvaluationTests.cs @@ -253,192 +253,218 @@ public void CanSelectNewGuid() [Test] public void CanQueryByRandomDouble() { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = db.Orders.Count(o => o.OrderId > random.NextDouble()); + var isSupported = IsFunctionSupported("random"); + RunTest( + isSupported, + spy => + { + var random = new Random(); + var x = db.Orders.Count(o => o.OrderId > random.NextDouble()); - Assert.That(x, Is.GreaterThan(0)); - AssertFunctionInSql("random", spy); - } + Assert.That(x, Is.GreaterThan(0)); + AssertFunctionInSql("random", spy); + }); } [Test] public void CanSelectRandomDouble() { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = - db - .Orders.Select(o => new { id = o.OrderId, r = random.NextDouble() }) - .OrderBy(o => o.id).ToList(); - - Assert.That(x, Has.Count.GreaterThan(0)); - var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(1)); - - if (!LegacyPreEvaluation && IsFunctionSupported("random")) + var isSupported = IsFunctionSupported("random"); + RunTest( + isSupported, + spy => { - // Naïve randomness check - Assert.That( - randomValues, - Has.Length.GreaterThan(x.Count / 2), - "Generated values do not seem very random"); - } + var random = new Random(); + var x = + db + .Orders.Select(o => new { id = o.OrderId, r = random.NextDouble() }) + .OrderBy(o => o.id).ToList(); - AssertFunctionInSql("random", spy); - } + Assert.That(x, Has.Count.GreaterThan(0)); + var randomValues = x.Select(o => o.r).Distinct().ToArray(); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(1)); + + if (!LegacyPreEvaluation && IsFunctionSupported("random")) + { + // Naïve randomness check + Assert.That( + randomValues, + Has.Length.GreaterThan(x.Count / 2), + "Generated values do not seem very random"); + } + + AssertFunctionInSql("random", spy); + }); } [Test] public void CanQueryByRandomInt() { + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); var idMin = db.Orders.Min(o => o.OrderId); - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - // Dodge a Firebird driver limitation by putting the constants before the order id. - // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not - // knowing the type of the condition. For some reasons the driver considers the casting should not be - // done next to the conditional operator. Having the cast only on one side is enough for avoiding - // Firebird complain, so moving the constants on the left side have been put before the order id, in - // order for these constants to be casted by the driver. - var x = db.Orders.Count(o => -idMin - 1 + o.OrderId < random.Next()); - - Assert.That(x, Is.GreaterThan(0)); - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + RunTest( + isSupported, + spy => + { + var random = new Random(); + // Dodge a Firebird driver limitation by putting the constants before the order id. + // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not + // knowing the type of the condition. For some reasons the driver considers the casting should not be + // done next to the conditional operator. Having the cast only on one side is enough for avoiding + // Firebird complain, so moving the constants on the left side have been put before the order id, in + // order for these constants to be casted by the driver. + var x = db.Orders.Count(o => -idMin - 1 + o.OrderId < random.Next()); + + Assert.That(x, Is.GreaterThan(0)); + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } [Test] public void CanSelectRandomInt() { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = - db - .Orders.Select(o => new { id = o.OrderId, r = random.Next() }) - .OrderBy(o => o.id).ToList(); - - Assert.That(x, Has.Count.GreaterThan(0)); - var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(int.MaxValue).And.TypeOf()); - - if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); + RunTest( + isSupported, + spy => { - // Naïve randomness check + var random = new Random(); + var x = + db + .Orders.Select(o => new { id = o.OrderId, r = random.Next() }) + .OrderBy(o => o.id).ToList(); + + Assert.That(x, Has.Count.GreaterThan(0)); + var randomValues = x.Select(o => o.r).Distinct().ToArray(); Assert.That( randomValues, - Has.Length.GreaterThan(x.Count / 2), - "Generated values do not seem very random"); - } - - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + Has.All.GreaterThanOrEqualTo(0).And.LessThan(int.MaxValue).And.TypeOf()); + + if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + { + // Naïve randomness check + Assert.That( + randomValues, + Has.Length.GreaterThan(x.Count / 2), + "Generated values do not seem very random"); + } + + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } [Test] public void CanQueryByRandomIntWithMax() { + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); var idMin = db.Orders.Min(o => o.OrderId); - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - // Dodge a Firebird driver limitation by putting the constants before the order id. - // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not - // knowing the type of the condition. For some reasons the driver considers the casting should not be - // done next to the conditional operator. Having the cast only on one side is enough for avoiding - // Firebird complain, so moving the constants on the left side have been put before the order id, in - // order for these constants to be casted by the driver. - var x = db.Orders.Count(o => -idMin + o.OrderId <= random.Next(10)); - - Assert.That(x, Is.GreaterThan(0).And.LessThan(11)); - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + RunTest( + isSupported, + spy => + { + var random = new Random(); + // Dodge a Firebird driver limitation by putting the constants before the order id. + // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not + // knowing the type of the condition. For some reasons the driver considers the casting should not be + // done next to the conditional operator. Having the cast only on one side is enough for avoiding + // Firebird complain, so moving the constants on the left side have been put before the order id, in + // order for these constants to be casted by the driver. + var x = db.Orders.Count(o => -idMin + o.OrderId <= random.Next(10)); + + Assert.That(x, Is.GreaterThan(0).And.LessThan(11)); + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } [Test] public void CanSelectRandomIntWithMax() { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = - db - .Orders.Select(o => new { id = o.OrderId, r = random.Next(10) }) - .OrderBy(o => o.id).ToList(); - - Assert.That(x, Has.Count.GreaterThan(0)); - var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(10).And.TypeOf()); - - if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); + RunTest( + isSupported, + spy => { - // Naïve randomness check - Assert.That( - randomValues, - Has.Length.GreaterThan(Math.Min(10, x.Count) / 2), - "Generated values do not seem very random"); - } + var random = new Random(); + var x = + db + .Orders.Select(o => new { id = o.OrderId, r = random.Next(10) }) + .OrderBy(o => o.id).ToList(); - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + Assert.That(x, Has.Count.GreaterThan(0)); + var randomValues = x.Select(o => o.r).Distinct().ToArray(); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(0).And.LessThan(10).And.TypeOf()); + + if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + { + // Naïve randomness check + Assert.That( + randomValues, + Has.Length.GreaterThan(Math.Min(10, x.Count) / 2), + "Generated values do not seem very random"); + } + + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } [Test] public void CanQueryByRandomIntWithMinMax() { + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); var idMin = db.Orders.Min(o => o.OrderId); - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - // Dodge a Firebird driver limitation by putting the constants before the order id. - // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not - // knowing the type of the condition. For some reasons the driver considers the casting should not be - // done next to the conditional operator. Having the cast only on one side is enough for avoiding - // Firebird complain, so moving the constants on the left side have been put before the order id, in - // order for these constants to be casted by the driver. - var x = db.Orders.Count(o => -idMin + o.OrderId < random.Next(1, 10)); - - Assert.That(x, Is.GreaterThan(0).And.LessThan(10)); - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + RunTest( + isSupported, + spy => + { + var random = new Random(); + // Dodge a Firebird driver limitation by putting the constants before the order id. + // This driver cast parameters to their types in some cases for avoiding Firebird complaining of not + // knowing the type of the condition. For some reasons the driver considers the casting should not be + // done next to the conditional operator. Having the cast only on one side is enough for avoiding + // Firebird complain, so moving the constants on the left side have been put before the order id, in + // order for these constants to be casted by the driver. + var x = db.Orders.Count(o => -idMin + o.OrderId < random.Next(1, 10)); + + Assert.That(x, Is.GreaterThan(0).And.LessThan(10)); + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } [Test] public void CanSelectRandomIntWithMinMax() { - using (var spy = new SqlLogSpy()) - { - var random = new Random(); - var x = - db - .Orders.Select(o => new { id = o.OrderId, r = random.Next(1, 11) }) - .OrderBy(o => o.id).ToList(); - - Assert.That(x, Has.Count.GreaterThan(0)); - var randomValues = x.Select(o => o.r).Distinct().ToArray(); - Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(1).And.LessThan(11).And.TypeOf()); - - if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + var isSupported = IsFunctionSupported("random") && IsFunctionSupported("floor"); + RunTest( + isSupported, + spy => { - // Naïve randomness check - Assert.That( - randomValues, - Has.Length.GreaterThan(Math.Min(10, x.Count) / 2), - "Generated values do not seem very random"); - } + var random = new Random(); + var x = + db + .Orders.Select(o => new { id = o.OrderId, r = random.Next(1, 11) }) + .OrderBy(o => o.id).ToList(); - // Next requires support of both floor and rand - AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); - } + Assert.That(x, Has.Count.GreaterThan(0)); + var randomValues = x.Select(o => o.r).Distinct().ToArray(); + Assert.That(randomValues, Has.All.GreaterThanOrEqualTo(1).And.LessThan(11).And.TypeOf()); + + if (!LegacyPreEvaluation && IsFunctionSupported("random") && IsFunctionSupported("floor")) + { + // Naïve randomness check + Assert.That( + randomValues, + Has.Length.GreaterThan(Math.Min(10, x.Count) / 2), + "Generated values do not seem very random"); + } + + // Next requires support of both floor and rand + AssertFunctionInSql(IsFunctionSupported("floor") ? "random" : "floor", spy); + }); } private void RunTest(bool isSupported, Action test) diff --git a/src/NHibernate/Linq/Functions/RandomHqlGenerator.cs b/src/NHibernate/Linq/Functions/RandomHqlGenerator.cs index 14d03c14cdf..bde4895e1e5 100644 --- a/src/NHibernate/Linq/Functions/RandomHqlGenerator.cs +++ b/src/NHibernate/Linq/Functions/RandomHqlGenerator.cs @@ -6,6 +6,7 @@ using NHibernate.Hql.Ast; using NHibernate.Linq.Visitors; using NHibernate.Util; +using Environment = NHibernate.Cfg.Environment; namespace NHibernate.Linq.Functions { @@ -74,9 +75,21 @@ public override HqlTreeNode BuildHql( /// public bool AllowPreEvaluation(MemberInfo member, ISessionFactoryImplementor factory) { - // When not supported, allow pre-evaluation on client side as a fallback. - return !factory.Dialect.Functions.ContainsKey(_randomFunctionName) || - member != _nextDouble && !factory.Dialect.Functions.ContainsKey(_floorFunctionName); + if (factory.Dialect.Functions.ContainsKey(_randomFunctionName) && + (member == _nextDouble || factory.Dialect.Functions.ContainsKey(_floorFunctionName))) + return false; + + if (factory.Settings.LinqToHqlFallbackOnPreEvaluation) + return true; + + var functionName = factory.Dialect.Functions.ContainsKey(_randomFunctionName) + ? _floorFunctionName + : _randomFunctionName; + throw new QueryException( + $"Cannot translate {member.DeclaringType.Name}.{member.Name}: {functionName} is " + + $"not supported by {factory.Dialect}. Either enable the fallback on pre-evaluation " + + $"({Environment.LinqToHqlFallbackOnPreEvaluation}) or evaluate {member.Name} " + + "outside of the query."); } ///