title: NHibernate - map interface or abstract component with mapping-by-code/Conformist
body: <p>This question is related to <a href="https://stackoverflow.com/questions/1548839/mapping-interface-or-abstract-class-component">Mapping interface or abstract class component</a>
  I'm also trying to map a component declared as an interface, but I'm using the built-in mapping-by-code/Conformist approach.</p>
  
  <p>Let's say I have an entity <code>Login</code> (C#):</p>
  
  <pre><code>public class Login
  {
      public virtual int Id { get; set; }
      public virtual string UserName { get; set; }
      public virtual IPassword Password { get; set; }
  }
  </code></pre>
  
  <p>I want to abstract away how the password is stored, so I've defined a simple interface <code>IPassword</code></p>
  
  <pre><code>public interface IPassword
  {
      bool Matches(string password);
  }
  </code></pre>
  
  <p>An example implementation is <code>HashedPassword</code>:</p>
  
  <pre><code>public class HashedPassword : IPassword
  {
      public virtual string Hash { get; set; }
      public virtual string Salt { get; set; }
  
      public virtual bool Matches(string password){ /* [snip] */ }
  }
  </code></pre>
  
  <p>I want to map <code>Login.Password</code> as a component rather than a many-to-one or one-to-one relation. Using XML I'd map it like this:</p>
  
  <pre><code>&lt;?xml version="1.0"?&gt;
  &lt;hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="..." namespace="..."&gt;
    &lt;class name="Login"&gt;
      &lt;id name="Id"&gt;...&lt;/id&gt;
      &lt;property name="UserName" .../&gt;
      &lt;component name="Password" class="HashedPassword"&gt;
        &lt;property name="Hash" not-null="true" length="32"/&gt;
        &lt;property name="Salt" not-null="true" length="32"/&gt;
      &lt;/component&gt;
    &lt;/class&gt;
  &lt;/hibernate-mapping&gt;
  </code></pre>
  
  <p>This works as expected. </p>
  
  <p>Here's my attempt to map it using NHibernate's built-in mapping-by-code facilities:</p>
  
  <pre><code>public class LoginMapping : ClassMapping&lt;Login&gt;
  {
      public LoginMapping()
      {
          Id(x =&gt; x.Id, map =&gt; map.Generator(Generators.HighLow));
          Property(x =&gt; x.UserName, map =&gt; map.Length(32));
          Component(x =&gt; x.Password, comp =&gt;
              {
                  comp.Class&lt;HashedPassword&gt;();
                  comp.Property("Salt", map =&gt; map.Length(32));
                  comp.Property("Hash", map =&gt; map.Length(32));
              });
      }
  }
  </code></pre>
  
  <p>When I use this mapping I get the following exception:</p>
  
  <blockquote>
    <p>NHibernate.MappingException: Member not found. The member 'Salt' does not exists in type IPassword</p>
  </blockquote>
  
  <p>While it's true that Salt isn't a member of <code>IPassword</code>, it <em>is</em> a member of the class that I set with <code>comp.Class&lt;HashedPassword&gt;()</code></p>
  
  <p>Do you know how I can map this scenario without getting the exception?</p>
  
  <hr>
  
  <p>So far there I haven't found a solution to the question itself. There are two work-arounds at the moment:</p>
  
  <ol>
  <li><p>Resort to XML mapping or FluentNHibernate. This could probably done for the "problematic" mappings only.</p></li>
  <li><p>Instead of a component, use a user type. This is what I'm doing right now. The type in my case (the hashed password) is immutable and can be stored as a single column, so the user type is fairly simple. </p></li>
  </ol>
  
  <p>Here's the user type I'm currently using (for sake of completion). I use PBKDF2 to create secure hashes. Note that in my application all data (salt, hash and PBKDF2 iteration count) is stored in one property (simply named <code>Hash</code>) of the HashedPassword.</p>
  
  <pre><code>public abstract class ImmutableValue&lt;T&gt; : IUserType where T : class
  {
      public abstract SqlType[] SqlTypes { get; }
  
      public virtual Type ReturnedType
      {
          get { return typeof (T); }
      }
  
      public bool IsMutable
      {
          get { return false; }
      }
  
      bool IUserType.Equals(object x, object y)
      {
          return InternalEquals(x, y);
      }
  
      protected virtual bool InternalEquals(object x, object y)
      {
          return Equals(x, y);
      }
  
      public virtual int GetHashCode(object x)
      {
          return x == null ? 0 : x.GetHashCode();
      }
  
      public virtual object NullSafeGet(IDataReader rs, string[] names, object owner)
      {
          return Load(rs, names, owner);
      }
  
      protected abstract T Load(IDataReader rs, string[] names, object owner);
  
      public virtual void NullSafeSet(IDbCommand cmd, object value, int index)
      {
          Save(cmd, (T) value, index);
      }
  
      protected abstract void Save(IDbCommand cmd, T value, int index);
  
      public virtual object DeepCopy(object value)
      {
          return value;
      }
  
      public virtual object Replace(object original, object target, object owner)
      {
          return original;
      }
  
      public virtual object Assemble(object cached, object owner)
      {
          return cached;
      }
  
      public virtual object Disassemble(object value)
      {
          return value;
      }
  
      protected void SetParameter(IDbCommand cmd, int index, object value)
      {
          var parameter = (IDataParameter) cmd.Parameters[index];
          var parameterValue = value ?? DBNull.Value;
          parameter.Value = parameterValue;
      }
  }
  
  public class HashedPasswordType : ImmutableValue&lt;HashedPassword&gt;
  {
      public override SqlType[] SqlTypes
      {
          get { return new SqlType[] {SqlTypeFactory.GetString(HashedPassword.ContentLength)}; }
      }
  
      protected override HashedPassword Load(IDataReader rs, string[] names, object owner)
      {
          var str = NHibernateUtil.String.NullSafeGet(rs, names[0]) as string;
          return HashedPassword.FromContent(str);
      }
  
      protected override void Save(IDbCommand cmd, HashedPassword value, int index)
      {
          SetParameter(cmd, index, value == null ? null : value.Hash);
      }
  }
  </code></pre>
  
  <p>The required mapping is then comparatively simple:</p>
  
  <pre><code>Property(x =&gt; x.Password, map =&gt;
      {
          map.Type&lt;HashedPasswordType&gt;();
          map.NotNullable(true);
      });
  </code></pre>