Skip to content

Commit 583f7fc

Browse files
rjperesbahusoid
authored andcommitted
NH-3435 - Ability to select the root entity in a criteria projection
1 parent 70413b7 commit 583f7fc

File tree

5 files changed

+263
-0
lines changed

5 files changed

+263
-0
lines changed

src/NHibernate.Test/Criteria/ProjectionsTest.cs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Text.RegularExpressions;
55
using NHibernate.Criterion;
66
using NHibernate.Dialect;
7+
using NHibernate.SqlCommand;
78
using NHibernate.SqlTypes;
89
using NHibernate.Type;
910
using NUnit.Framework;
@@ -432,5 +433,83 @@ public void UseSubquerySumWithNullResultWithProjection()
432433
Assert.AreEqual(0, sum);
433434
}
434435
}
436+
437+
[Test]
438+
public void UseRootProjection()
439+
{
440+
//NH-3435
441+
using (ISession session = Sfi.OpenSession())
442+
using (ITransaction tx = session.BeginTransaction())
443+
{
444+
Course course = new Course();
445+
course.CourseCode = "HIB";
446+
course.Description = "Hibernate Training";
447+
session.Save(course);
448+
449+
Student gavin = new Student();
450+
gavin.Name = "Gavin King";
451+
gavin.StudentNumber = 667;
452+
session.Save(gavin);
453+
454+
Enrolment enrolment = new Enrolment();
455+
enrolment.Course = course;
456+
enrolment.CourseCode = course.CourseCode;
457+
enrolment.Semester = 1;
458+
enrolment.Year = 1999;
459+
enrolment.Student = gavin;
460+
enrolment.StudentNumber = gavin.StudentNumber;
461+
gavin.Enrolments.Add(enrolment);
462+
session.Save(enrolment);
463+
464+
session.Flush();
465+
466+
Student g = session.CreateCriteria(typeof(Student))
467+
.Add(Expression.IdEq(gavin.StudentNumber))
468+
.SetFetchMode("Enrolments", FetchMode.Join)
469+
.SetProjection(Projections.RootEntity())
470+
.UniqueResult<Student>();
471+
472+
Assert.AreSame(gavin, g);
473+
}
474+
}
475+
476+
[Test]
477+
public void UseEntityProjection()
478+
{
479+
//NH-3435
480+
using (ISession session = Sfi.OpenSession())
481+
using (ITransaction tx = session.BeginTransaction())
482+
{
483+
Course course = new Course();
484+
course.CourseCode = "HIB";
485+
course.Description = "Hibernate Training";
486+
session.Save(course);
487+
488+
Student gavin = new Student();
489+
gavin.Name = "Gavin King";
490+
gavin.StudentNumber = 667;
491+
session.Save(gavin);
492+
493+
Enrolment enrolment = new Enrolment();
494+
enrolment.Course = course;
495+
enrolment.CourseCode = course.CourseCode;
496+
enrolment.Semester = 1;
497+
enrolment.Year = 1999;
498+
enrolment.Student = gavin;
499+
enrolment.StudentNumber = gavin.StudentNumber;
500+
gavin.Enrolments.Add(enrolment);
501+
session.Save(enrolment);
502+
503+
session.Flush();
504+
505+
Student g = session.CreateCriteria(typeof(Enrolment))
506+
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", course.CourseCode)))
507+
.CreateAlias("Student", "s", JoinType.InnerJoin)
508+
.SetProjection(Projections.Entity<Student>("s"))
509+
.UniqueResult<Student>();
510+
511+
Assert.AreSame(gavin, g);
512+
}
513+
}
435514
}
436515
}
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using NHibernate;
5+
using NHibernate.Criterion;
6+
using NHibernate.Engine;
7+
using NHibernate.Persister.Entity;
8+
using NHibernate.SqlCommand;
9+
using NHibernate.Type;
10+
11+
namespace NHibernate.Criterion
12+
{
13+
[Serializable]
14+
public abstract class BaseEntityProjection : IProjection
15+
{
16+
private string alias = null;
17+
private string[] columnAliases = null;
18+
private bool lazy = true;
19+
20+
protected BaseEntityProjection(System.Type rootEntity, string alias)
21+
{
22+
this.RootEntity = rootEntity;
23+
this.alias = alias;
24+
}
25+
26+
protected System.Type RootEntity
27+
{
28+
get;
29+
private set;
30+
}
31+
32+
public BaseEntityProjection SetLazy(bool lazy)
33+
{
34+
this.lazy = lazy;
35+
36+
return (this);
37+
}
38+
39+
string[] IProjection.Aliases
40+
{
41+
get
42+
{
43+
return (this.columnAliases.ToArray());
44+
}
45+
}
46+
47+
TypedValue[] IProjection.GetTypedValues(ICriteria criteria, ICriteriaQuery criteriaQuery)
48+
{
49+
throw new NotImplementedException();
50+
}
51+
52+
IType[] IProjection.GetTypes(string alias, ICriteria criteria, ICriteriaQuery criteriaQuery)
53+
{
54+
return (new IType[] { criteriaQuery.GetType(criteria, alias) });
55+
}
56+
57+
private void SetFields(ICriteria criteria)
58+
{
59+
if (this.RootEntity == null)
60+
{
61+
this.RootEntity = criteria.GetRootEntityTypeIfAvailable();
62+
}
63+
64+
if (this.alias == null)
65+
{
66+
this.alias = criteria.Alias;
67+
}
68+
}
69+
70+
IType[] IProjection.GetTypes(ICriteria criteria, ICriteriaQuery criteriaQuery)
71+
{
72+
this.SetFields(criteria);
73+
74+
return (new IType[] { new ManyToOneType(this.RootEntity.FullName, this.lazy) });
75+
}
76+
77+
bool IProjection.IsAggregate
78+
{
79+
get { return (false); }
80+
}
81+
82+
bool IProjection.IsGrouped
83+
{
84+
get { return (false); }
85+
}
86+
87+
SqlString IProjection.ToGroupSqlString(ICriteria criteria, ICriteriaQuery criteriaQuery)
88+
{
89+
throw new NotImplementedException();
90+
}
91+
92+
SqlString IProjection.ToSqlString(ICriteria criteria, int position, ICriteriaQuery criteriaQuery)
93+
{
94+
this.SetFields(criteria);
95+
96+
SqlStringBuilder builder = new SqlStringBuilder();
97+
AbstractEntityPersister persister = criteriaQuery.Factory.TryGetEntityPersister(this.RootEntity.FullName) as AbstractEntityPersister;
98+
ICriteria subcriteria = criteria.GetCriteriaByAlias(this.alias);
99+
100+
this.columnAliases = persister.GetIdentifierAliases(string.Empty);
101+
102+
string[] columnNames = persister.GetPropertyColumnNames(persister.IdentifierPropertyName).Select(x => string.Concat(criteriaQuery.GetSQLAlias(subcriteria, persister.IdentifierPropertyName), ".", criteriaQuery.Factory.Dialect.QuoteForColumnName(x))).ToArray();
103+
104+
for (int i = 0; i < columnNames.Length; ++i)
105+
{
106+
builder.Add(String.Format("{0} as {1}", columnNames[i], this.columnAliases[i]));
107+
108+
if (i < columnNames.Length - 1)
109+
{
110+
builder.Add(", ");
111+
}
112+
}
113+
114+
return (builder.ToSqlString());
115+
}
116+
117+
public string[] GetColumnAliases(int position, ICriteria criteria, ICriteriaQuery criteriaQuery)
118+
{
119+
return ((this as IProjection).Aliases);
120+
}
121+
122+
public string[] GetColumnAliases(string alias, int position, ICriteria criteria, ICriteriaQuery criteriaQuery)
123+
{
124+
return ((this as IProjection).Aliases);
125+
}
126+
}
127+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
3+
namespace NHibernate.Criterion
4+
{
5+
[Serializable]
6+
public class EntityProjection : BaseEntityProjection
7+
{
8+
public EntityProjection(System.Type rootEntity, String alias) : base(rootEntity, alias)
9+
{
10+
}
11+
}
12+
13+
[Serializable]
14+
public class EntityProjection<T> : EntityProjection
15+
{
16+
public EntityProjection(String alias) : base(typeof(T), alias)
17+
{
18+
}
19+
}
20+
}

src/NHibernate/Criterion/Projections.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,31 @@ namespace NHibernate.Criterion
1616
/// </summary>
1717
public static class Projections
1818
{
19+
/// <summary>
20+
/// Return the root entity.
21+
/// </summary>
22+
/// <returns>The root entity.</returns>
23+
public static IProjection RootEntity()
24+
{
25+
return (new RootEntityProjection());
26+
}
27+
28+
/// <summary>
29+
/// Return an aliased entity.
30+
/// </summary>
31+
/// <param name="type">The type of the entity.</param>
32+
/// <param name="alias">The alias of the entity.</param>
33+
/// <returns>A projection of the entity.</returns>
34+
public static IProjection Entity(System.Type type, string alias)
35+
{
36+
return (new EntityProjection(type, alias));
37+
}
38+
39+
public static IProjection Entity<T>(string alias)
40+
{
41+
return (new EntityProjection<T>(alias));
42+
}
43+
1944
/// <summary>
2045
/// Create a distinct projection from a projection
2146
/// </summary>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System;
2+
3+
namespace NHibernate.Criterion
4+
{
5+
[Serializable]
6+
public class RootEntityProjection : BaseEntityProjection
7+
{
8+
public RootEntityProjection() : base(null, null)
9+
{
10+
}
11+
}
12+
}

0 commit comments

Comments
 (0)