We are a group of users of Blackbaud products and are not affiliated with Blackbaud. We'd love to have you join our community to help and be helped in getting the most from your Blackbaud software.
Register now to join us to get independent advice on your system, connect with 3rd party consultants to help you maximize your database and have a real alternative to the official Blackbaud website.
What is the best way to loop through every constituent in RE? We will need to do that as a part of some pretty large data merges we will be doing with external data such as student data from the university.
There are a couple of methods depending on what you want to do.
The easiest and most intuitive method is to simply load the CRecords object without any filters. This will bring back everything in your database. However depending on the size of the database it could be quite a load for or an app.
Another way is to use ADO to pull the ids from the Records table and loop through all the ids - you would need to make sure that you are only pulling constituents (individual and organisation relationship records are also recorded there).
I possibly didn't make myself clear. If you go the direct route via the database then you have to filter out any individual and organisation relationship records. These are not constituents but they are stored in this table any way. If you only want individual constituents then you can still use the CRecords approach you just need to put a filter on so that you only pull individuals and not organisations. For example when you initialise the CRecords object you would use the tvf_record_Individuals switch under the filters.
Ahhh... that makes sense. I am pretty new to Raiser's Edge and somewhat new to programming in the microsoft environment so I still get confused easily.
Here is some c sharp code that describes what I would like to do embedded with actual code that does not work. I've got 2 c# books on order so perhaps when they show up I can help me help myself
using Blackbaud.PIA.RE7.BBREAPI;
// main program
static void Main(string[] args)
// connect to RE
REAPI fsuRE = new REAPI();
fsuRE.Init("TREE7302252", "loginname", "password", 1, "", AppMode.amServer);
fsuRE.SignOutOnTerminate = true;
// load every person in the RE database
Blackbaud.PIA.RE7.BBREAPI._CRecord people = new Blackbaud.PIA.RE7.BBREAPI._CRecord();
people.Init(ref session);
// I think I need to do something like this but I'm missing something, I would guess executing the method
// Load with no parameter will load everyone. Maybe I should have used the interface CRecordClass??
// Is there documentation somewhere I should look at... argh... I can only get so much out of the object // browser.
people.Load();
Switching to pseudo code now
foreach person returned
-----load that person's record object
-----foreach _CConstitAddress object in this person's record object
----------loop through each enum item in the enum ECONSTIT_ADDRESSFields
---------------print the enum item and the value for that item
My thought is that this will show me exactly what is out there and I can start to write something to compare different addresses to each other, clean up bad data and merge existing data in RE with new better faster smarter data
// Get an array of enum values for a constituent address
Array addressFields = Enum.GetValues(typeof(Blackbaud.PIA.RE7.BBREAPI.ECONSTIT_ADDRESSFields));
// Initialize the records class to retrieve all records in a read-only mode
// Sorted by last name
Blackbaud.PIA.RE7.BBREAPI.CRecordsClass people = new Blackbaud.PIA.RE7.BBREAPI.CRecordsClass();
people.Init(ref session, Blackbaud.PIA.RE7.BBREAPI.TopViewFilter_Record.tvf_record_All, string.Empty, true);
people.SortField = Blackbaud.PIA.RE7.BBREAPI.ERECORDSFields.RECORDS_fld_LAST_NAME;
people.SortOrder = Blackbaud.PIA.RE7.BBREAPI.bbSortOrders.Ascending;
foreach (Blackbaud.PIA.RE7.BBREAPI._CRecord person in people)
{
foreach (Blackbaud.PIA.RE7.BBREAPI._CConstitAddress address in person.Addresses)
{
foreach(Blackbaud.PIA.RE7.BBREAPI.ECONSTIT_ADDRESSFields addressField in addressFields)
{
Console.WriteLine(addressField.ToString() + ": " + (string)address.get_Fields(addressField));
}
}
}
I must be making progress as that code makes sense. In fact yesterday I was digging around looking for exactly some sort of method that would return an array of the constituent address enum items.
Actually this is kind of interesting... So I can pass the init method what amounts to a filter, but I have to pick a pre built filter and each filter option is essentially an enum item in the enum list. Good gravy! Is it possible to abstract this out anymore.
There has got to be some documentation listing all the interfaces, objects, methods and enums out there and what they do. The object browser doesn't explain that clearly. Does that information exist? The one pdf I have doesn't really do that.
Actually this is kind of interesting... So I can pass the init method what amounts to a filter, but I have to pick a pre built filter and each filter option is essentially an enum item in the enum list. Good gravy! Is it possible to abstract this out anymore.
There has got to be some documentation listing all the interfaces, objects, methods and enums out there and what they do. The object browser doesn't explain that clearly. Does that information exist? The one pdf I have doesn't really do that.
Have you looked in C:\Program Files\Blackbaud\The Raisers Edge 7\Help ?
reapi.chm
REMetaView.exe
RE7Objects.chm
api.pdf
The records class will accept a custom SQL filter as well - but you have to know what the DB column names are and what the values are.
In The Raiser's Edge go to Help and Visual Basic help. There is a list of all the classes, interfaces and enums in the API. You are not restricted to filters of an enum. There is a filter object and you can use a custom where clause. Both of these are covered in my blog (see link below)
Ok, I can find a cRecords object in the documentation but no CRecordsClass object. Sigh... either I'm missing something or the documentation is missing something.
Actually it looks like what we are using is a collection class; that's a nuance I'll have to dig through later when my books arrive.
Two specific questions.
1 - I see in the docs that indeed there is an optional custom where clause: sCustomWhereClause Optional. A String value.Where would I find more detail on the format for that string. Is it an actual SQL statement like 'where lastname = 'smith'
I'll dig through David's blog and see what I can see.
2 - It seems that via C# you must pass all parameters, even optional ones. I suppose if the parameter is a string I could just pass along "". In the case of an optional enumerated constant, I'm not suree how to pass along a null value for that short of creating an enum with nothing in it myself.
Edit---- It seems one on the enum items is tvf_record_CustomWhereClause so I suppose that would go in place if you wanted to use the custom clause.
The custom where clause is a SQL where clause based off the records table. You can use any sql there that you would do in SQL but only for a where. If you need other tables you have to write a subselect to access them.
Entering the optional parameters can be dodone with the Type.Missing "object"
Do you have to have the RE modules VBA/API to do any/all of these tasks? Besides exporting all constituents to an external program and then using that for comparison?
Danielle
Do you have to have the RE modules VBA/API to do any/all of these tasks?
Hi Danielle,
Without the API or VBA module, your only avenue to using the REAPI object model would be a plugin. Blackbaud has example plugin code here, and David Zeidman has an excellent riff on it here.