Skip to content

Commit 8162a91

Browse files
committed
GH-948 (NH-3435):
1) Added more tests (lazy and eager version); 2) Refactored BaseEntityProjection to use ILoadable interface instead of AbstractEntityPersister; 3) Exteneded Projections helper method to expose lazy setting and allow to use from QueryOver.
1 parent 583f7fc commit 8162a91

File tree

5 files changed

+314
-93
lines changed

5 files changed

+314
-93
lines changed

src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
using System.Text.RegularExpressions;
1515
using NHibernate.Criterion;
1616
using NHibernate.Dialect;
17+
using NHibernate.SqlCommand;
1718
using NHibernate.SqlTypes;
1819
using NHibernate.Type;
1920
using NUnit.Framework;
@@ -57,10 +58,49 @@ protected override void OnSetUp()
5758
}
5859
}
5960

61+
private void PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode)
62+
{
63+
courseCode = "HIB";
64+
using (ISession session = Sfi.OpenSession())
65+
using (ITransaction tx = session.BeginTransaction())
66+
{
67+
Course course = new Course
68+
{
69+
CourseCode = "HIB",
70+
Description = "Hibernate Training"
71+
};
72+
session.Save(course);
73+
74+
gavin = new Student
75+
{
76+
Name = "Gavin King",
77+
StudentNumber = 667,
78+
79+
};
80+
session.Save(gavin);
81+
82+
Enrolment enrolment = new Enrolment
83+
{
84+
Course = course,
85+
CourseCode = course.CourseCode,
86+
Semester = 1,
87+
Year = 1999,
88+
Student = gavin,
89+
StudentNumber = gavin.StudentNumber
90+
};
91+
gavin.Enrolments.Add(enrolment);
92+
session.Save(enrolment);
93+
94+
session.Flush();
95+
tx.Commit();
96+
}
97+
}
98+
6099
protected override void OnTearDown()
61100
{
62101
using (ISession session = Sfi.OpenSession())
63102
{
103+
session.Delete($"from {typeof(Enrolment).FullName}");
64104
session.Delete("from System.Object");
65105
session.Flush();
66106
}
@@ -443,5 +483,111 @@ public async Task UseSubquerySumWithNullResultWithProjectionAsync()
443483
Assert.AreEqual(0, sum);
444484
}
445485
}
486+
487+
[Test]
488+
public async Task UseRootProjection_EagerAsync()
489+
{
490+
//NH-3435
491+
PrepareDataForEntityProjectionTests(out Student gavin, out string _);
492+
493+
using (ISession session = Sfi.OpenSession())
494+
{
495+
Student g = await (session.CreateCriteria(typeof(Student))
496+
.Add(Expression.IdEq(gavin.StudentNumber))
497+
.SetFetchMode("Enrolments", FetchMode.Join)
498+
.SetProjection(Projections.RootEntity(lazy: false))
499+
.UniqueResultAsync<Student>());
500+
501+
Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
502+
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
503+
}
504+
}
505+
506+
[Test]
507+
public async Task UseRootProjection_LazyAsync()
508+
{
509+
PrepareDataForEntityProjectionTests(out Student gavin, out string _);
510+
511+
//NH-3435
512+
using (ISession session = Sfi.OpenSession())
513+
{
514+
Student g = await (session.CreateCriteria(typeof(Student))
515+
.Add(Expression.IdEq(gavin.StudentNumber))
516+
.SetFetchMode("Enrolments", FetchMode.Join)
517+
.SetProjection(Projections.RootEntity(lazy: false))
518+
.UniqueResultAsync<Student>());
519+
520+
Assert.That(NHibernateUtil.IsInitialized(g), Is.False, "object must be lazy and not initialized");
521+
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
522+
}
523+
}
524+
525+
[Test]
526+
public async Task UseEntityProjection_EagerAsync()
527+
{
528+
//NH-3435
529+
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);
530+
531+
using (ISession session = Sfi.OpenSession())
532+
{
533+
Student g = await (session.CreateCriteria(typeof(Enrolment))
534+
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", courseCode)))
535+
.CreateAlias("Student", "s", JoinType.InnerJoin)
536+
.SetProjection(Projections.Entity<Student>("s", lazy:false))
537+
.UniqueResultAsync<Student>());
538+
539+
Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
540+
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
541+
}
542+
}
543+
544+
[Test]
545+
public async Task UseEntityProjection_LazyAsync()
546+
{
547+
//NH-3435
548+
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);
549+
550+
using (ISession session = Sfi.OpenSession())
551+
using (ITransaction tx = session.BeginTransaction())
552+
{
553+
Student g = await (session.CreateCriteria(typeof(Enrolment))
554+
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", courseCode)))
555+
.CreateAlias("Student", "s", JoinType.InnerJoin)
556+
.SetProjection(Projections.Entity<Student>("s", lazy:false))
557+
.UniqueResultAsync<Student>());
558+
559+
Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
560+
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
561+
}
562+
}
563+
564+
[Test]
565+
public async Task UseMultipleEntityProjectionsAsync()
566+
{
567+
//NH-3435
568+
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);
569+
570+
using (ISession session = Sfi.OpenSession())
571+
{
572+
Enrolment en = null;
573+
Student s = null;
574+
Course c = null;
575+
576+
var result = await (session.QueryOver(() => en)
577+
.Where(e => e.StudentNumber == gavin.StudentNumber && e.CourseCode == courseCode)
578+
.JoinAlias(e => e.Student, () => s)
579+
.JoinAlias(e => e.Course, () => c)
580+
.Select(Projections.RootEntity(lazy: true), Projections.Entity(() => s, lazy:false), Projections.Entity(() => c, lazy:false))
581+
.SingleOrDefaultAsync<object[]>());
582+
583+
en = (Enrolment) result[0];
584+
s = (Student) result[1];
585+
c = (Course) result[2];
586+
587+
Assert.That(NHibernateUtil.IsInitialized(en), Is.False, "Object must be lazy and not initialized");
588+
Assert.That(NHibernateUtil.IsInitialized(s), Is.True, "Object must be initialized");
589+
Assert.That(NHibernateUtil.IsInitialized(c), Is.True, "Object must be initialized");
590+
}
591+
}
446592
}
447593
}

src/NHibernate.Test/Criteria/ProjectionsTest.cs

Lines changed: 118 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,49 @@ protected override void OnSetUp()
4747
}
4848
}
4949

50+
private void PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode)
51+
{
52+
courseCode = "HIB";
53+
using (ISession session = Sfi.OpenSession())
54+
using (ITransaction tx = session.BeginTransaction())
55+
{
56+
Course course = new Course
57+
{
58+
CourseCode = "HIB",
59+
Description = "Hibernate Training"
60+
};
61+
session.Save(course);
62+
63+
gavin = new Student
64+
{
65+
Name = "Gavin King",
66+
StudentNumber = 667,
67+
68+
};
69+
session.Save(gavin);
70+
71+
Enrolment enrolment = new Enrolment
72+
{
73+
Course = course,
74+
CourseCode = course.CourseCode,
75+
Semester = 1,
76+
Year = 1999,
77+
Student = gavin,
78+
StudentNumber = gavin.StudentNumber
79+
};
80+
gavin.Enrolments.Add(enrolment);
81+
session.Save(enrolment);
82+
83+
session.Flush();
84+
tx.Commit();
85+
}
86+
}
87+
5088
protected override void OnTearDown()
5189
{
5290
using (ISession session = Sfi.OpenSession())
5391
{
92+
session.Delete($"from {typeof(Enrolment).FullName}");
5493
session.Delete("from System.Object");
5594
session.Flush();
5695
}
@@ -435,80 +474,108 @@ public void UseSubquerySumWithNullResultWithProjection()
435474
}
436475

437476
[Test]
438-
public void UseRootProjection()
477+
public void UseRootProjection_Eager()
439478
{
440479
//NH-3435
480+
PrepareDataForEntityProjectionTests(out Student gavin, out string _);
481+
441482
using (ISession session = Sfi.OpenSession())
442-
using (ITransaction tx = session.BeginTransaction())
443483
{
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);
484+
Student g = session.CreateCriteria(typeof(Student))
485+
.Add(Expression.IdEq(gavin.StudentNumber))
486+
.SetFetchMode("Enrolments", FetchMode.Join)
487+
.SetProjection(Projections.RootEntity(lazy: false))
488+
.UniqueResult<Student>();
453489

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);
490+
Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
491+
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
492+
}
493+
}
463494

464-
session.Flush();
495+
[Test]
496+
public void UseRootProjection_Lazy()
497+
{
498+
PrepareDataForEntityProjectionTests(out Student gavin, out string _);
465499

500+
//NH-3435
501+
using (ISession session = Sfi.OpenSession())
502+
{
466503
Student g = session.CreateCriteria(typeof(Student))
467-
.Add(Expression.IdEq(gavin.StudentNumber))
468-
.SetFetchMode("Enrolments", FetchMode.Join)
469-
.SetProjection(Projections.RootEntity())
470-
.UniqueResult<Student>();
504+
.Add(Expression.IdEq(gavin.StudentNumber))
505+
.SetFetchMode("Enrolments", FetchMode.Join)
506+
.SetProjection(Projections.RootEntity(lazy: false))
507+
.UniqueResult<Student>();
508+
509+
Assert.That(NHibernateUtil.IsInitialized(g), Is.False, "object must be lazy and not initialized");
510+
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
511+
}
512+
}
513+
514+
[Test]
515+
public void UseEntityProjection_Eager()
516+
{
517+
//NH-3435
518+
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);
519+
520+
using (ISession session = Sfi.OpenSession())
521+
{
522+
Student g = session.CreateCriteria(typeof(Enrolment))
523+
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", courseCode)))
524+
.CreateAlias("Student", "s", JoinType.InnerJoin)
525+
.SetProjection(Projections.Entity<Student>("s", lazy:false))
526+
.UniqueResult<Student>();
471527

472-
Assert.AreSame(gavin, g);
528+
Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
529+
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
473530
}
474531
}
475532

476533
[Test]
477-
public void UseEntityProjection()
534+
public void UseEntityProjection_Lazy()
478535
{
479536
//NH-3435
537+
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);
538+
480539
using (ISession session = Sfi.OpenSession())
481540
using (ITransaction tx = session.BeginTransaction())
482541
{
483-
Course course = new Course();
484-
course.CourseCode = "HIB";
485-
course.Description = "Hibernate Training";
486-
session.Save(course);
542+
Student g = session.CreateCriteria(typeof(Enrolment))
543+
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", courseCode)))
544+
.CreateAlias("Student", "s", JoinType.InnerJoin)
545+
.SetProjection(Projections.Entity<Student>("s", lazy:false))
546+
.UniqueResult<Student>();
487547

488-
Student gavin = new Student();
489-
gavin.Name = "Gavin King";
490-
gavin.StudentNumber = 667;
491-
session.Save(gavin);
548+
Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
549+
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
550+
}
551+
}
492552

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);
553+
[Test]
554+
public void UseMultipleEntityProjections()
555+
{
556+
//NH-3435
557+
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);
502558

503-
session.Flush();
559+
using (ISession session = Sfi.OpenSession())
560+
{
561+
Enrolment en = null;
562+
Student s = null;
563+
Course c = null;
504564

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>();
565+
var result = session.QueryOver(() => en)
566+
.Where(e => e.StudentNumber == gavin.StudentNumber && e.CourseCode == courseCode)
567+
.JoinAlias(e => e.Student, () => s)
568+
.JoinAlias(e => e.Course, () => c)
569+
.Select(Projections.RootEntity(lazy: true), Projections.Entity(() => s, lazy:false), Projections.Entity(() => c, lazy:false))
570+
.SingleOrDefault<object[]>();
571+
572+
en = (Enrolment) result[0];
573+
s = (Student) result[1];
574+
c = (Course) result[2];
510575

511-
Assert.AreSame(gavin, g);
576+
Assert.That(NHibernateUtil.IsInitialized(en), Is.False, "Object must be lazy and not initialized");
577+
Assert.That(NHibernateUtil.IsInitialized(s), Is.True, "Object must be initialized");
578+
Assert.That(NHibernateUtil.IsInitialized(c), Is.True, "Object must be initialized");
512579
}
513580
}
514581
}

0 commit comments

Comments
 (0)