views:

1261

answers:

2

I'm having trouble with something that (I think) should be simple, but can't find any clear info.

In the scenario where I have three tables, describing a domain where a person can have more than one job:

Person - has PersonId, Name
Job - has JobId, JobName
PersonJob - has PersonId, JobId, YearsOfEmployment

Note: In my object model, I have entities representing each table. I have that third entity to represent the Person/Job relationship since there is useful metadata there (YearsOfEmployment) and is not just a simple join table.

So, if I knew the PersonId and the JobId, is there a simple way for me to use the session and return an object matching those Ids?

Or, put a different way, since I already know the primary keys is there a brain-dead, simple way I can turn the SQL "SELECT YearsOfEmployment FROM PersonJob WHERE PersonId=1 AND JobId=1" into something like:

var keys = new {PersonId=1, JobId=2};
PersonJob obj = Session.Get<PersonJob>(keys);

BTW: maps would look something like this:

<class name="Person" table="dbo.Person" lazy="true">
  <id name="PersonId">
    <generator class="native"/>
  </id>
  <property name="Name"/>
</class>
<class name="Job" table="dbo.Job" lazy="true">
  <id name="JobId">
    <generator class="native"/>
  </id>
  <property name="JobName"/>
</class>
<class name="PersonJob" table="dbo.PersonJob" lazy="true">
  <composite-id>
    <key-property name="PersonId"></key-property>
    <key-property name="JobId"></key-property>
  </composite-id>
  <property name="YearsOfEmployment"/>
</class>
+6  A: 

Well, I answered my own question. I think posting your problem is almost as cathartic as talking it out with someone. If I were to make the composite-id of PersonJob a component or class, i.e.

<class name="PersonJob" table="dbo.PersonJob" lazy="true">
    <composite-id name="PersonJobKey" class="PersonJobKey">
      <key-property name="PersonId"></key-property>
      <key-property name="JobId"></key-property>
    </composite-id>
</class>

Then I can simply do this:

PersonJobKey key = new PersonJobKey() { PersonId = 1, JobId = 1 };  
PersonJob obj = Session.Get<PersonJob>(key);  
int yearsOfEmployment = obj.YearsOfEmployment;

cool. hope this helps anyone else figuring this out ...

joshua.ewer
Might be worth adding the whole PersonJobKey class as I am currently trying to find out what class I need to override.
LnDCobra
+2  A: 

Thanks for posting the answer above, I was looking at it against an object I have mapped where the composite key doesn't have a name or class. When I tried making a class to represent the composite key, it changed the way that the object behaved when used by other code. Also I wanted to write something like;

Session.Get<SalesRepArea>(new { AreaCode = "ACode", RegionCode = "RCode"});

I found that nHibernate couldn't make much sense of the anonymous object, but I did realise that I don't need a name for my composite key, or a class type. What the nHibernate Get method is after, in fact, is a transient object so that it can get it's equivalent object from the database (must be why you have to override the equals method in your C# class to get the composite key to work). So for the following map

<class name="SalesRepArea">
   <composite-id>
      <key-property 
         name="AreaCode" column="AreaCode" type="String" length="12" />
      <key-property 
         name="RegionCode" column="RegionCode" type="String" length="12" />
   </composite-id>

I write a bit less code, and dispense with the object representing the key to get

SalesRepArea myArea = Session.Get<SalesRepArea>(
   new SalesRepArea()
   { 
      AreaCode = "ACode", 
      RegionCode = "RCode" 
   }
);

I'm not saying that the named key method is bad, less code is not always better, it's just to show that Hibernate is looking for the object that the key is in to get the specific object from the database.

If I've got it wrong please let me know, but I hope this helps, as I was having a bit of trouble with this.

Thanks,

Mark

Mark Dickinson