I have a webpart which is 2-3 subsites down the top level site. I need to query the list which is in top site collection and one at the same level,I guess its possible through SPSiteDataquery...I have some confusion related to it can i write single query which can query both these list....
The scope of this query is sitecollection so that means it wud going to look into all list in sitecollection..and if my CAML query is same for both these lists ...it should work?
let me explain through my code:
SPSite mySite = SPControl.GetContextSite(Context);
SPWeb myWeb = SPControl.GetContextWeb(Context);
SPSiteDataQuery qry = new SPSiteDataQuery();
qry.Lists = "<Lists BaseType='0' />";
qry.Query = "<Where><Contains><FieldRef Name='Country'/><Value Type='Text'>" + strcount + "</Value></Contains></Where>";
qry.ViewFields = "<FieldRef Name='Capital' Nullable='TRUE'/><FieldRef Name='Currency' Nullable='TRUE'/>";
qry.Webs = "<Webs Scope='SiteCollection' />";
DataTable dt = myWeb.GetSiteData(qry);
Now i need currency from list which is in top level site and Capital from the list which is at same level. Is this possible? or I misunderstood SPSiteDataQuery...?
You are on the right track and it is possible to retrieve results for lists in different webs. The following example shows how to retrieve items from the default 'Tasks' or 'Workflow Tasks' lists and works with task lists created at the root level and within a sub site.
SPSiteDataQuery q = new SPSiteDataQuery();
q.ViewFields = "<FieldRef Name='Title'/><FieldRef Name='Priority'/><FieldRef Name='Status'/>";
q.Webs = "<Webs Scope='SiteCollection' />";
q.Lists = "<Lists BaseType='0' />";
q.Query = "<Where><Gt><FieldRef Name='ID' /><Value Type='Number'>0</Value></Gt></Where>";
DataTable results = new DataTable();
using (SPSite site = new SPSite("http://sharepoint"))
{
using (SPWeb web = site.OpenWeb("subsite"))
{
results = web.GetSiteData(q);
}
}
I've written it using a hardcoded URL so you can run it inside a console application for testing but you can replace the using statements with something like SPWeb web = SPContext.Current.Web; when you put this inside a web part.
A few other things worth considering:
The lists you are querying must contain all the fields in the ViewFields element
Multi-lookup fields do not work well with the SPSiteDataQuery (single value lookup fields are ok)
The u2u CAML builder tool is also useful for testing CAML queries. See http://www.u2u.be/Res/Tools/CamlQueryBuilder.aspx
Related
I am using Sharepoint 2010, and wrote an application page in C#/VS2010. I am using ListViewByQuery to display a list. All is well, until I add the GroupBy tag to group the list. When this is added, for some reason the columns I've chosen with query.ViewFields are ignored, and instead three other columns are displayed, both when collapsed and when expanded. Code is here:
//this section demonstrates how to display a list in an SP Application Page project:
using (SPWeb web = site.OpenWeb())
{
myListQuery.List = web.Lists["Links"];
SPQuery query = new SPQuery(myListQuery.List.DefaultView);
//note: there seems to be bug somewhere... when the list is grouped by (folders), you
// don't see the fields you request - just three basic fields. It seems to ignore the ViewFields
// that you specified, unless you don't group. Weird.
query.ViewFields = "<FieldRef Name=\"ID\" /><FieldRef Name=\"URLwMenu\" /><FieldRef Name=\"List\" /><FieldRef Name=\"Category\" /><FieldRef Name=\"Author\" />";
query.Query = "<Where><Contains><FieldRef Name=\"List\"/><Value Type=\"Text\">Projects</Value></Contains></Where>";
//if this next line is commented out, all the correct columns are shown
query.Query += "<GroupBy Collapse=\"FALSE\" GroupLimit=\"100\"><FieldRef Name=\"Category\"></GroupBy>";
myListQuery.DisableFilter = false;
myListQuery.DisableSort = false;
myListQuery.Query = query;
}
The columns that are shown, in this example, are Type, Edit, URL, and Notes. If anyone has any clues, it would be much appreciated!
You appear to be missing the / in the closing tag of the FieldRef in the GroupBy clause:
<FieldRef Name=\"Category\">
I have a calculated field in my list and I am trying to use filter on this field. For some reason, the following query always returns all items instead of a filtered item collection:
var spQuery = new SPQuery
{
Query = #"<Where><Geq><FieldRef Name='Score' /><Value Type='Calculated'>10000</Value></Geq></Where><OrderBy><FieldRef Name='Modified' Ascending='True' /></OrderBy>",
RowLimit = 200,
ViewFields = #"<FieldRef Name='Username' />"
};
var spList = web.Lists["Users"];
var spListItemCollection = spList.GetItems(spQuery);
try using
spQuery.ViewFieldsOnly = true;
Remove the query element from your SPQuery. See syntax here
Try removing ViewFields section (to get all columns, also those that are needed for calculation) or set SPQUery.IncludeMandatoryColumns
I have a scenario where I need to update a list item, but I don't know the internal ID of the list item - hence the following won't work for me:
batchElement.InnerXml = "<Method ID='1' Cmd='Update'>" +
"<Field Name='ID'>" + id + "</Field>" +
"<Field Name='DeliveryStatus'>" + newStatus.ToString() + "</Field></Method>";
Instead I have another field in the list called ProcessID:
So I would like to update the delivery status where ProcessID = X
Is this possible using SharePoint web services.
One solution I was thinking of is to first do a select for the ID based on the ProcessID - then update based on this ID, but this seems like a crazy solution, surely the inventors of MOSS CAML would have provided a way to update a list item by some means of a where clause, or using another field for filtration rather than just plain old ID?
Thanks
I don't believe you can do an UPDATE WHERE. You will need to get all the items matching your given ProcessID in order to get each of the individual item IDs.
Since you're using web services, one way to make this more efficient is to make sure you set the ViewFields property when you perform your select in order to limit it to only the columns you are interested in (in this case, ID).
Example:
XmlDocument xmlDoc = new System.Xml.XmlDocument();
XmlNode ndQuery = xmlDoc.CreateNode(XmlNodeType.Element, "Query", "");
XmlNode ndViewFields = xmlDoc.CreateNode(XmlNodeType.Element, "ViewFields", "");
XmlNode ndQueryOptions = xmlDoc.CreateNode(XmlNodeType.Element, "QueryOptions", "");
ndQueryOptions.InnerXml = "<ViewAttributes Scope='Recursive' />";
ndViewFields.InnerXml = "<FieldRef Name='ID' />";
ndQuery.InnerXml = query;
I'm trying to query a SharePoint list using the following CAML query in a webpart. I have tested the query in U2U CAML Query Builder and Stramit CAML Viewer and it works fine, only returning the matching records, but when I use it in my webpart it return all list items. It is driving me crazyyyyy. Here is the code:
string camlQuery = string.Format(#"<Query><Where><Contains><FieldRef Name='Title' /><Value Type='Text'>2</Value></Contains></Where></Query>");
SPQuery query = new SPQuery();
query.Query = camlQuery;
SPListItemCollection items = Articles.GetItems(query);
grid.DataSource = items.GetDataTable();
grid.DataBind();
Leave out the surrounding Query tag, just use:
<Where><Contains><FieldRef Name='Title' /><Value Type='Text'>2</Value></Contains></Where>
SPQuery adds the Query tag itself.
I need help converting the following code snippet to use SPSiteDataQuery instead of SPQuery b/c I need to query accross all Document Libraries in the site.
Here's the original code:
using (SPWeb oWeb = new SPSite(properties.SiteId).OpenWeb(properties.RelativeWebUrl))
{
SPList oList = oWeb.Lists["Quality Documents"];
//create query
SPQuery oQuery = new SPQuery();
//configure the query //
oQuery.Query = "<Where><Eq><FieldRef Name='Document_x0020_Number' /><Value Type='Text'>" + docNum + "</Value></Eq></Where>";
//get the collection of items in the list
SPListItemCollection oItems = oList.GetItems(oQuery);
if (oItems.Count > 0)
{
newRnd = 0;
}
else
{
newRnd = 1;
}
}
And here's what I have for the SPSiteDataQuery but I don't know if it's correct and/or how to make sure the code does the same thing as the above code.
SPSiteDataQuery q = new SPSiteDataQuery();
q.Lists = "<Lists BaseType='1'/>";
q.Query = "<Where><Eq><FieldRef Name='Document_x0020_Number' /><Value Type='Text'>" + docNum + "</Value></Eq></Where>";
q.Webs = "<Webs Scope='SiteCollection' />";
q.ViewFields = "<FieldRef Name='Document_x0020_Number' />"';
q.RowLimit = 1;
The main difference between SPQuery and SPSiteDataQuery is in specifying the list to query. Unlike with SPQuery, in SPSiteDataQuery you cannot specify a list title to narrow down your query in each site, you only have the Lists element which is a lot less flexible. Vincent Rothwell describes all of the possibilities here.
This inflexibility means that the use of BaseType=1 in your Lists element code will return documents from all document libraries. The only way you can avoid this is if you deployed a custom list template for Quality Documents with its own ID number. You would then be able to use <Lists ServerTemplate='XYZ' /> (where XYZ is the ID number to narrow results down to that type of list). Otherwise you will need to filter the results you get back so they only contain entries from the Quality Documents library.
Apart from this your code looks equivalent. You may also like to look at CrossListQueryInfo and CrossListQueryCache if you are running MOSS. These allow you to cache SPSiteDataQuery-style queries. See this post by Jeff Dalton for good information on this.
Update from comments about object disposal:
Your code will leak the SPSite object - this needs a using clause as well. Replace the using line you currently have with these lines:
using (SPSite oSite = new SPSite(properties.SiteId))
using (SPWeb oWeb = oSite.OpenWeb(properties.RelativeWebUrl))
{
// Your code
}
Also, it is easy to use SPDisposeCheck. To integrate with Visual Studio add the following line to your project's post build event:
"%ProgramFiles%\Microsoft\SharePoint
Dispose Check\SPDisposeCheck.exe"
$(TargetPath)
The build will now fail if you have memory leaks. Check the Output window for details on where they are. Note that SPDisposeCheck sometimes reports false positives and it is possible to ignore these (read the documentation to tell you how).