NHibernate - HBMs - Composite Key with foreign keys needs a fix

Posts   
 
    
rodri_ogri
User
Posts: 22
Joined: 05-Nov-2010
# Posted on: 14-Dec-2010 21:01:22   

[llbl GenPro v3.0, NHibernate 3.0, Oracle 11G] Hi, We have a table named "Son" with a composite primary key which has two foreign keys from its parent (the parent has two fields as its primary key) .

  • PK IdSon
  • PK (FK) Id1Parent
  • PK (FK) Id2Parent

When we map this to Nhibernate HBM file we have the following code generated:

<composite-id>
      <key-property name="IdSon" column="IdSon" access="field.camelcase-underscore" />
      <key-many-to-one name="Parent" column="Id1Parent" access="field.camelcase-
underscore"  />
      <key-many-to-one name="Parent" column="Id2Parent" access="field.camelcase-underscore"  />
</composite-id>

Well... as soon as I try to initialize my NHibernate SessionFactory, it throws a mapping exception telling me that there's a reference to Parent duplicated. Of course, because the mapping has mapped the same navigator twice.

the correct way to map it correctly must be (at least on NH 3) as follows:

<composite-id>
      <key-property name="IdSon" column="IdSon" access="field.camelcase-underscore" />
      <key-many-to-one name="Parent"  access="field.camelcase-underscore"  >
        <column name="Id1Parent" />
        <column name="Id2Parent" />
      </key-many-to-one>
</composite-id>

We had to change this generation on the template file (entityHbmMapping.lpt) using two collections. Now it works fine.

I hope you guys can fix this particular issue on the next releases.

best regards

Rodrigo

MTrinder
User
Posts: 1461
Joined: 08-Oct-2008
# Posted on: 14-Dec-2010 21:22:17   

Thanks for that - we'll take a look.

Matt

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 14-Dec-2010 22:30:58   

thanks Rodrigo. We thought we had covered all bases with the key-many-to-one stuff, as there's no documentation about this (at least we couldn't find proper docs on this) and NH users/team weren't helpful to fix this. (read: debating why this was even needed... disappointed )

We'll look into fixing this. What exactly did you change in the template?

Frans Bouma | Lead developer LLBLGen Pro
rodri_ogri
User
Posts: 22
Joined: 05-Nov-2010
# Posted on: 14-Dec-2010 22:50:11   

Otis wrote:

thanks Rodrigo. We thought we had covered all bases with the key-many-to-one stuff, as there's no documentation about this (at least we couldn't find proper docs on this) and NH users/team weren't helpful to fix this. (read: debating why this was even needed... disappointed )

We'll look into fixing this. What exactly did you change in the template?

Hi frans,

what I've done starts on line 44: COMPOSITE KEY FIELDS

I created a Dictionary with the following types:

Key: string -> NavigatorName Value: Dictionary<string,string> -> List of Fields

On the Fields dictionary: Key: string -> Field's Name Value: string -> typeConverterDeclaration field

I'm collecting all the composite fields and then I'm "rendering" with two foreach loops (for every dictionary)

The result: It renders well. The problem: I have render the fields on the proper order. So I must now add a Hashtable<string, object> to collect the key-property and key-many-to-one fields and then render them in the correct order. (If they are in an incorrect order, the sql is not well formed)

best regards

Rodrigo

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 15-Dec-2010 11:26:48   

Thanks. You can determine the order of the Fk fields from the relationship, by obtaining the pk fields from the relationship, then sorting them alphabetically, then loop over them and obtain each fk field related to the current pk field, and emit that.

I do recall something like this which failed in NH 2.1, and I think it was indeed with invalid sql due to a wrong order (but we didn't know that was the case) and we gave up as we couldn't get anyone confirm how to write the proper xml (no docs, no-one knew how to do it). The xsd for the .hbm files suggested what you wrote, but we couldn't get it to work. Apparently we were very close wink .

The current code was a result of a bugfix, so it was never correct for the situation you described.

We'll fix this for the next build.

Btw, you're still using a trial license?

Frans Bouma | Lead developer LLBLGen Pro
rodri_ogri
User
Posts: 22
Joined: 05-Nov-2010
# Posted on: 15-Dec-2010 15:17:58   

Hi,

I don't know if we completly fixed this but now works fine when we render the keys as the collection comes, I mean, we are assuming that the foreach loop is bringing key collections in the proper order for each entity.

regarding the trial licence, yes, I'm using the trial licence which ends today. I'm affraid that "the man" has not purchased the licence due to the logistics of the project (we were supposed to have it two weeks ago). I hope we have it this week.

best regards.

Rodrigo

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 15-Dec-2010 15:55:38   

rodri_ogri wrote:

Hi, I don't know if we completly fixed this but now works fine when we render the keys as the collection comes, I mean, we are assuming that the foreach loop is bringing key collections in the proper order for each entity.

Yes, it needs a check whether there are 1 or more fields, and if there are 2 or more, the keys should be emitted with <column> elements instead. This is a bit of a pain, but I think we have this also in another template (for ef) so it's not that hard to make this work I think. We hope to have an update for this tomorow (thursday).

regarding the trial licence, yes, I'm using the trial licence which ends today. I'm affraid that "the man" has not purchased the licence due to the logistics of the project (we were supposed to have it two weeks ago). I hope we have it this week.

Thanks, and no problem simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 16-Dec-2010 15:49:55   

There's indeed a problem, although it doesn't occur always. Say you have this: PkSide: F1, A, B FkSide: Z, Y (to A), X (to F1)*, B

This gives a problem. Not only are the fields of FkSide sorted as: X, Y, Z but the pk of PkSide is sorted as: A, F1.

So the FkSide pk can't be sorted, well, not the FK fields. They have to be sorted according to the PK Side's pk field order. Which is A, F1. , So, FkSide's PK should be: Y, X, Z, or at least have Y and X in that order, as they point to the fields in that order, but that reference is never stored in NH mapping files.

Now, the problem gets bigger when an entity Foo points to FkSide's PK. For emitting Foo's pk fields, we can't rely on FkSide's order, as that's determined from PkSide's order. We can't look at some cache, because it might be PkSide hasn't been processed yet. disappointed

It's a problem as the fields have to be grouped together but the ordering based on name might dictate differently. (in the case of Bar: A, B, C, D* where A and D are together a compound FK to a different entity.

disappointed I can't express how much I loath the system NHibernate uses for mapping this. It's solved if they allow to define the many-to-one relationship like any other relationship and thus define the PK as normal too. Because they're combined (for no reason), it's extremely complicated all of a sudden.

From what I read in your posts, you use a cache for the PK field order per entity, correct? This will indeed work till the PK side isn't emitted yet. Which can be the case, the entities are processed alphabetically.

We'll see if we can find a different ordering scheme which always works and groups fk fields together...

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 16-Dec-2010 16:06:32   

It can be solved with a topological sort of the complete entity model, then calculate for each entity the Pk field order properly, which is then stored in the cache. The first entity processed will trigger this action: if the cache item doesn't exist, it's created, otherwise it's simply used.

For every entity the cache is then used to emit the pk fields. This is 100% solid, as topological sorting guarantees the order to be correct, so pk side is always processed before fk side so you can always determine the fk side's pk field order this way. (if there's a cycle in the model, ignore it)

Our code already has the logic to deal with this, so the hard part is determining the field order. We won't be able to finish this today, so it'll be tomorrow.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 17-Dec-2010 13:20:33   

Almost there. It emits proper hbm now, have to port the fluentNH code as well, and also update the relationship emitting code so it takes into account the pk order, and some cleaning up in the template code, as it has some duplicate code now around the <key-many-to-one emitter.

Frans Bouma | Lead developer LLBLGen Pro
rodri_ogri
User
Posts: 22
Joined: 05-Nov-2010
# Posted on: 17-Dec-2010 14:12:24   

Otis wrote:

Almost there. It emits proper hbm now, have to port the fluentNH code as well, and also update the relationship emitting code so it takes into account the pk order, and some cleaning up in the template code, as it has some duplicate code now around the <key-many-to-one emitter.

Great job!

regards.

rodrigo

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 17-Dec-2010 14:56:50   

simple_smile

There's another problem, FK fields which are in a compound PK get an Fk field emitted. This isn't how NHibernate works. These have to go too.

I have a miserable model defined now, which contains all the mess one can throw at this, should be doable to get everything ironed out with this today simple_smile

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 17-Dec-2010 15:41:57   

Everything works, FluentNH left...

(edit) fixed. Buildtests on other projects pending, but I don't expect problems. Will release a new build with the new templates in an hour or so.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39899
Joined: 17-Aug-2003
# Posted on: 17-Dec-2010 18:20:38   

Fixed. New build is now available which has the updated templates. As there were more than 1, I uploaded a new build instead of attaching the templates here. Hopefully this covers all bases. simple_smile

Frans Bouma | Lead developer LLBLGen Pro