diff --git a/src/NHibernate.Test/Criteria/ProjectionsTest.cs b/src/NHibernate.Test/Criteria/ProjectionsTest.cs index 8bc4e71ccc9..b2b36ff5ad8 100644 --- a/src/NHibernate.Test/Criteria/ProjectionsTest.cs +++ b/src/NHibernate.Test/Criteria/ProjectionsTest.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using NHibernate.Criterion; using NHibernate.Dialect; +using NHibernate.SqlCommand; using NUnit.Framework; namespace NHibernate.Test.Criteria @@ -347,6 +348,82 @@ public void UseNotEqPropertyWithProjection() } } + [Test] + public void UseRootProjection() + { + //NH-3435 + using (ISession session = sessions.OpenSession()) + using (ITransaction tx = session.BeginTransaction()) + { + Course course = new Course(); + course.CourseCode = "HIB"; + course.Description = "Hibernate Training"; + session.Save(course); + + Student gavin = new Student(); + gavin.Name = "Gavin King"; + gavin.StudentNumber = 667; + session.Save(gavin); + + Enrolment enrolment = new Enrolment(); + enrolment.Course = course; + enrolment.CourseCode = course.CourseCode; + enrolment.Semester = 1; + enrolment.Year = 1999; + enrolment.Student = gavin; + enrolment.StudentNumber = gavin.StudentNumber; + gavin.Enrolments.Add(enrolment); + session.Save(enrolment); + + session.Flush(); + + Student g = session.CreateCriteria(typeof(Student)) + .Add(Expression.IdEq(gavin.StudentNumber)) + .SetFetchMode("Enrolments", FetchMode.Join) + .SetProjection(Projections.RootEntity()) + .UniqueResult(); + + Assert.AreSame(gavin, g); + } + } + [Test] + public void UseEntityProjection() + { + //NH-3435 + using (ISession session = sessions.OpenSession()) + using (ITransaction tx = session.BeginTransaction()) + { + Course course = new Course(); + course.CourseCode = "HIB"; + course.Description = "Hibernate Training"; + session.Save(course); + + Student gavin = new Student(); + gavin.Name = "Gavin King"; + gavin.StudentNumber = 667; + session.Save(gavin); + + Enrolment enrolment = new Enrolment(); + enrolment.Course = course; + enrolment.CourseCode = course.CourseCode; + enrolment.Semester = 1; + enrolment.Year = 1999; + enrolment.Student = gavin; + enrolment.StudentNumber = gavin.StudentNumber; + gavin.Enrolments.Add(enrolment); + session.Save(enrolment); + + session.Flush(); + + Student g = session.CreateCriteria(typeof(Enrolment)) + .Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", course.CourseCode))) + .CreateAlias("Student", "s", JoinType.InnerJoin) + .SetProjection(Projections.Entity("s")) + .UniqueResult(); + + Assert.AreSame(gavin, g); + } + } } } diff --git a/src/NHibernate/Criterion/BaseEntityProjection.cs b/src/NHibernate/Criterion/BaseEntityProjection.cs new file mode 100644 index 00000000000..7272d165b48 --- /dev/null +++ b/src/NHibernate/Criterion/BaseEntityProjection.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NHibernate; +using NHibernate.Criterion; +using NHibernate.Engine; +using NHibernate.Persister.Entity; +using NHibernate.SqlCommand; +using NHibernate.Type; + +namespace NHibernate.Criterion +{ + [Serializable] + public abstract class BaseEntityProjection : IProjection + { + private string alias = null; + private string[] columnAliases = null; + private bool lazy = true; + + protected BaseEntityProjection(System.Type rootEntity, string alias) + { + this.RootEntity = rootEntity; + this.alias = alias; + } + + protected System.Type RootEntity + { + get; + private set; + } + + public BaseEntityProjection SetLazy(bool lazy) + { + this.lazy = lazy; + + return (this); + } + + string[] IProjection.Aliases + { + get + { + return (this.columnAliases.ToArray()); + } + } + + TypedValue[] IProjection.GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery) + { + throw new NotImplementedException(); + } + + IType[] IProjection.GetTypes(string alias, ICriteria criteria, ICriteriaQuery criteriaQuery) + { + return (new IType[] { criteriaQuery.GetType(criteria, alias) }); + } + + private void SetFields(ICriteria criteria) + { + if (this.RootEntity == null) + { + this.RootEntity = criteria.GetRootEntityTypeIfAvailable(); + } + + if (this.alias == null) + { + this.alias = criteria.Alias; + } + } + + IType[] IProjection.GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery) + { + this.SetFields(criteria); + + return (new IType[] { new ManyToOneType(this.RootEntity.FullName, this.lazy) }); + } + + bool IProjection.IsAggregate + { + get { return (false); } + } + + bool IProjection.IsGrouped + { + get { return (false); } + } + + SqlString IProjection.ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery, IDictionary enabledFilters) + { + throw new NotImplementedException(); + } + + SqlString IProjection.ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery, IDictionary enabledFilters) + { + this.SetFields(criteria); + + SqlStringBuilder builder = new SqlStringBuilder(); + AbstractEntityPersister persister = criteriaQuery.Factory.TryGetEntityPersister(this.RootEntity.FullName) as AbstractEntityPersister; + ICriteria subcriteria = criteria.GetCriteriaByAlias(this.alias); + + this.columnAliases = persister.GetIdentifierAliases(string.Empty); + + string[] columnNames = persister.GetPropertyColumnNames(persister.IdentifierPropertyName).Select(x => string.Concat(criteriaQuery.GetSQLAlias(subcriteria, persister.IdentifierPropertyName), ".", criteriaQuery.Factory.Dialect.QuoteForColumnName(x))).ToArray(); + + for (int i = 0; i < columnNames.Length; ++i) + { + builder.Add(String.Format("{0} as {1}", columnNames[i], this.columnAliases[i])); + + if (i < columnNames.Length - 1) + { + builder.Add(", "); + } + } + + return (builder.ToSqlString()); + } + + public string[] GetColumnAliases(int position, ICriteria criteria, ICriteriaQuery criteriaQuery) + { + return ((this as IProjection).Aliases); + } + + public string[] GetColumnAliases(string alias, int position, ICriteria criteria, ICriteriaQuery criteriaQuery) + { + return ((this as IProjection).Aliases); + } + } +} \ No newline at end of file diff --git a/src/NHibernate/Criterion/EntityProjection.cs b/src/NHibernate/Criterion/EntityProjection.cs new file mode 100644 index 00000000000..9ceb093fa58 --- /dev/null +++ b/src/NHibernate/Criterion/EntityProjection.cs @@ -0,0 +1,20 @@ +using System; + +namespace NHibernate.Criterion +{ + [Serializable] + public class EntityProjection : BaseEntityProjection + { + public EntityProjection(System.Type rootEntity, String alias) : base(rootEntity, alias) + { + } + } + + [Serializable] + public class EntityProjection : EntityProjection + { + public EntityProjection(String alias) : base(typeof(T), alias) + { + } + } +} \ No newline at end of file diff --git a/src/NHibernate/Criterion/Projections.cs b/src/NHibernate/Criterion/Projections.cs index 88f750de722..eac1e59e942 100644 --- a/src/NHibernate/Criterion/Projections.cs +++ b/src/NHibernate/Criterion/Projections.cs @@ -16,6 +16,31 @@ namespace NHibernate.Criterion /// public static class Projections { + /// + /// Return the root entity. + /// + /// The root entity. + public static IProjection RootEntity() + { + return (new RootEntityProjection()); + } + + /// + /// Return an aliased entity. + /// + /// The type of the entity. + /// The alias of the entity. + /// A projection of the entity. + public static IProjection Entity(System.Type type, string alias) + { + return (new EntityProjection(type, alias)); + } + + public static IProjection Entity(string alias) + { + return (new EntityProjection(alias)); + } + /// /// Create a distinct projection from a projection /// diff --git a/src/NHibernate/Criterion/RootEntityProjection.cs b/src/NHibernate/Criterion/RootEntityProjection.cs new file mode 100644 index 00000000000..ff839cf63cf --- /dev/null +++ b/src/NHibernate/Criterion/RootEntityProjection.cs @@ -0,0 +1,12 @@ +using System; + +namespace NHibernate.Criterion +{ + [Serializable] + public class RootEntityProjection : BaseEntityProjection + { + public RootEntityProjection() : base(null, null) + { + } + } +} \ No newline at end of file diff --git a/src/NHibernate/NHibernate.csproj b/src/NHibernate/NHibernate.csproj index cbb25cad16d..4d05d85f8f1 100644 --- a/src/NHibernate/NHibernate.csproj +++ b/src/NHibernate/NHibernate.csproj @@ -138,6 +138,9 @@ + + +