I have always found attributes to be odd to work with in The Raiser’s Edge API. For some reason Blackbaud treat them somewhat differently than other child objects on a record. I have already spoken about that a few years ago but I wanted to elaborate on a couple of issues.
When you have an attribute category that takes as its description a boolean, you would assume that the API would work in the same way as import works. Import accepts yes, no, true, false, y and n and you would have thought that the API would accept the same values. It does not. Instead it accepts -1 and 0. That means whenever a true or false or yes or no value comes in you have to translate it to these values. If you know in advance that the attribute you are working with is a boolean then you do not need to determine this yourself. If you are working with a generic method to add attributes then the attribute category could be any type of attribute. It is quite possible that you have a code table attribute with the entries of “yes” and “no”. In that case you do not want to convert these values to 0 and -1. To determine if the attribute is a boolean you should do the following
Dim mustBeUnique as Boolean Dim attServer as New CAttributeTypeServer
attServer.Init(SessionContext) If attServer.GetAttributeDataType(id, mustBeUnique) = bbAttributeTypes.bbAttribute_BOOLEAN Then .... End If
Here the method GetAttributeDataType takes the attribute type id (this is the category’s id) and a variable that is passed by reference which tells you whether or not the attribute must be unique.
Knowing whether or not the attribute should be unique is also important. When working with attributes you need to know whether or not you should be adding to any existing attributes of the same type or overwriting existing attributes. Of course if you are writing for one specific type of attribute you will know if this is possible or not but if you are writing a generic routine to add any attribute then you need to determine whether or not The Raiser’s Edge will allow you to add more than one, whether you want to overwrite the existing attribute or whether you want to raise your own, more meaningful exception. Using the above method will tell you but you can also tell from a simple property on the attribute.
Once you have got hold of the attribute object from the constituent (gift, action, fund, etc) collection of attributes you can look at the MustBeUnique property.
I share your sentiments regarding the way attributes are handled. I’m currently trying to work out more on handling them (some of the methods and functions seem intriguing, particularly the ExistOnRecord function of the CAttributeType object).
We’re in the process of changing a Constituent attribute from boolean to table (it will still have yes/no, but a third value as well). So I’ve modified code so when the attribute is added it checks the type, and if boolean converts it to -1/0, otherwise enter it as yes/no.
This way once other processes are updated and the attribute is changed over in RE (the table attribute will have the same name as the boolean), this code will be able to keep working without modification.