views:

743

answers:

1

Client has a Report, Configuration etc properties. A client can have only one of each. Also, each report can belong to only one Client. This is in a way a one-to-one relationship. Therefore my Report table has a foreignkey column clientID. Same for the Configuration and other tables.

Now as per the definition of one-to-one that i read on the nhibernate site, it means that both the primary keys of Report and Client should be the same. Lets just assume that I cannot implement it that way. Hence to simulate the structure that I have in the database, I have the following mappings:

ReportMap

References(x => x.Client, "clientID").Unique().Not.Nullable();

ClientMap

HasOne(x => x.Report).PropertyRef(x => x.Client).LazyLoad().Cascade.SaveUpdate();

Now the problem I am facing is that when I query for a Client, NHibernate is also generating queries to get the Report, Configuration etc... Also, depending on whether I use Criteria or HQL, the generated queries vary wildly.

var client = session.CreateQuery("from Client as c where c.Id = :clientId")
                    .SetParameter("clientId", 1L)
                    .UniqueResult<Client>();

generates one query for the client followed by one query for each property that I mapped as HasOne. ie 2 more queries. One for Report and one for Configuration. HQL generates a total of 3 queries.

However, if I use the Load method or Criteria, it generates one query which joins all the concerned tables.

Despite mapping these collections to be lazy loaded, why is NHibernate fetching them? I really only want information from the Client table.

Whats the logical explanation to this?

From the Nhibernate documentaion on fetching strategies, i understand that single associations are lazy proxy fetched. and that the default fetch strategy of select is executed only when the association is accessed. In my case i am not accessing the association. I am simply reading properties that belong to the Client.

All this is so confusing...

Edit1: I have mapped my one to one relation as mentioned in the nhibernate documentation. http://nhforge.org/doc/nh/en/index.html#mapping-declaration-onetoone

There are two varieties of one-to-one association:

* primary key associations
* unique foreign key associations

Alternatively, a foreign key with a unique constraint, from Employee to Person, may be > expressed as:

<many-to-one name="Person" class="Person" column="PERSON_ID" unique="true"/>

And this association may be made bidirectional by adding the following to the Person >mapping:

<one-to-one name="Employee" class="Employee" property-ref="Person"/>

So technically as i understand, i am not doing anything wrong. This scenario is supposed to be supported by nhibernate.

+1  A: 

I'm not sure what the problem is with your query, but I suggest you change your mapping. You have is a one-to-many relationship between Client-Report and a business rule that a client can have only one report. You should map it as such. The reports collection can be mapped as a private member and you can expose a Report property on Client to enforce the business rule. I expect that mapping it this way will resolve your query problem.

You could also map it in the other direction witht Client on the many side if that makes more sense.

Jamie Ide
Ideally i would like to map the reports as Component or a value object. But i have an existing database and i cannot change that. Your suggestion aint bad. I implemented it and it seems to work the way i want. Though, i would still appreciate a proper solution. Or atleast an explanation of what is going wrong. I dont know if i should post this to the nhibernate-users list. I will wait for a couple of days here first.
Amith George
Components are used for fields that are in the same table as the containing type. For example, you might have an Address component on a Company class to map Street, City, and State fields in your table. I think the proper solution was to change your mapping -- you were misusing one-to-one mapping and the different fetch strategies were a results of that.
Jamie Ide
Regarding components, thats what i meant. Since i know for a fact that a Client will always have only 1 Report, i can technically collapse the two tables into one. For certain reasons we didnt do that. I guess one of them being that the Client table would have ended up with lots and lots of columns. not all of which we always need. Stuff like Report are only needed in a particular screen. Anyway, as i said your proposed solution works out well. But i feel its more of a work around than a solution.
Amith George