diff --git a/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs b/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs index 7e3112b3f94..6046c9c4859 100644 --- a/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs +++ b/src/NHibernate.Test/Async/Criteria/CriteriaQueryTest.cs @@ -13,6 +13,7 @@ using System.Collections.Generic; using NHibernate.Dialect; using NHibernate.Criterion; +using NHibernate.Linq; using NHibernate.SqlCommand; using NHibernate.Transform; using NHibernate.Type; @@ -873,7 +874,7 @@ public async Task ProjectionsTestAsync() ProjectionList p2 = Projections.ProjectionList() .Add(Projections.Min("StudentNumber")) .Add(Projections.Avg("StudentNumber")) - .Add(Projections.SqlProjection( + .Add(Projections.Sql( "1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 } @@ -922,6 +923,92 @@ public async Task ProjectionsTestAsync() s.Close(); } + [Test] + public async Task TestSQLProjectionWithAliasesAsync() + { + using(ISession s = OpenSession()) + using(ITransaction t = s.BeginTransaction()) + { + Course course = new Course(); + course.CourseCode = "HIB"; + course.Description = "Hibernate Training"; + await (s.SaveAsync(course)); + + Student gavin = new Student(); + gavin.Name = "Gavin King"; + gavin.StudentNumber = 667; + await (s.SaveAsync(gavin)); + + Student xam = new Student(); + xam.Name = "Max Rydahl Andersen"; + xam.StudentNumber = 101; + await (s.SaveAsync(xam)); + + Enrolment enrolment = new Enrolment(); + enrolment.Course = course; + enrolment.CourseCode = course.CourseCode; + enrolment.Semester = 1; + enrolment.Year = 1999; + enrolment.Student = xam; + enrolment.StudentNumber = xam.StudentNumber; + xam.Enrolments.Add(enrolment); + await (s.SaveAsync(enrolment)); + + enrolment = new Enrolment(); + enrolment.Course = course; + enrolment.CourseCode = course.CourseCode; + enrolment.Semester = 3; + enrolment.Year = 1998; + enrolment.Student = gavin; + enrolment.StudentNumber = gavin.StudentNumber; + gavin.Enrolments.Add(enrolment); + await (s.SaveAsync(enrolment)); + await (t.CommitAsync()); + } + + using (var s = OpenSession()) + { + Student studentSubquery = null; + var subquery = QueryOver.Of(() => studentSubquery) + .And( + Restrictions.Sql("{e}.studentId = 667 and {studentSubquery}.studentId = 667") + .AddAliases("e", "studentSubquery")).Select(Projections.Id()); + + var uniqueResult = await (s.CreateCriteria(typeof(Student)) + .Add(Subqueries.Exists(subquery.DetachedCriteria)) + .AddOrder(Order.Asc("Name")) + .CreateCriteria("Enrolments", "e") + .AddOrder(Order.Desc("Year")) + .AddOrder(Order.Desc("Semester")) + .CreateCriteria("Course", "c") + .AddOrder(Order.Asc("Description")) + .SetProjection( + Projections.Sql( + "{alias}.studentId as studentNumber, {e}.Semester as semester," + + " {c}.CourseCode as courseCode, {c}.Description as descr", + new string[] {"studentNumber", "semester", "courseCode", "descr"}, + new[] + { + TypeFactory.HeuristicType(typeof(long)), + TypeFactory.HeuristicType(typeof(short)), + TypeFactory.HeuristicType(typeof(string)), + TypeFactory.HeuristicType(typeof(string)), + }).AddAliases("e", "c")) + .UniqueResultAsync()); + + Assert.That(uniqueResult, Is.Not.Null); + } + + using (var s = OpenSession()) + using (s.BeginTransaction()) + { + await (s.Query().DeleteAsync()); + await (s.Query().DeleteAsync()); + await (s.Query().DeleteAsync()); + await (s.GetCurrentTransaction().CommitAsync()); + } + } + [Test] public async Task CloningProjectionsTestAsync() { @@ -1066,7 +1153,7 @@ public async Task CloningProjectionsTestAsync() ProjectionList p2 = Projections.ProjectionList() .Add(Projections.Min("StudentNumber")) .Add(Projections.Avg("StudentNumber")) - .Add(Projections.SqlProjection( + .Add(Projections.Sql( "1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 } @@ -1366,7 +1453,7 @@ public async Task ProjectionsUsingPropertyAsync() ProjectionList p2 = Projections.ProjectionList() .Add(Property.ForName("StudentNumber").Min()) .Add(Property.ForName("StudentNumber").Avg()) - .Add(Projections.SqlProjection( + .Add(Projections.Sql( "1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 } @@ -1859,7 +1946,7 @@ public async Task CloningProjectionsUsingPropertyAsync() ProjectionList p2 = Projections.ProjectionList() .Add(Property.ForName("StudentNumber").Min()) .Add(Property.ForName("StudentNumber").Avg()) - .Add(Projections.SqlProjection( + .Add(Projections.Sql( "1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 } @@ -2452,7 +2539,7 @@ public async Task SqlExpressionWithParametersAsync() { ICriteria c = session.CreateCriteria(typeof(Student)); c.Add(Expression.Eq("StudentNumber", (long)232)); - c.Add(Expression.Sql("2 = ?", 1, NHibernateUtil.Int32)); + c.Add(Restrictions.Sql("2 = ?", 1, NHibernateUtil.Int32)); Student gavin = new Student(); gavin.Name = "Gavin King"; diff --git a/src/NHibernate.Test/Async/Criteria/DetachedCriteriaSerializable.cs b/src/NHibernate.Test/Async/Criteria/DetachedCriteriaSerializable.cs index acaabbf375b..50891d4c925 100644 --- a/src/NHibernate.Test/Async/Criteria/DetachedCriteriaSerializable.cs +++ b/src/NHibernate.Test/Async/Criteria/DetachedCriteriaSerializable.cs @@ -150,19 +150,19 @@ public async Task ExecutableCriteriaAsync() // SQLCriterion dc = DetachedCriteria.For(typeof(Student)) - .Add(Expression.Sql("{alias}.Name = 'Gavin'")); + .Add(Restrictions.Sql("{alias}.Name = 'Gavin'")); await (SerializeAndListAsync(dc)); // SQLProjection dc = DetachedCriteria.For(typeof(Enrolment)) - .SetProjection(Projections.SqlProjection("1 as constOne, count(*) as countStar", + .SetProjection(Projections.Sql("1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 })); await (SerializeAndListAsync(dc)); dc = DetachedCriteria.For(typeof(Student)) .SetProjection( - Projections.SqlGroupProjection("COUNT({alias}.studentId), {alias}.preferredCourseCode", + Projections.Sql("COUNT({alias}.studentId), {alias}.preferredCourseCode", "{alias}.preferredCourseCode", new string[] { "studentsOfCourse", "CourseCode" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 })); diff --git a/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs b/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs index 86b59bbe491..c489bba3e16 100644 --- a/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs +++ b/src/NHibernate.Test/Async/ExpressionTest/Projection/ProjectionSqlFixture.cs @@ -112,7 +112,7 @@ public async Task SelectSqlProjectionTestAsync() ICriteria c = session.CreateCriteria(typeof(ProjectionTestClass)); c.SetProjection(Projections.ProjectionList() - .Add(Projections.SqlProjection("Avg({alias}.Pay) as MyPay", + .Add(Projections.Sql("Avg({alias}.Pay) as MyPay", new string[] { "MyPay" }, new IType[] { NHibernateUtil.Double }))); diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH1792/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH1792/Fixture.cs index 1d5b3022887..585c72dd502 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH1792/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH1792/Fixture.cs @@ -113,11 +113,11 @@ public async Task PageWithRawSqlSubqueryWithOrderByAsync() IList results = await (session.CreateCriteria().Add( - Expression.Sql("{alias}.Id in (Select " + top + " p.Id from Product p order by Name)")).Add(Restrictions.Gt("Id", 0)). + Restrictions.Sql("{alias}.Id in (Select " + top + " p.Id from Product p order by Name)")).Add(Restrictions.Gt("Id", 0)). SetMaxResults(3).ListAsync()); Assert.AreEqual(3, results.Count); } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs b/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs index 59a1d3d2cea..e365029c7b1 100644 --- a/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs +++ b/src/NHibernate.Test/Async/NHSpecificTest/NH2318/Fixture.cs @@ -68,7 +68,7 @@ public async Task CriteriaTrimFunctionsWithParametersAsync() "trim", NHibernateUtil.String, Projections.Constant("f"), - Projections.SqlProjection("from", null, null), // Silly hack to get "from" as a second argument. + Projections.Sql("from", null, null), // Silly hack to get "from" as a second argument. Projections.Property("Name")), "irst")); IList items = await (criteria.ListAsync()); diff --git a/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs b/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs index b173b8c6987..c4a59779405 100644 --- a/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs +++ b/src/NHibernate.Test/Criteria/CriteriaQueryTest.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using NHibernate.Dialect; using NHibernate.Criterion; +using NHibernate.Linq; using NHibernate.SqlCommand; using NHibernate.Transform; using NHibernate.Type; @@ -970,7 +971,7 @@ public void ProjectionsTest() ProjectionList p2 = Projections.ProjectionList() .Add(Projections.Min("StudentNumber")) .Add(Projections.Avg("StudentNumber")) - .Add(Projections.SqlProjection( + .Add(Projections.Sql( "1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 } @@ -1019,6 +1020,92 @@ public void ProjectionsTest() s.Close(); } + [Test] + public void TestSQLProjectionWithAliases() + { + using(ISession s = OpenSession()) + using(ITransaction t = s.BeginTransaction()) + { + Course course = new Course(); + course.CourseCode = "HIB"; + course.Description = "Hibernate Training"; + s.Save(course); + + Student gavin = new Student(); + gavin.Name = "Gavin King"; + gavin.StudentNumber = 667; + s.Save(gavin); + + Student xam = new Student(); + xam.Name = "Max Rydahl Andersen"; + xam.StudentNumber = 101; + s.Save(xam); + + Enrolment enrolment = new Enrolment(); + enrolment.Course = course; + enrolment.CourseCode = course.CourseCode; + enrolment.Semester = 1; + enrolment.Year = 1999; + enrolment.Student = xam; + enrolment.StudentNumber = xam.StudentNumber; + xam.Enrolments.Add(enrolment); + s.Save(enrolment); + + enrolment = new Enrolment(); + enrolment.Course = course; + enrolment.CourseCode = course.CourseCode; + enrolment.Semester = 3; + enrolment.Year = 1998; + enrolment.Student = gavin; + enrolment.StudentNumber = gavin.StudentNumber; + gavin.Enrolments.Add(enrolment); + s.Save(enrolment); + t.Commit(); + } + + using (var s = OpenSession()) + { + Student studentSubquery = null; + var subquery = QueryOver.Of(() => studentSubquery) + .And( + Restrictions.Sql("{e}.studentId = 667 and {studentSubquery}.studentId = 667") + .AddAliases("e", "studentSubquery")).Select(Projections.Id()); + + var uniqueResult = s.CreateCriteria(typeof(Student)) + .Add(Subqueries.Exists(subquery.DetachedCriteria)) + .AddOrder(Order.Asc("Name")) + .CreateCriteria("Enrolments", "e") + .AddOrder(Order.Desc("Year")) + .AddOrder(Order.Desc("Semester")) + .CreateCriteria("Course", "c") + .AddOrder(Order.Asc("Description")) + .SetProjection( + Projections.Sql( + "{alias}.studentId as studentNumber, {e}.Semester as semester," + + " {c}.CourseCode as courseCode, {c}.Description as descr", + new string[] {"studentNumber", "semester", "courseCode", "descr"}, + new[] + { + TypeFactory.HeuristicType(typeof(long)), + TypeFactory.HeuristicType(typeof(short)), + TypeFactory.HeuristicType(typeof(string)), + TypeFactory.HeuristicType(typeof(string)), + }).AddAliases("e", "c")) + .UniqueResult(); + + Assert.That(uniqueResult, Is.Not.Null); + } + + using (var s = OpenSession()) + using (s.BeginTransaction()) + { + s.Query().Delete(); + s.Query().Delete(); + s.Query().Delete(); + s.GetCurrentTransaction().Commit(); + } + } + [Test] public void CloningProjectionsTest() { @@ -1163,7 +1250,7 @@ public void CloningProjectionsTest() ProjectionList p2 = Projections.ProjectionList() .Add(Projections.Min("StudentNumber")) .Add(Projections.Avg("StudentNumber")) - .Add(Projections.SqlProjection( + .Add(Projections.Sql( "1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 } @@ -1463,7 +1550,7 @@ public void ProjectionsUsingProperty() ProjectionList p2 = Projections.ProjectionList() .Add(Property.ForName("StudentNumber").Min()) .Add(Property.ForName("StudentNumber").Avg()) - .Add(Projections.SqlProjection( + .Add(Projections.Sql( "1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 } @@ -1956,7 +2043,7 @@ public void CloningProjectionsUsingProperty() ProjectionList p2 = Projections.ProjectionList() .Add(Property.ForName("StudentNumber").Min()) .Add(Property.ForName("StudentNumber").Avg()) - .Add(Projections.SqlProjection( + .Add(Projections.Sql( "1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 } @@ -2575,7 +2662,7 @@ public void SqlExpressionWithParameters() { ICriteria c = session.CreateCriteria(typeof(Student)); c.Add(Expression.Eq("StudentNumber", (long)232)); - c.Add(Expression.Sql("2 = ?", 1, NHibernateUtil.Int32)); + c.Add(Restrictions.Sql("2 = ?", 1, NHibernateUtil.Int32)); Student gavin = new Student(); gavin.Name = "Gavin King"; diff --git a/src/NHibernate.Test/Criteria/DetachedCriteriaSerializable.cs b/src/NHibernate.Test/Criteria/DetachedCriteriaSerializable.cs index 2ecad73a656..c65fa04fc12 100644 --- a/src/NHibernate.Test/Criteria/DetachedCriteriaSerializable.cs +++ b/src/NHibernate.Test/Criteria/DetachedCriteriaSerializable.cs @@ -262,18 +262,18 @@ public void SubqueriesExpressions() [Test] public void SQLCriterion() { - ICriterion c = Expression.Sql("SELECT Name FROM Student"); + ICriterion c = Restrictions.Sql("SELECT Name FROM Student"); NHAssert.IsSerializable(c); } [Test] public void SQLProjection() { - IProjection p = Projections.SqlProjection("COUNT(*)", + IProjection p = Projections.Sql("COUNT(*)", new string[] { "tStudent" }, new IType[] { NHibernateUtil.Int32 }); NHAssert.IsSerializable(p); p = - Projections.SqlGroupProjection("COUNT({alias}.studentId), {alias}.preferredCourseCode", + Projections.Sql("COUNT({alias}.studentId), {alias}.preferredCourseCode", "{alias}.preferredCourseCode", new string[] { "studentsOfCourse", "CourseCode" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 }); @@ -404,19 +404,19 @@ public void ExecutableCriteria() // SQLCriterion dc = DetachedCriteria.For(typeof(Student)) - .Add(Expression.Sql("{alias}.Name = 'Gavin'")); + .Add(Restrictions.Sql("{alias}.Name = 'Gavin'")); SerializeAndList(dc); // SQLProjection dc = DetachedCriteria.For(typeof(Enrolment)) - .SetProjection(Projections.SqlProjection("1 as constOne, count(*) as countStar", + .SetProjection(Projections.Sql("1 as constOne, count(*) as countStar", new String[] { "constOne", "countStar" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 })); SerializeAndList(dc); dc = DetachedCriteria.For(typeof(Student)) .SetProjection( - Projections.SqlGroupProjection("COUNT({alias}.studentId), {alias}.preferredCourseCode", + Projections.Sql("COUNT({alias}.studentId), {alias}.preferredCourseCode", "{alias}.preferredCourseCode", new string[] { "studentsOfCourse", "CourseCode" }, new IType[] { NHibernateUtil.Int32, NHibernateUtil.Int32 })); diff --git a/src/NHibernate.Test/ExpressionTest/Projection/ProjectionFixture.cs b/src/NHibernate.Test/ExpressionTest/Projection/ProjectionFixture.cs index 55a65e9d140..5c955ec98e8 100644 --- a/src/NHibernate.Test/ExpressionTest/Projection/ProjectionFixture.cs +++ b/src/NHibernate.Test/ExpressionTest/Projection/ProjectionFixture.cs @@ -155,7 +155,7 @@ public void PropertyTest() public void SqlGroupProjectionTest() { ISession session = factory.OpenSession(); - IProjection expression = Projections.SqlGroupProjection("count(Pay)", "Pay", + IProjection expression = Projections.Sql("count(Pay)", "Pay", new string[] {"PayCount"}, new IType[] {NHibernateUtil.Double} ); @@ -170,7 +170,7 @@ public void SqlGroupProjectionTest() public void SqlProjectionTest() { ISession session = factory.OpenSession(); - IProjection expression = Projections.SqlProjection("count(Pay)", + IProjection expression = Projections.Sql("count(Pay)", new string[] {"CountOfPay"}, new IType[] {NHibernateUtil.Double}); CreateObjects(typeof(Simple), session); diff --git a/src/NHibernate.Test/ExpressionTest/Projection/ProjectionSqlFixture.cs b/src/NHibernate.Test/ExpressionTest/Projection/ProjectionSqlFixture.cs index 4867332b8c4..ea1682c9559 100644 --- a/src/NHibernate.Test/ExpressionTest/Projection/ProjectionSqlFixture.cs +++ b/src/NHibernate.Test/ExpressionTest/Projection/ProjectionSqlFixture.cs @@ -101,7 +101,7 @@ public void SelectSqlProjectionTest() ICriteria c = session.CreateCriteria(typeof(ProjectionTestClass)); c.SetProjection(Projections.ProjectionList() - .Add(Projections.SqlProjection("Avg({alias}.Pay) as MyPay", + .Add(Projections.Sql("Avg({alias}.Pay) as MyPay", new string[] { "MyPay" }, new IType[] { NHibernateUtil.Double }))); diff --git a/src/NHibernate.Test/ExpressionTest/SQLExpressionFixture.cs b/src/NHibernate.Test/ExpressionTest/SQLExpressionFixture.cs index 156703a1695..84e878c2ead 100644 --- a/src/NHibernate.Test/ExpressionTest/SQLExpressionFixture.cs +++ b/src/NHibernate.Test/ExpressionTest/SQLExpressionFixture.cs @@ -13,7 +13,7 @@ public void StraightSqlTest() { using (ISession session = factory.OpenSession()) { - ICriterion sqlExpression = Expression.Sql("{alias}.address is not null"); + ICriterion sqlExpression = Restrictions.Sql("{alias}.address is not null"); CreateObjects(typeof(Simple), session); SqlString sqlString = sqlExpression.ToSqlString(criteria, criteriaQuery); @@ -29,7 +29,7 @@ public void NoParamsSqlStringTest() { using (ISession session = factory.OpenSession()) { - ICriterion sqlExpression = Expression.Sql(new SqlString("{alias}.address is not null")); + ICriterion sqlExpression = Restrictions.Sql(new SqlString("{alias}.address is not null")); CreateObjects(typeof(Simple), session); SqlString sqlString = sqlExpression.ToSqlString(criteria, criteriaQuery); @@ -52,7 +52,7 @@ public void WithParameterTest() builder.Add("{alias}.address = "); builder.AddParameter(); - ICriterion sqlExpression = Expression.Sql(builder.ToSqlString(), "some address", NHibernateUtil.String); + ICriterion sqlExpression = Restrictions.Sql(builder.ToSqlString(), "some address", NHibernateUtil.String); CreateObjects(typeof(Simple), session); SqlString sqlString = sqlExpression.ToSqlString(criteria, criteriaQuery); @@ -61,4 +61,4 @@ public void WithParameterTest() } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH1792/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH1792/Fixture.cs index b8bb16b57d7..07ba434d6bb 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH1792/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH1792/Fixture.cs @@ -102,11 +102,11 @@ public void PageWithRawSqlSubqueryWithOrderBy() IList results = session.CreateCriteria().Add( - Expression.Sql("{alias}.Id in (Select " + top + " p.Id from Product p order by Name)")).Add(Restrictions.Gt("Id", 0)). + Restrictions.Sql("{alias}.Id in (Select " + top + " p.Id from Product p order by Name)")).Add(Restrictions.Gt("Id", 0)). SetMaxResults(3).List(); Assert.AreEqual(3, results.Count); } } } -} \ No newline at end of file +} diff --git a/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs b/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs index b5f15a3194a..4cdf86a9d0e 100644 --- a/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs +++ b/src/NHibernate.Test/NHSpecificTest/NH2318/Fixture.cs @@ -56,7 +56,7 @@ public void CriteriaTrimFunctionsWithParameters() "trim", NHibernateUtil.String, Projections.Constant("f"), - Projections.SqlProjection("from", null, null), // Silly hack to get "from" as a second argument. + Projections.Sql("from", null, null), // Silly hack to get "from" as a second argument. Projections.Property("Name")), "irst")); IList items = criteria.List(); diff --git a/src/NHibernate/Criterion/Expression.cs b/src/NHibernate/Criterion/Expression.cs index 2233f631313..69490c8478c 100644 --- a/src/NHibernate/Criterion/Expression.cs +++ b/src/NHibernate/Criterion/Expression.cs @@ -1,7 +1,6 @@ using System; using NHibernate.SqlCommand; using NHibernate.Type; -using NHibernate.Util; namespace NHibernate.Criterion { @@ -23,7 +22,9 @@ private Expression() /// /// /// - public static AbstractCriterion Sql(SqlString sql, object[] values, IType[] types) + //Since v5.3 + [Obsolete("Use Restrictions.Sql instead")] + public new static AbstractCriterion Sql(SqlString sql, object[] values, IType[] types) { return new SQLCriterion(sql, values, types); } @@ -35,7 +36,9 @@ public static AbstractCriterion Sql(SqlString sql, object[] values, IType[] type /// /// /// - public static AbstractCriterion Sql(SqlString sql, object value, IType type) + //Since v5.3 + [Obsolete("Use Restrictions.Sql instead")] + public new static AbstractCriterion Sql(SqlString sql, object value, IType type) { return Sql(sql, new object[] { value }, new IType[] { type }); } @@ -43,12 +46,16 @@ public static AbstractCriterion Sql(SqlString sql, object value, IType type) /// /// Apply a constraint expressed in SQL, with the given SQL parameter /// - public static AbstractCriterion Sql(string sql, object value, IType type) + //Since v5.3 + [Obsolete("Use Restrictions.Sql instead")] + public new static AbstractCriterion Sql(string sql, object value, IType type) { return Sql(sql, new object[] { value }, new IType[] { type }); } - public static AbstractCriterion Sql(string sql, object[] values, IType[] types) + //Since v5.3 + [Obsolete("Use Restrictions.Sql instead")] + public new static AbstractCriterion Sql(string sql, object[] values, IType[] types) { return new SQLCriterion(SqlString.Parse(sql), values, types); } @@ -58,7 +65,9 @@ public static AbstractCriterion Sql(string sql, object[] values, IType[] types) /// /// /// - public static AbstractCriterion Sql(SqlString sql) + //Since v5.3 + [Obsolete("Use Restrictions.Sql instead")] + public new static AbstractCriterion Sql(SqlString sql) { return Sql(sql, Array.Empty(), TypeHelper.EmptyTypeArray); } @@ -68,7 +77,9 @@ public static AbstractCriterion Sql(SqlString sql) /// /// /// - public static AbstractCriterion Sql(string sql) + //Since v5.3 + [Obsolete("Use Restrictions.Sql instead")] + public new static AbstractCriterion Sql(string sql) { return Sql(sql, Array.Empty(), TypeHelper.EmptyTypeArray); } diff --git a/src/NHibernate/Criterion/ICriteriaQuery.cs b/src/NHibernate/Criterion/ICriteriaQuery.cs index 7113e6676b4..b7db32441d8 100644 --- a/src/NHibernate/Criterion/ICriteriaQuery.cs +++ b/src/NHibernate/Criterion/ICriteriaQuery.cs @@ -1,11 +1,28 @@ using System.Collections.Generic; using NHibernate.Engine; +using NHibernate.Loader.Criteria; using NHibernate.Param; using NHibernate.SqlCommand; using NHibernate.Type; +using NHibernate.Util; namespace NHibernate.Criterion { + //TODO 6.0: Add to ICriteriaQuery interface + internal static class CriteriaQueryExtensions + { + /// + /// Get the SQL table alias for given criteria alias + /// + public static string GetSQLAlias(this ICriteriaQuery query, string criteriaAlias) + { + return + ReflectHelper + .CastOrThrow(query, "retrieving criteria SQL alias") + .GetSQLAlias(criteriaAlias); + } + } + /// /// An instance of is passed to criterion, /// order and projection instances when actually compiling and @@ -80,4 +97,4 @@ public interface ICriteriaQuery Parameter CreateSkipParameter(int value); Parameter CreateTakeParameter(int value); } -} \ No newline at end of file +} diff --git a/src/NHibernate/Criterion/Projections.cs b/src/NHibernate/Criterion/Projections.cs index 468bcb50511..e2c13c9cb39 100644 --- a/src/NHibernate/Criterion/Projections.cs +++ b/src/NHibernate/Criterion/Projections.cs @@ -214,12 +214,40 @@ public static AggregateProjection Sum(IProjection projection) } /// - /// A SQL projection, a typed select clause fragment + /// A SQL projection, a typed select clause fragment. + /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") /// - /// - /// - /// - /// + /// The sql fragment representing the columns to select. + /// The column alias names returned by . + /// The types of each column returned by . + /// A sql projection. + public static SQLProjection Sql(string sql, string[] columnAliases, IType[] types) + { + return new SQLProjection(sql, columnAliases, types); + } + + /// + /// A grouping SQL projection, specifying both select clause and group by clause fragments + /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") + /// + /// The sql fragment representing the columns to select. + /// The sql fragment representing the columns to group by. + /// The column alias names returned by . + /// The types of each column returned by . + /// A sql projection. + public static SQLProjection Sql(string sql, string groupBy, string[] columnAliases, IType[] types) + { + return new SQLProjection(sql, groupBy, columnAliases, types); + } + + /// + /// A SQL projection, a typed select clause fragment. + /// The string {alias} will be replaced by the alias of the root entity. + /// + //Since v5.3 + [Obsolete("Use Projections.Sql instead")] public static IProjection SqlProjection(string sql, string[] columnAliases, IType[] types) { return new SQLProjection(sql, columnAliases, types); @@ -227,12 +255,10 @@ public static IProjection SqlProjection(string sql, string[] columnAliases, ITyp /// /// A grouping SQL projection, specifying both select clause and group by clause fragments + /// The string {alias} will be replaced by the alias of the root entity. /// - /// - /// - /// - /// - /// + //Since v5.3 + [Obsolete("Use Projections.Sql instead")] public static IProjection SqlGroupProjection(string sql, string groupBy, string[] columnAliases, IType[] types) { return new SQLProjection(sql, groupBy, columnAliases, types); diff --git a/src/NHibernate/Criterion/Restrictions.cs b/src/NHibernate/Criterion/Restrictions.cs index 2ca3e11d374..733719db140 100644 --- a/src/NHibernate/Criterion/Restrictions.cs +++ b/src/NHibernate/Criterion/Restrictions.cs @@ -5,6 +5,8 @@ using System.Linq.Expressions; using NHibernate.Criterion.Lambda; using NHibernate.Impl; +using NHibernate.SqlCommand; +using NHibernate.Type; namespace NHibernate.Criterion { @@ -795,5 +797,85 @@ public static LambdaRestrictionBuilder On(Expression> expression) ExpressionProcessor.ProjectionInfo projection = ExpressionProcessor.FindMemberProjection(expression.Body); return new LambdaRestrictionBuilder(projection); } + + /// + /// Apply a constraint expressed in SQL, with the given SQL parameters + /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") + /// + /// The sql constraint expression, with ? representing a parameter. + /// The parameters values for . + /// The parameters types. + /// A sql criterion. + public static SQLCriterion Sql(SqlString sql, object[] values, IType[] types) + { + return new SQLCriterion(sql, values, types); + } + + /// + /// Apply a constraint expressed in SQL, with the given SQL parameter + /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") + /// + /// The sql constraint expression, with ? representing the parameter. + /// The parameters value for . + /// The parameter type. + /// A sql criterion. + public static SQLCriterion Sql(SqlString sql, object value, IType type) + { + return Sql(sql, new object[] { value }, new IType[] { type }); + } + + /// + /// Apply a constraint expressed in SQL, with the given SQL parameter + /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") + /// + /// The sql constraint expression, with ? representing the parameter. + /// The parameters value for . + /// The parameter type. + /// A sql criterion. + public static SQLCriterion Sql(string sql, object value, IType type) + { + return Sql(sql, new object[] { value }, new IType[] { type }); + } + + /// + /// Apply a constraint expressed in SQL, with the given SQL parameter + /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") + /// + /// The sql constraint expression, with ? representing a parameter. + /// The parameters values for . + /// The parameters types. + /// A sql criterion. + public static SQLCriterion Sql(string sql, object[] values, IType[] types) + { + return new SQLCriterion(SqlString.Parse(sql), values, types); + } + + /// + /// Apply a constraint expressed in SQL + /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") + /// + /// The sql constraint expression. + /// A sql criterion. + public static SQLCriterion Sql(SqlString sql) + { + return Sql(sql, Array.Empty(), TypeHelper.EmptyTypeArray); + } + + /// + /// Apply a constraint expressed in SQL + /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") + /// + /// The sql constraint expression. + /// A sql criterion. + public static SQLCriterion Sql(string sql) + { + return Sql(sql, Array.Empty(), TypeHelper.EmptyTypeArray); + } } } diff --git a/src/NHibernate/Criterion/SQLCriterion.cs b/src/NHibernate/Criterion/SQLCriterion.cs index 06df9db44a3..47596d9c4cd 100644 --- a/src/NHibernate/Criterion/SQLCriterion.cs +++ b/src/NHibernate/Criterion/SQLCriterion.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using NHibernate.Engine; using NHibernate.SqlCommand; @@ -9,6 +10,7 @@ namespace NHibernate.Criterion /// /// An that creates a SQLExpression. /// The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") /// /// /// This allows for database specific Expressions at the cost of needing to @@ -19,6 +21,7 @@ public class SQLCriterion : AbstractCriterion { private readonly SqlString _sql; private readonly TypedValue[] _typedValues; + private List _criteriaAliases; public SQLCriterion(SqlString sql, object[] values, IType[] types) { @@ -42,7 +45,7 @@ public override SqlString ToSqlString(ICriteria criteria, ICriteriaQuery criteri parameters[paramPos++].BackTrack = parameter.BackTrack; } } - return _sql.Replace("{alias}", criteriaQuery.GetSQLAlias(criteria)); + return SQLProjection.GetSqlString(criteria, criteriaQuery, _sql, _criteriaAliases); } public override TypedValue[] GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery) @@ -59,5 +62,21 @@ public override string ToString() { return _sql.ToString(); } + + /// + /// Provide the list of criteria aliases which are used in SQL criterion, + /// and need to be replaced with SQL aliases. + /// + /// The list of criteria aliases. + /// A SQL criterion. + public SQLCriterion AddAliases(params string[] criteriaAliases) + { + if(_criteriaAliases == null) + _criteriaAliases = new List(); + + _criteriaAliases.AddRange(criteriaAliases); + + return this; + } } } diff --git a/src/NHibernate/Criterion/SQLProjection.cs b/src/NHibernate/Criterion/SQLProjection.cs index ce1d9c39448..b3a1b16ff96 100644 --- a/src/NHibernate/Criterion/SQLProjection.cs +++ b/src/NHibernate/Criterion/SQLProjection.cs @@ -1,7 +1,7 @@ using System; +using System.Collections.Generic; using NHibernate.SqlCommand; using NHibernate.Type; -using NHibernate.Util; namespace NHibernate.Criterion { @@ -9,6 +9,7 @@ namespace NHibernate.Criterion /// /// A SQL fragment. The string {alias} will be replaced by the alias of the root entity. + /// Criteria aliases can also be used: "{a}.Value + {bc}.Value". Such aliases need to be registered via call to AddAliases("a", "bc") /// [Serializable] public sealed class SQLProjection : IProjection @@ -19,6 +20,7 @@ public sealed class SQLProjection : IProjection private readonly string[] aliases; private readonly string[] columnAliases; private readonly bool grouped; + private List _criteriaAliases; internal SQLProjection(string sql, string[] columnAliases, IType[] types) : this(sql, null, columnAliases, types) @@ -37,15 +39,50 @@ internal SQLProjection(string sql, string groupBy, string[] columnAliases, IType public SqlString ToSqlString(ICriteria criteria, int loc, ICriteriaQuery criteriaQuery) { - //SqlString result = new SqlString(criteriaQuery.GetSQLAlias(criteria)); - //result.Replace(sql, "{alias}"); - //return result; - return new SqlString(sql?.Replace("{alias}", criteriaQuery.GetSQLAlias(criteria))); + return GetSqlString(criteria, criteriaQuery, sql); + } + + /// + /// Provide the list of criteria aliases which are used in SQL projection, + /// and need to be replaced with SQL aliases. + /// + /// The list of criteria aliases. + /// A SQL projection. + public SQLProjection AddAliases(params string[] criteriaAliases) + { + if(_criteriaAliases == null) + _criteriaAliases = new List(); + + _criteriaAliases.AddRange(criteriaAliases); + + return this; } public SqlString ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery) { - return new SqlString(groupBy?.Replace("{alias}", criteriaQuery.GetSQLAlias(criteria))); + return GetSqlString(criteria, criteriaQuery, groupBy); + } + + private SqlString GetSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, string sqlTemplate) + { + return GetSqlString(criteria, criteriaQuery, new SqlString(sqlTemplate), _criteriaAliases); + } + + internal static SqlString GetSqlString( + ICriteria criteria, + ICriteriaQuery criteriaQuery, + SqlString sqlTemplate, + List criteriaAliases) + { + if (criteriaAliases != null) + { + foreach (var alias in criteriaAliases) + { + sqlTemplate = sqlTemplate.Replace("{" + alias + "}", criteriaQuery.GetSQLAlias(alias)); + } + } + + return sqlTemplate.Replace("{alias}", criteriaQuery.GetSQLAlias(criteria)); } public override string ToString() diff --git a/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs b/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs index 682dc73e084..ddf5ae6dd47 100644 --- a/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs +++ b/src/NHibernate/Loader/Criteria/CriteriaQueryTranslator.cs @@ -863,6 +863,18 @@ public string GetEntityName(ICriteria subcriteria, string propertyName) return GetEntityName(subcriteria); } + //TODO 6.0: Add to ICriteriaQuery interface + public string GetSQLAlias(string criteriaAlias) + { + if (aliasCriteriaMap.TryGetValue(criteriaAlias, out var criteria)) + return GetSQLAlias(criteria); + + if (outerQueryTranslator != null) + return outerQueryTranslator.GetSQLAlias(criteriaAlias); + + throw new InvalidOperationException("Could not find criteria by alias: " + criteriaAlias); + } + public string GetSQLAlias(ICriteria criteria, string propertyName) { if (StringHelper.IsNotRoot(propertyName, out var root))