title: Problem mapping composite key with NHibernate (column already been added)
body: <p>new to NHibernate (and Hibernate for that matter),  and I'm struggling with a composite key problem.  Here's a simplified version of part of the database design.</p>
  
  <pre><code>  table_a
   +---------------------+
   | * a_id varcha (10)  |                   table_z
   |   label varchar(50) |                 +----------------------+
   |                     +&lt;----------------+ * a_id varchar(10)   |
   +---------------------+      +----------| * b_id varchar(10)   |
                                |   +------+ * c_id varchar(10)   |
    table_b                     |   |      |   name varchar(100)  |
   +---------------------+      |   |      |                      |
   | * b_id varcha (10)  |      |   |      +----------------------+
   |   label varchar(50) &lt;------+   |
   |                     |          |
   +---------------------+          |
                                    |
    table_c                         |
   +---------------------+          |
   | * c_id varcha (10)  &lt;----------+
   |   label varchar(50) |
   |                     |
   +---------------------+
  </code></pre>
  
  <p>The key element here is table_z primary key is a composite of the 3 primary keys of table a,b,c (so, it controls unique combinations of a,b and c).  They are also individually FK to table_a, table_b and table_c.</p>
  
  <p>Now, beyond database design considerations, is there a way to map this into NHibernate.  My attemps result in a stack trace complaining that "ArgumentException: The column 'a_id' has already been added in this SQL builder".   Googling around told me that the issue is that I use the same field name on both end of the join.  I'm surprised it's even an issue - or I totally misunderstand the problem..</p>
  
  <p>Here's the DDL (Postgresql)</p>
  
  <pre><code>CREATE TABLE test.table_a(
  a_id varchar(10) primary key,
  label varchar(50)
  );
  
  CREATE TABLE test.table_b(
  b_id varchar(10) primary key,
  label varchar(50)
  );
  
  
  CREATE TABLE test.table_c(
  c_id varchar(10) primary key,
  label varchar(50)
  );
  
  CREATE TABLE test.table_z(
  a_id varchar(10),
  b_id varchar(10),
  c_id varchar(10),
  name varchar(100)
  );
  
  -- add combined primary key on table_z
  ALTER TABLE test.table_z ADD CONSTRAINT pk_z_combined
      PRIMARY KEY (a_id,b_id,c_id)
  ;
  
  -- FK
  
  ALTER TABLE test.table_z ADD CONSTRAINT FK_to_a
      FOREIGN KEY (a_id) REFERENCES test.table_a (a_id) ON DELETE No Action ON UPDATE No Action;
  
  ALTER TABLE test.table_z ADD CONSTRAINT FK_to_b
      FOREIGN KEY (b_id) REFERENCES test.table_b (b_id) ON DELETE No Action ON UPDATE No Action;
  
      ALTER TABLE test.table_z ADD CONSTRAINT FK_to_c
      FOREIGN KEY (c_id) REFERENCES test.table_c (c_id) ON DELETE No Action ON UPDATE No Action;
  </code></pre>
  
  <p>and here's the Fluent Hibernate C# code</p>
  
  <pre><code>
  using FluentNHibernate.Mapping;
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  
  namespace pm
  {
  
      class TestAMapping : ClassMap&lt;TestA&gt;
      {
          public TestAMapping()
          {
              Table("test.table_a");
              Id(x =&gt; x.Id, "a_id");
              Map(x =&gt; x.Label, "label");
          }
      }
  
      class TestBMapping : ClassMap&lt;TestB&gt;
      {
          public TestBMapping()
          {
              Table("test.table_b");
              Id(x =&gt; x.Id, "b_id");
              Map(x =&gt; x.Label, "label");
          }
      }
  
      class TestCMapping : ClassMap&lt;TestC&gt;
      {
          public TestCMapping()
          {
              Table("test.table_c");
              Id(x =&gt; x.Id, "c_id");
              Map(x =&gt; x.Label, "label");
          }
      }
  
      class TestZMapping : ClassMap&lt;TestZ&gt;
      {
          public TestZMapping()
          {
              Table("test.table_z");
              CompositeId()
                  .KeyProperty(x =&gt; x.Aid, "a_id")
                  .KeyProperty(x =&gt; x.Bid, "b_id")
                  .KeyProperty(x =&gt; x.Cid, "c_id");
              Map(x =&gt; x.Name, "name");
              References(x =&gt; x.TestAObj).Column("a_id");
              References(x =&gt; x.TestBObj).Column("b_id");
              References(x =&gt; x.TestCObj).Column("c_id");
  
          }
      }
  
  
      class TestA
      {
          public virtual string Id { get; set; }
          public virtual string Label { get; set; }
  
      }
      class TestB
      {
          public virtual string Id { get; set; }
          public virtual string Label { get; set; }
  
      }
      class TestC
      {
          public virtual string Id { get; set; }
          public virtual string Label { get; set; }
  
      }
  
      class TestZ
      {
          public virtual string Aid { get; set; }
          public virtual string Bid { get; set; }
          public virtual string Cid { get; set; }
          public virtual string Name { get; set; }
          public virtual TestA TestAObj { get; set; }
          public virtual TestB TestBObj { get; set; }
          public virtual TestC TestCObj { get; set; }
  
          // https://stackoverflow.com/a/7919012/8691687
          public override bool Equals(object obj)
          {
              var other = obj as TestZ;
  
              if (ReferenceEquals(null, other)) return false;
              if (ReferenceEquals(this, other)) return true;
  
              return this.Aid == other.Aid &amp;&amp;
                  this.Bid == other.Bid &amp;&amp; this.Cid == other.Cid;
          }
  
          public override int GetHashCode()
          {
              unchecked
              {
                  int hash = GetType().GetHashCode();
                  hash = (hash * 31) ^ Aid.GetHashCode();
                  hash = (hash * 31) ^ Bid.GetHashCode();
                  hash = (hash * 31) ^ Cid.GetHashCode();
  
                  return hash;
              }
          }
      }
  
  }
  
  </code></pre>
  
  <p>Relevant stack trace</p>
  
  <pre><code>
  FluentNHibernate.Cfg.FluentConfigurationException
    HResult=0x80131500
    Message=An invalid or incomplete configuration was used while creating a SessionFactory. Check PotentialReasons collection, and InnerException for more detail.
  
  
    Source=FluentNHibernate
    StackTrace:
     at FluentNHibernate.Cfg.FluentConfiguration.BuildSessionFactory()
     at pm.dal.DAL.CreateSessionFactory(String connectionString) in C:\Users\Laptop\source\repos\pm\dal\DAL.cs:line 49
     at pm.dal.DAL..ctor(String connectionString) in C:\Users\Laptop\source\repos\pm\dal\DAL.cs:line 41
     at pm.Manager.Manager.Connect(String connectionString) in C:\Users\Laptop\source\repos\pm\Manager\Manager.cs:line 102
    (blah...)
  
  Inner Exception 1:
  MappingException: Unable to build the insert statement for class pm.TestZ: a failure occured when adding the Id of the class
  
  Inner Exception 2:
  ArgumentException: The column 'a_id' has already been added in this SQL builder
  Parameter name: columnName
  </code></pre>
  
  <p>Can anyone tell me where I sinned..</p>
  
  <p>Thanks a heap</p>