-
Notifications
You must be signed in to change notification settings - Fork 936
NH-3435 - Ability to select the root entity in a criteria projection #302
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
Conversation
I'm afraid I don't follow... This appears to be only new code - what is being cleaned up? |
There was a broken pull request #299 |
Hi @rjperes, I've cleaned up your old pull request with:
|
Restarting tests |
BTW: can you lower the priority from Major to something else? And will it be in 4.1? |
Looks to me like this new code only selects the identifier of the root entity and not all the properties. |
Did you try it? |
Yes I did, and the SQL produced only selects the identifier. The way I read it, the code that retrieves the column names and alias name in Unfortunately my knowledge of this code base is non-existent and I would not dare hazard a guess at the fix for this. |
This works as expected, AFAIK. |
The unit tests are not failing. However, I thought that the purpose of this change was to be able to create a projection of all the properties of the specified entity . This is useful if you have multiple joins in the query and only want to retrieve e.g. the root entity without creating a sql select statement with every property of all the joined entities. When I run the unit test
This means that if the entity is not in cache, accessing any of the entities properties will cause an additional query to retrieve the rest of the properties. |
I also really miss the ability to eager fetch entities via QueryOver/Criteria API. Regarding unit tests - they check object loading that's already present in session. So tests don't really check that all properties are fetched. I updated tests to show the issue: Updated tests[Test]
public void UseRootProjection()
{
//NH-3435
using (ISession session = Sfi.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();
//Clear session to make sure entity is eager fetched
session.Clear();
Student g = session.CreateCriteria(typeof(Student))
.Add(Expression.IdEq(gavin.StudentNumber))
.SetFetchMode("Enrolments", FetchMode.Join)
.SetProjection(Projections.RootEntity())
.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()
{
//NH-3435
using (ISession session = Sfi.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();
//Clear session to make sure entity is eager fetched
session.Clear();
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<Student>("s"))
.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));
}
} |
Updated tests can also be found here (rebased with master): https://github.com/bahusoid/nhibernate-core/commits/GH948. |
Yayk! It's actually possible to eager fetch. It's just not exposed for some reasons via Projections helper methods. But it's possible via: I think SetLazy should be definitely exposed via additional parameter (or maybe Projections helper methods should simply return exact class instead of IProjection interface) |
If you wish to tackle this subject, PR your rebase and go ahead with required changes, it will then replace this PR. Update: I am not sure this PR was actually about eager fetching. If you change things about it, it may be better to do it as a separated PR. |
@fredericDelaporte No changes needed (except small changes to better expose already present functionality). This PR allows to retrieve entity as projection both ways (as lazy and eager fetched). Ok I will add separate tests for lazy and eager part and submit a new PR for this. |
Replaced by #1458 |
https://nhibernate.jira.com/browse/NH-3435 (#948)