0

I have two objects, Case and Note. A Case can have gobs of Notes, like, in the thousands. We are trying to load them asynchronously, in batches, and stream them to the UI so there is no delay waiting for them all to load.

The class/mappings are

public class Case
{
        public virtual IList<Note> Notes { get; protected set; }
}

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="SCMS.TAMS.BusinessEntities" namespace="SCMS.TAMS.BusinessEntities">
    <class name="Case" table="Cases">
        <bag name="Notes" inverse="true" cascade="all" lazy="true">
            <key column="CaseID" />
            <one-to-many class="Note" />
        </bag>
    </class>
</hibernate-mapping>

public class Note
{
    public virtual Case Case {get; set;}
    public virtual long CaseId {get; set;}
}

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="SCMS.TAMS.BusinessEntities" namespace="SCMS.TAMS.BusinessEntities" default-lazy="true">
    <class name="Note" table="CaseNotes">
        <many-to-one name="Case" column="CaseID"/>
        <property name="CaseId" column="CaseID" />
    </class>
</hibernate-mapping>

Now, when I call

NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Skip(0).Take(10).ToList();

to load the first 10 Notes for Case 123, the thing loads the Case object, which takes about 30 seconds because there's lots of other things on it, and other logic when it gets loaded, etc., none of which I need/want at this time. All I want/need are the 10 Notes.

I've tried all sorts of variations on this mapping and none of them have worked. What am I doing wrong here?

2 Answers 2

1

How are you using this query? is it some thing for the UI? liking showing in a grid or something? or are you performing business logic in a component?

Either way you want to project into another object. Your query right now returns a list of notes which is then going to load that parent object per the mappings.

So if you are using this query to send the information to the UI of an asp.net mvc application, project directly into your view model

NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Select(n => new SomeViewModel { Prop1 = n.Prop1, Prop2 = n.Prop2 ...}).Skip(0).Take(10).ToList();

or create an anonymous object

NHibernateSession.Query<Note>().Where(n => n.CaseId == 123).Select n => new { n.Prop1, n.Prop2, ...}).Skip(0).Take(10).ToList();

This will keep the parent object from loading. It also has the added benefit that you are only querying the information you need because the query be limited to the data you are projecting.

Sign up to request clarification or add additional context in comments.

1 Comment

I was hoping for a different solution, but this one at least works and validates my thoughts.
0

Important to know is that if all above is true...

this is the real mapping (which is not it is just an obvious extract)

<class name="Note" table="CaseNotes">
    <many-to-one name="Case" column="CaseID"/>
    ...

this is the class (again extract without ID)

public class Note
{
    public virtual Case Case {get; set;}
    public virtual long CaseId {get; set;}
}

and that would be a UNIT TEST statement to load notes:

var list = NHibernateSession
  .Query<Note>()
  .Where(n => n.CaseId == 123)
  .Skip(0).Take(10)
  .ToList();

then NHibernate will NEVER load the Case object. Never. Because:

NHibernate is lazy, just live with it

The reason, the trigger to load related reference (Case property) must be something explicit.

Mostly:

there is usage of the Case object somewhere. E.g. in override of the GetHashCode() the Case.ID is used

Or:

there is a serialization or DTO conversion which does touch the Case property

In those case, NHibernate must load that...

So, create few unit tests with basic queries and assure that your the is really as shown above. Then it will work as expected

2 Comments

That's my actual code/mapping. I removed [italic](all) references to Note.Case, verifying by commenting out the Case object in my Note and it still built. We have gobs of (IMO unnecessary) interceptors and whatnot in our repository, there is a chance something there could be accessing the Case in Note but I commented out what I could find by stepping into with the debugger, and it's still loading the Case.
Look, my answer really is about solution. For example - these interceptors could touch your Case reference and that will cause its load from DB. I am simply trying to tell you, that by default NHibernate will do what you expect... ATTENTION, please, if you use debug.. you are in fact forcing NHibernate to load.. all the stuff you observe. So, debug could be causing it...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.