3
votes

I am learning to use fluent nhibernate and am having trouble understanding how to create my mappings. I have a table that has a multi-column primary key, but I can't get it to map correctly. I have the following fluent mapping -

public class MyEntityMappingOverride : IAutoMappingOverride<MyEntity>
    {
        public void Override(AutoMapping<MyEntity> mapping)
        {
            mapping.CompositeId()
                .KeyProperty(x => x.Id_1, "Id_1")
                .KeyProperty(x => x.Id_2, "Id_2");

            mapping.References(x => x.otherEntity)
                .Column("JoinColumn");

            // Commented out to attempt to map to another entity on multiple columns
            //mapping.HasMany(x => x.thirdEntit)
            //    .KeyColumns.Add("thirdId_1", "thirdId_2")
            //    .Cascade.All();



        }
    }

The problem that I am having is the composite id doesn't seem to be working.

Here is a snippet from the produced mapping file -

<id name="Id" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
      <column name="Id" />
      <generator class="identity" />
    </id>

I then get an error that column (id) is not found in any table in the query.

Am I wrong in thinking that my mapping code will produce the correct composite ID? Am I missing something or doing something incorrectly?

1
Perhaps an NHibernate Automapping convention is overriding your fluent mapping?rebelliard
Perhaps that is the issue - I will have to look into that. NOTE - I have adapted some pieces from SharpArchitecture for mapping my domain. I just looked, and there may be something happening there. I will check it out.czuroski
Sharp? It's definitely that. I had the same problem, and I had to modify the primary key convention so it ignored my specific type.rebelliard
Have you made sure to tell the Automapper about your overrides? Something like AutoMap...UseOverridesFromAssemblyOf<MyEntityMappingOverride>()Vadim

1 Answers

3
votes

It's recommended (and I've had lots of success with) that if you're doing CompositeKeys you use an ID object as per:

NHibernate and Composite Keys

In your case you'd create a new class...

[Serializable]
public MyEntityIdentifier
{
   public virtual TYPE Id_1;
   public virtual TYPE Id_2;

   // You need to override Equals(MyEntityIdentifier), Equals(object obj) and GetHashCode()
}

Then your mapping becomes

public class MyEntityMappingOverride : IAutoMappingOverride<MyEntity>
{
        public void Override(AutoMapping<MyEntity> mapping)
        {
            mapping.CompositeId()
                .ComponentCompositeIdentifier(x => x.MyEntityIdentifier)
                .KeyProperty(x => x.MyEntityIdentifier.Id_1, Id_1, "Id_1")
                .KeyProperty(x => x.MyEntityIdentifier.Id_2, "Id_2");

            // snip
        }
}

And your class goes from having two properties (Id_1 & Id_2) to just having a MyEntityIdentifier.

Then you use your MyEntityIdentifier where required to load..

MyEntity entity = Session.Load<MyEntity>(new MyEntityIdentifier { Id_1 = Whatever, Id_2 = Whatever });

And also if you have ANY control over this database I would STRONGLY recommend not using CompositeKeys. While NHibernate will definitely handle them they do come with a bit of additional mental complexity and problems.