For anyone needing to query data from several lists in a site collection the CQWP is the best tool to do so. However, sometimes you just need more flexibility. So did I, I am working on a News webpart which allows for tabs and filtering per tab on, well, basically anything you could want to filter on. Plus it is all asynchronous loading with jquery.
So, I wanted to create a webservice to give me my news pages from the entire site collection. A rather cool but relatively unused way to do this is to use the CrossListQueryCache and CrossListQueryInfo. This is the class that the ContentByQueryWebPart also uses to retrieve it's data. The advantage of this class vs SiteDataQuery is that this has built in caching and audience filtering. There are a few need-to-knows though to get this to work correctly.
Basically, to get the CrossListQueryInfo and CrossListQueryCache to work isn't rocket science, you can google enough about it. a rather nice blogpost about it can be found here: http://bloggingabout.net/blogs/bas/archive/2009/03/27/using-the-crosslistqueryinfo-and-crosslistquerycache.aspx
However, to get Audience Targeting to work is another story. It seems so simple, setting two properties in your CrossListQueryInfo:
clqinfo.FilterByAudience = true;
clqinfo.ShowUntargetedItems = true;
However this will still give you results, but will not filter. The class works as follows: first it queryies the lists and retrieves the data. After this, audience filtering is applied. To filter the audience, the audience info must be present in the data. So, add it to the viewfields as follows:
string viewFields = "<FieldRef Name=\"Title\"/>" +
"<FieldRef Name=\"ContentType\"/>" +
----- snip -----
"<FieldRef Name=\"FileRef\" Nullable=\"True\"/>" +
(string.Format("<FieldRef Name=\"{0}\" Type=\"{1}\" />",
"{" + FieldId.AudienceTargeting.ToString() + "}",
"TargetTo"));
And presto, now you will have audience filtering.
Note: because the audience filtering is applied after retrieving the data, specifying an rowlimit, this will result in less results after filtering. Make sure your rowlimit is high enough to allow the necessary amount of results to show up in your webpart after filtering. This is also a bug in CQWP and there's no fix as of yet. But you can workaround it in your code.