2

I have the following table

tblChild

FatherCode ChildNumber Name

FatherCode and ChildNumber are the primary keys of the table.

Since something like this happens very often in this database (I have ZERO control over it), I created the following class for me to map the Id:

public class ComposedId {
   public virtual int FatherId {get;set;}
   public virtual int ChildId {get;set;}
   //More code implementing Equals and GetHashCode
}

Now, the mapping goes like this:

aMapper.Class<Child>(aClassMapper => aClassMapper.ComposedId(aComposedIdMapper =>
                {
                    aComposedIdMapper.Property(aChild => aChild.Id); //Id's implementation is: public virtual ComposedId Id {get;set;}
                }));

aMapper.Class<Child>(aClassMapper => aClassMapper.ComponentAsId(aChild => aChild.Id, aComponentAsIdMapper =>
    {
        aComponentAsIdMapper.Property(aComposedId => aComposedId.FatherId, aPropertyMapper => aPropertyMapper.Column("FatherCode"));
        aComponentAsIdMapper.Property(aComposedId => aComposedId.ChildId, aPropertyMapper => aPropertyMapper.Column("ChildNumber"));
    }));

But when I'm try to query the table, NHibernate tries to get the Id as a column.

I don't know what I'm doing wrong, and I tried a lot of ways to map this with this structure, but nothing works :(

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Tejo
  • 1,268
  • 11
  • 18
  • 1
    Have you tried commenting the first mapping? It looks like it's messing the second mapping statement. – Andre Calil Jul 06 '12 at 13:19
  • BTW, what mapping strategy is this? I've seen HBM and Fluent, but this one I don't recognize. – Andre Calil Jul 06 '12 at 14:17
  • This is Loquacious, if from NHibernate 3.3, and it's like their own Fluent. This is one of the problems.. is kind of a new thing, so there's isn't much on the internet – Tejo Jul 06 '12 at 15:12
  • It looks so... dirty. I like Fluent better. No way to change? – Andre Calil Jul 06 '12 at 15:42
  • 2
    I'd rather not, since this ways is native to NHibernate. And I didn't find it ugly(maybe the aMapper.Class thing is abit awkward, but this is my fault and not NHibernate's). Besides, we're not here to argue wich technology is better, I just have to make this work :) – Tejo Jul 06 '12 at 18:13
  • Not at all, it was just a random idea =) – Andre Calil Jul 06 '12 at 18:47

1 Answers1

2

The first line in your mapping is incorrect.

I used this, which is just a simplified version of your code:

mapper.Class<Child>(cm => cm.ComponentAsId(
    x => x.Id,
    caim =>
    {
        caim.Property(x => x.FatherId, pm => pm.Column("FatherCode"));
        caim.Property(x => x.ChildId, pm => pm.Column("ChildNumber"));
    }));

And it correctly generated this mapping (XML-serialized):

<composite-id class="ComposedId" name="Id">
  <key-property name="FatherId" column="FatherCode" />
  <key-property name="ChildId" column="ChildNumber" />
</composite-id>

...which in turn produces correct SQL.

You say in the comments that you tried without the first line, but you probably forgot to compile, deploy or restart a server when testing it.

As a side note, if you rename the properties of ComposedId to match the db and use ConventionModelMapper, you don't even have to map the Id manually.


To get the XML mapping I use this:

var mappingDocument = mapper.CompileMappingForAllExplicitlyAddedEntities();
new XmlSerializer(typeof(HbmMapping)).Serialize(Console.Out, mappingDocument);
Diego Mijelshon
  • 52,548
  • 16
  • 116
  • 154
  • The problem is that I want the ComposedId class to be a generic structure for these kind of situations, I'm gonna try this again and tell you the results. By the way, how do you see the xml generated by NHibernate? – Tejo Jul 07 '12 at 12:44
  • And another thing... would this work if ComposedId was ComposedId (in this case, it'd be a generic class that takes the types of it's two attributes. It's what i actually have here, i just omited for the sake of simplicity) – Tejo Jul 07 '12 at 15:26
  • See added block for XML serialization. It works just fine with a generic ComposedId; the XML is ugly because of the CLR syntax, but you don't have to deal with it so it's not a problem. – Diego Mijelshon Jul 07 '12 at 15:32
  • HOHO OH WOW! It actually worked. Maybe I forgot to clean something before trying. Thanks dude :) And thanks for the XML thing – Tejo Jul 09 '12 at 13:19
  • Man, actually it didn't work... i tried with Repository.GetAll().Count() and it ran fine, but when I use Repository.GetAll().ToList() it keeps complaining that ID doesn't exist :( – Tejo Jul 09 '12 at 13:48
  • Also tried taking out the generics from my ComposedId class(to make it like the example i posted) still same error. – Tejo Jul 09 '12 at 14:40
  • Ok, got it yo work... apparently you have to map the component first, and then you can use it as the Id, i've edited your aswer so I can accept it. Thanks for all the help :) – Tejo Jul 09 '12 at 17:37
  • @Tejo, your change generates exactly the same output. Please verify and post the XML with and without the change. – Diego Mijelshon Jul 09 '12 at 20:54
  • Yeah, so.. With the change, it generates the XML you posted, without it, NHibernate tries to map the properties to the ID field, that doesn't exist.. it probably is a bug – Tejo Jul 10 '12 at 16:11
  • There has to be something *else* that you are doing with the mapper to cause that. Maybe some convention... – Diego Mijelshon Jul 10 '12 at 16:43
  • This is a Special case, if my class has a ComposedId, I don`t use convention in them. I think it's probably a bug, dunno.. this can't be the default behavior, and i'm sure i'm not doing anything else :( – Tejo Jul 11 '12 at 00:08
  • This is not working when you have multiple classes, the ComposedId was shared between classes... any tip? – Rodolpho Brock Dec 18 '13 at 20:22