Overloading ORM Implicit Get and Set Methods

This is something I just ran into with ColdFusion 9's ORM implementation, that thankfully Rupesh got back to me very fast on, otherwise, I probably would have been confused for quite a while.

I
needed to overwrite a get and set value in a CFC I was creating.  We
will say for arguments sake I was hashing a password on a User object
(even though I was doing something completely different), like so:


component output="false" persistent="true"
{
    property name="userid" fieldtype="id" ormtype="int" generator="identity" hint="primary key";
    property name="name" type="string" notnull="true" length="200" hint="The user's name";
    property name="password" type="string" length="200" hint="The user's password";

    public void function setPassword(String password)
    {
        instance.password = hash(arguments.password);
    }

    public String function getPassword()
    {
        return instance.password;
    }
}

This is how I would usually have written my Components, storing my data in variables.instance, so they wouldn't overlap with any of the data stored in my variables scope.

What I couldn't understand was, my password would keep getting stored in my database as NULL, even though I had explicitly set it.

Thankfully Rupesh explained that when the ColdFusion ORM retrieves and populates data in an ORM managed CFC, it directly accesses the variables scope in the CFC.  So in the above instance, the ORM was finding no data for the password, and interpreting that to mean that I wanted to insert that as NULL into my database.

Therefore,  to get my code to work was to store my data in the variables scope, like so:


component output="false" persistent="true"
{
    property name="userid" fieldtype="id" ormtype="int" generator="identity" hint="primary key";
    property name="name" type="string" notnull="true" length="200" hint="The user's name";
    property name="password" type="string" length="200" hint="The user's password";

    public void function setPassword(String password)
    {
        variables.password = hash(arguments.password);
    }

    public String function getPassword()
    {
        return variables.password;
    }
}


This way the ORM can find exactly what it is looking for, and I can manipulate my data the way I want.

The fact that the ORM integration works this way is actually a very good thing, as it means that my password above doesn't get hash'd
over and over again, but it is something we all should be aware of when
you want to overwrite the implicit get and set functions that get
generated by <cfproperty> declarations.

Leave a Comment

Comments

  • Tony Nelson | August 18, 2009

    What are your thoughts on adding an implicit instance scope to CF similar to what they did with the local scope in CF9? In my opinion, it seems to be a pretty common convention that could warrant being built into the language.

  • Mark | August 18, 2009

    @Tony,
    I can definitely see it’s uses, however I’d be reticent to want to add yes *another* underlying Java object to CFC creation.

    Variables scope works, it can be a tad tricky to manage around the UDFs that are in the same scope, but it’s manageable.

  • Ben Nadel | August 20, 2009

    Very cool. So, I assume you don’t have to turn off the setter="false" attribute. Just defining the setter will automatically overwrite the implicit setter?

  • Mark | August 20, 2009

    @Ben,
    Yes, that is totally correct, you don’t have to turn the setter to ‘false’, defining the setter automatically overwrites the generated one.

  • Ben Nadel | August 20, 2009

    Very cool, thanks for the tip.

  • Alan | April 17, 2012

    Super helpful Mark, question though. Let’s say instead of a hash, you store them using AES Encryption. Setting the password is easy on each insert or update – even handling the decryption during the get is no problem.

    How do you handle encrypting the password value when used as part of the"WHERE" statement (EntityLoad()), without having to do it at the point of usage?

    I’d prefer to store the encryption function as part of the model, so that I can just focus on passing in the original string value wherever I need to retrieve the account.

  • Mark | April 17, 2012

    @Alan,

    Honestly, I never use the password as part of the ‘WHERE’ part of my sql (and I use HQL mostly anyway).

    If I need to compare the password to a user input string, I write a ‘comparePassword()’ that returns true / false. That way the implementation of the passwod encryption stays within the User object and is encapsulated.