Skip to content

#948(NH-3435) - Ability to select entities in a criteria projections (rebased PR #302) #1458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions src/NHibernate.Test/Async/Criteria/ProjectionsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
using System.Text.RegularExpressions;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using NHibernate.Type;
using NUnit.Framework;
Expand Down Expand Up @@ -57,10 +58,49 @@ protected override void OnSetUp()
}
}

private void PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode)
{
courseCode = "HIB";
using (ISession session = Sfi.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
Course course = new Course
{
CourseCode = "HIB",
Description = "Hibernate Training"
};
session.Save(course);

gavin = new Student
{
Name = "Gavin King",
StudentNumber = 667,

};
session.Save(gavin);

Enrolment enrolment = new Enrolment
{
Course = course,
CourseCode = course.CourseCode,
Semester = 1,
Year = 1999,
Student = gavin,
StudentNumber = gavin.StudentNumber
};
gavin.Enrolments.Add(enrolment);
session.Save(enrolment);

session.Flush();
tx.Commit();
}
}

protected override void OnTearDown()
{
using (ISession session = Sfi.OpenSession())
{
session.Delete($"from {typeof(Enrolment).FullName}");
session.Delete("from System.Object");
session.Flush();
}
Expand Down Expand Up @@ -443,5 +483,111 @@ public async Task UseSubquerySumWithNullResultWithProjectionAsync()
Assert.AreEqual(0, sum);
}
}

[Test]
public async Task UseRootProjection_EagerAsync()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string _);

using (ISession session = Sfi.OpenSession())
{
Student g = await (session.CreateCriteria(typeof(Student))
.Add(Expression.IdEq(gavin.StudentNumber))
.SetFetchMode("Enrolments", FetchMode.Join)
.SetProjection(Projections.RootEntity(lazy: false))
.UniqueResultAsync<Student>());

Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
}
}

[Test]
public async Task UseRootProjection_LazyAsync()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string _);

using (ISession session = Sfi.OpenSession())
{
Student g = await (session.CreateCriteria(typeof(Student))
.Add(Expression.IdEq(gavin.StudentNumber))
.SetFetchMode("Enrolments", FetchMode.Join)
.SetProjection(Projections.RootEntity(lazy: true))
.UniqueResultAsync<Student>());

Assert.That(NHibernateUtil.IsInitialized(g), Is.False, "object must be lazy and not initialized");
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
}
}

[Test]
public async Task UseEntityProjection_EagerAsync()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);

using (ISession session = Sfi.OpenSession())
{
Student g = await (session.CreateCriteria(typeof(Enrolment))
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", courseCode)))
.CreateAlias("Student", "s", JoinType.InnerJoin)
.SetProjection(Projections.Entity<Student>("s", lazy:false))
.UniqueResultAsync<Student>());

Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
}
}

[Test]
public async Task UseEntityProjection_LazyAsync()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);

using (ISession session = Sfi.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
Student g = await (session.CreateCriteria(typeof(Enrolment))
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", courseCode)))
.CreateAlias("Student", "s", JoinType.InnerJoin)
.SetProjection(Projections.Entity<Student>("s", lazy:true))
.UniqueResultAsync<Student>());

Assert.That(NHibernateUtil.IsInitialized(g), Is.False, "object must be lazy and not initialized");
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
}
}

[Test]
public async Task UseMultipleEntityProjectionsAsync()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);

using (ISession session = Sfi.OpenSession())
{
Enrolment en = null;
Student s = null;
Course c = null;

var result = await (session.QueryOver(() => en)
.Where(e => e.StudentNumber == gavin.StudentNumber && e.CourseCode == courseCode)
.JoinAlias(e => e.Student, () => s)
.JoinAlias(e => e.Course, () => c)
.Select(Projections.RootEntity(lazy: true), Projections.Entity(() => s, lazy:false), Projections.Entity(() => c, lazy:false))
.SingleOrDefaultAsync<object[]>());

en = (Enrolment) result[0];
s = (Student) result[1];
c = (Course) result[2];

Assert.That(NHibernateUtil.IsInitialized(en), Is.False, "Object must be lazy and not initialized");
Assert.That(NHibernateUtil.IsInitialized(s), Is.True, "Object must be initialized");
Assert.That(NHibernateUtil.IsInitialized(c), Is.True, "Object must be initialized");
}
}
}
}
146 changes: 146 additions & 0 deletions src/NHibernate.Test/Criteria/ProjectionsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Text.RegularExpressions;
using NHibernate.Criterion;
using NHibernate.Dialect;
using NHibernate.SqlCommand;
using NHibernate.SqlTypes;
using NHibernate.Type;
using NUnit.Framework;
Expand Down Expand Up @@ -46,10 +47,49 @@ protected override void OnSetUp()
}
}

private void PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode)
{
courseCode = "HIB";
using (ISession session = Sfi.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
Course course = new Course
{
CourseCode = "HIB",
Description = "Hibernate Training"
};
session.Save(course);

gavin = new Student
{
Name = "Gavin King",
StudentNumber = 667,

};
session.Save(gavin);

Enrolment enrolment = new Enrolment
{
Course = course,
CourseCode = course.CourseCode,
Semester = 1,
Year = 1999,
Student = gavin,
StudentNumber = gavin.StudentNumber
};
gavin.Enrolments.Add(enrolment);
session.Save(enrolment);

session.Flush();
tx.Commit();
}
}

protected override void OnTearDown()
{
using (ISession session = Sfi.OpenSession())
{
session.Delete($"from {typeof(Enrolment).FullName}");
session.Delete("from System.Object");
session.Flush();
}
Expand Down Expand Up @@ -432,5 +472,111 @@ public void UseSubquerySumWithNullResultWithProjection()
Assert.AreEqual(0, sum);
}
}

[Test]
public void UseRootProjection_Eager()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string _);

using (ISession session = Sfi.OpenSession())
{
Student g = session.CreateCriteria(typeof(Student))
.Add(Expression.IdEq(gavin.StudentNumber))
.SetFetchMode("Enrolments", FetchMode.Join)
.SetProjection(Projections.RootEntity(lazy: false))
.UniqueResult<Student>();

Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
}
}

[Test]
public void UseRootProjection_Lazy()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string _);

using (ISession session = Sfi.OpenSession())
{
Student g = session.CreateCriteria(typeof(Student))
.Add(Expression.IdEq(gavin.StudentNumber))
.SetFetchMode("Enrolments", FetchMode.Join)
.SetProjection(Projections.RootEntity(lazy: true))
.UniqueResult<Student>();

Assert.That(NHibernateUtil.IsInitialized(g), Is.False, "object must be lazy and not initialized");
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
}
}

[Test]
public void UseEntityProjection_Eager()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);

using (ISession session = Sfi.OpenSession())
{
Student g = session.CreateCriteria(typeof(Enrolment))
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", courseCode)))
.CreateAlias("Student", "s", JoinType.InnerJoin)
.SetProjection(Projections.Entity<Student>("s", lazy:false))
.UniqueResult<Student>();

Assert.That(NHibernateUtil.IsInitialized(g), Is.True, "object must be initialized");
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
}
}

[Test]
public void UseEntityProjection_Lazy()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);

using (ISession session = Sfi.OpenSession())
using (ITransaction tx = session.BeginTransaction())
{
Student g = session.CreateCriteria(typeof(Enrolment))
.Add(Expression.And(Expression.Eq("StudentNumber", gavin.StudentNumber), Expression.Eq("CourseCode", courseCode)))
.CreateAlias("Student", "s", JoinType.InnerJoin)
.SetProjection(Projections.Entity<Student>("s", lazy:true))
.UniqueResult<Student>();

Assert.That(NHibernateUtil.IsInitialized(g), Is.False, "object must be lazy and not initialized");
Assert.That(g, Is.EqualTo(gavin).Using((Student x, Student y) => x.StudentNumber == y.StudentNumber && x.Name == y.Name ? 0 : 1));
}
}

[Test]
public void UseMultipleEntityProjections()
{
//NH-3435
PrepareDataForEntityProjectionTests(out Student gavin, out string courseCode);

using (ISession session = Sfi.OpenSession())
{
Enrolment en = null;
Student s = null;
Course c = null;

var result = session.QueryOver(() => en)
.Where(e => e.StudentNumber == gavin.StudentNumber && e.CourseCode == courseCode)
.JoinAlias(e => e.Student, () => s)
.JoinAlias(e => e.Course, () => c)
.Select(Projections.RootEntity(lazy: true), Projections.Entity(() => s, lazy:false), Projections.Entity(() => c, lazy:false))
.SingleOrDefault<object[]>();

en = (Enrolment) result[0];
s = (Student) result[1];
c = (Course) result[2];

Assert.That(NHibernateUtil.IsInitialized(en), Is.False, "Object must be lazy and not initialized");
Assert.That(NHibernateUtil.IsInitialized(s), Is.True, "Object must be initialized");
Assert.That(NHibernateUtil.IsInitialized(c), Is.True, "Object must be initialized");
}
}
}
}
56 changes: 56 additions & 0 deletions src/NHibernate.Test/NHSpecificTest/GH948/Entities.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;

namespace NHibernate.Test.NHSpecificTest.GH948
{
public class EntitySimpleChild
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
}

public class EntityComplex
{
public virtual Guid Id { get; set; }

public virtual int Version { get; set; }

public virtual string Name { get; set; }

public virtual string LazyProp { get; set; }

public virtual EntitySimpleChild Child1 { get; set; }
public virtual EntitySimpleChild Child2 { get; set; }
public virtual EntityComplex SameTypeChild { get; set; }

public virtual IList<EntitySimpleChild> ChildrenList { get; set; }
}

public class CompositeKey
{
public int Id1 { get; set; }
public int Id2 { get; set; }

public override bool Equals(object obj)
{
var key = obj as CompositeKey;
return key != null
&& Id1 == key.Id1
&& Id2 == key.Id2;
}

public override int GetHashCode()
{
var hashCode = -1596524975;
hashCode = hashCode * -1521134295 + Id1.GetHashCode();
hashCode = hashCode * -1521134295 + Id2.GetHashCode();
return hashCode;
}
}

public class EntityWithCompositeId
{
public virtual CompositeKey Key { get; set; }
public virtual string Name { get; set; }
}
}
Loading