Search code examples
nhibernatefluent-nhibernatenhibernate-mappingusertype

NHibernate: Access another column's value in a UserType


I'm trying to make a UserType that hashes a value. The issue I'm having is getting access to the Salt that sits in the same table.

  void IUserType.NullSafeSet(IDbCommand cmd, object value, int index)
    {
        object paramVal = DBNull.Value;

        if (!String.IsNullOrEmpty((string)value))
        {
            paramVal = ComputeHash((string)value, saltBytes?);
        }

        IDataParameter parameter = (IDataParameter)cmd.Parameters[index];
        parameter.Value = paramVal;
    }

I am uncertain on how to reliably access a database column of the same table to get the salt that was set.

I could do something like this to access the salt column:

byte[] saltValueBeingInsertedIntoDB = (IDataParameter)cmd.Parameters[1].Value;

It just seems so fragile to access it via index, as the order could change. I'd love it if I could access it off of the column name, but the column name (SoureColumn) is never populated.

How can I reliably access the Salt that exists in cmd.Parameters? Or is there a better way? (I have full control to change whatever is needed, except the NHibernate version).

Note: If I'm setting the salt somewhere else, it may make sense for me to also hash the value in that place, rather than using a UserType.

NHiberate 2.1.2.4000 Fluent NHibernate 1.1.0.685


Solution

  • To solve my issue, I chose not to use the UserType.

    Instead, I create a static instance of my Ciphering service on the object(s) that need it, and then use a helper property to get/set the encrypted value. This works great for me.

    public class Consumer
    {
        static Consumer()
        {
            CipherConsumerSsnService = new CipherConsumerSsnService();
        }
    
        public static ICipherConsumerSsnService CipherConsumerSsnService { get; set; }
    
        public virtual long ID { get; private set; }
        public virtual byte[] SSN { get; protected set; }
    
        public virtual string GetDecryptedSsnOrSetSsnValueAndEncryptIt
        {
            get
            {
                return SSN != null ? CipherConsumerSsnService.Decrypt(SSN) : null;
            }
            set
            {
                SSN = value != null ? CipherConsumerSsnService.Encrypt(value) : null;
            }
        }
    }
    

    Note that this example doesn't use a salt, but you should!