Dynamic property defaults in CF9 ORM - orm

How do you set up dynamic property defaults on CF9 ORM objects?
For instance, I know I can set a property default like this:
property name="isActive" default="1";
But what if you want to have a dynamically generated default, such as a date or a UUID?
property name="uuid" default="#createUUID()#";
...throws an error - so what's the workaround for this?

When an Entity object is created the objects constructor is called. This is a great place for running "setup" code.
User.cfc
component persistent="true"
{
property name="id" fieldtype="id" generator="native";
property name="secretKey";
public User function init() {
if (isNull(variables.secretKey))
setSecretKey(createdUUID());
return this;
}
}

Have you tried overloading the getter?
public string function getUUID() {if(variables.UUID EQ ""){ return createUUID(); } else { return variables.firstName; }; }
I can't test that from where I'm at, but I would try.

Related

how do you name (and map) a backing property?

In a few cases, I have a property that needs a "backing property" for practical reasons.
For example, I have one type with a Name property - there is no transformation of the value happening on access, it merely triggers an action of some kind; a side-effect, if you will. (not that it matters for the sake of discussion, but in this particular case, the name gets copied somewhere else when changed.)
Let's say:
public class Person
{
private string __name;
protected internal virtual string _name
{
get
{
return this.__name;
}
set
{
this.__name = value;
}
}
public virtual string Name
{
get
{
return _name;
}
set
{
_name = value;
// action when changing the name takes place here...
}
}
}
So the "_name" property is mapped to the database, but is kept protected/internal so that it cannot be modified directly. And the second public property "Name" provides the actual access.
The reason I have it set up this way, is because if that action was built directly into the mapped "_name" property's set-method, it would be triggered when an object is hydrated from the database, which is not what I want.
This all works fine as such.
The problem is, when you need to query this type, attempting to query Person.Name won't work, because that property isn't mapped!
What I dislike about this, is the fact that you're writing code against Person.Name, but have to write queries against Person._name, which is error-prone and confusing.
Is there a better way to solve this problem?
Can you use nosetter.camelcase-underscore for the access in the mapping? This would set the field directly (if named correctly, eg _name) instead of using the property setter.
eg:
<property name="Name" column="Name" type="String" access="nosetter.camelcase-underscore"/>

Ignore column using mapping by code in HNibernate

I'm using mapping by code in NHibernate.
I got a class with several properties. One of them is not related to any columns in DB but still has getter and setter.
I use ConventionModelMapper not ModelMapper. The first one assumes that all properties are mapped.
How i can tell to NHibernate to ignore it?
I find it easier to just create an attribute, attach that attribute to the property, and check for it in the mapper.IsPersistentProperty method. Something like this:
class IngnoreAttribute : Attribute
{
}
class Foo
{
[Ignore]
public virtual string Bar { get; set; }
}
mapper.IsPersistentProperty((mi, declared) => mi.GetCustomAttribute<IgnoreAttribute>() == null);
This way, I don't have to keep a list of properties to be ignored at the mapping codes.
Why not map the properties you want and leave the ones not needed to be mapped
check this
You can manage the persistence of ConventionModelMapper as following:
mapper.BeforeMapProperty += (mi, propertyPath, map) =>
{
// Your code here using mi, propertyPath, and map to decide if you want to skip the property .. can check for property name and entity name if you want to ignore it
};
A better answer would be:
mapper.IsPersistentProperty((mi, declared) =>
{
if (mi.DeclaringType == typeof (YourType) && mi.Name == "PropertyNameToIgnore")
return false;
return true;
});
If you do not mention the property that should be ignored in your NHibernate mapping, NHibernate will ignore it.

unmapped class error with coldfusion 9.0.1 orm

i have to model classes User and Order. what i want is to have a relationship between them, so that a user has many orders, which in this case would be a one-to-many rel. which i defined in the User.cfc as follows:
property name="orders"
fieldtype="one-to-many"
cfc="Order"
fkcolumn="userID"
type="array";
each of this cfcs can be loaded through EntityLoad( Entity Name ) without any problems; i see all the data in the dump output.
however, as soon as i put the orders relationship in the User.cfc, it all breaks apart and i get an error message:
Association references unmapped class: Order
here's the code for the cfcs
User.cfc
component persistent="true" datasource="otherDatasource"
{
property name="id" fieldtype="id";
property name="userName";
property name="password";
property name="firstName";
property name="lastName";
property name="title";
property name="orders"
fieldtype="one-to-many"
cfc="Order"
fkcolumn="userID"
type="array";
function init()
{
return this;
}
}
Order.cfc
component persistent="true"
{
property name="id" fieldtype="id" generator="guid";
property name="quantity";
property name="period";
property name="region";
property name="createdAt" ormtype="date";
function init()
{
return this;
}
}
Any ideas what i'm doing wrong here?
it seems as i have my answer. coldfusion 9.0.1 orm isn't capable of building a relationship between tables in different databases.

NHibernate Custom Collections hack works outside of a transaction, but not inside

Following the technique described here, I was able to populate a domain object that uses custom collections for its children. The relevant property mapping looks like this:
<component name="Contacts" class="My.CustomList`1[[Domain.Object, DomainAssembly]], MyAssembly">
<set name="InnerList">
<key column="PARENT_ID" />
<one-to-many class="Contact" />
</set>
</component>
My custom collection class exposes the InnerList property as an ICollection like so:
protected System.Collections.ICollection InnerList
{
get
{
return this;
}
set
{
Clear();
foreach (DomainObject o in value)
{
Add(o);
}
}
}
This worked like a charm to load data from the database and not have to abandon my rather useful custom collection class.
Then I moved on to try implement saving, and following the advice given in this thread, decided to wrap every call to NHibernate in a transaction.
Now when I commit following my load, NHibernate throws an InvalidCastException: "Unable to cast object of type 'My.CustomList`1[Domain.Object, DomainAssembly]' to type 'Iesi.Collections.ISet'."
Is there a way to make this work the way I expect it to?
EDIT:
Following the lead provided by Raphael, I tried switching to ICollection<T> which gives me a different InvalidCastException when I commit the transaction: Unable to cast object of type 'My.CustomList`1[Domain.Object]' to type 'NHibernate.Collection.IPersistentCollection'.
Change the property to be of type
IList<T>

super() type functionality on ORM CFC

When I use CF9's ORM feature and generate an explict setter for my ORM CFC, is there anyway to call the default funcitionailty of the ORM CFC after i have done the work needed in the method. For example i am looking for something like this. Obviosuly the code will not run , and super is the wrong concept since the ORM CFC isnt inherting anything, but thats the type of functionality I am looking for.
public void setMovie(String movie){
if(movie == "inception"){
ORMCFC.super().setMovie("Greatest movie ever made")
}else{
ORMCFC.super().setMovie(movie)
}
In your model CFC for the ORM you can specify additional "decorator" functions.
component persistent="true" table="Movie" schema="dbo" output="false"
{
/* properties */
property name="MovieNo" column="MovieNo" type="numeric" ormtype="double" fieldtype="id" ;
property name="Name" column="Name" type="string" ormtype="string" ;
/* decorator */
public void function setMovie(name)
{
if(name == "inception"){
setName("Greatest movie ever made")
}else{
setName(name)
}
}
}
Otherwise if you need to (using your example) setMovie() you will need to do an EntityLoad or create a new entity to set a value to.