I am using SharePoint web service and am trying to return the highest ID number from a list. My scenario is like say I have 10 items in a list. Highest ows_ID at this point is 10. Now, if I delete an item and check the max of ows_ID, I got 9, however the highest ows_ID is 10 inclusive of deletion.
If a new item gets inserted, it gets the ows_ID as 11 instead of 10. In the same way, is it possible to get the highest ows_ID even though the item is deleted?
You can call GetList to see the highest ID used. That method returns information about the list itself rather than the items in it.
Try "rowLimit", configure your CAML to do your stuff and only get the first item in the search criteria:
string rowLimit = "1";
System.Xml.XmlDocument xmlDoc = new System.Xml.XmlDocument();
System.Xml.XmlElement query = xmlDoc.CreateElement("Query");
System.Xml.XmlElement viewFields = xmlDoc.CreateElement("ViewFields");
System.Xml.XmlElement queryOptions = xmlDoc.CreateElement("QueryOptions");
query.InnerXml = "<Where><Eq><FieldRef Name=\"FileLeafRef\"/><Value Type=\"" + fieldType + "\">" + fieldValue + "</Value></Eq></Where> ";
viewFields.InnerXml = "<FieldRef Name=\""+fieldToGet+"\" />";
queryOptions.InnerXml = "";
System.Xml.XmlNode nodes = myservice.GetListItems(listGuid, viewGuid, query, viewFields, rowLimit, null, null);
In my example below, I just get the last created item, using some criteria, but as You don't need this, just fix the caml in my code.
Related
there are 7000 items in my list. i need to filter the list and retrieve result
i am using the following code in my webpart.
string query = "<Where><BeginsWith><FieldRef Name='Project' /><Value Type='Text'>ab</Value></BeginsWith></Where>"
SPQuery spquery = new SPQuery();
spquery.Query = query;
ContentIterator iterator = new ContentIterator();
iterator.ProcessListItems(list, spquery, ProcessListItem, ProcessListItemError)
as i am using ContentIterator still it is giving me the error "The attempted operation is prohibited because it exceeds the list view threshold enforced by the administrator"
Update:
string query2 = #"<Where><Eq><FieldRef Name='Project' /><Value Type='Text'>11759</Value></Eq></Where>";
SPQuery spquery = new SPQuery();
spquery.RowLimit = 10;
spquery.Query = query2;
spquery.QueryThrottleMode = SPQueryThrottleOption.Override;
ContentIterator iterator = new ContentIterator();
iterator.ProcessListItems(list, spquery, ProcessListItem, ProcessListItemError);
In every case weather I used SPCollectionItem or Iterator. when ever I am passing the where condition in spquery. same error comes.
To efficiently use ContentIterator and avoid throttle exception, you should explicitly include OrderBy clauses.
Try to use ContentIterator.ItemEnumerationOrderByNVPField which actually enables the index to be used.
For more details,check this out
http://extreme-sharepoint.com/2012/07/17/data-access-via-caml-queries/
Likely because the the Field you are comparing on is not indexed: http://msdn.microsoft.com/en-us/library/ff798465
If you were to build a query that returns the first 100 items sorted
by the ID field, the query would execute without issue because the ID
column is always indexed. However, if you were to build a query that
returns the first 100 items sorted by a non-indexed Title field, the
query would have to scan all 10,000 rows in the content database in
order to determine the sort order by title before returning the first
100 items. Because of this, the query would be throttled, and rightly
so—this is a resource-intensive operation.
You either have to ...
... set a RowLimit below the configured threshold on your query.
... or define a query that returns less items.
... or change the threshold of the list.
have you seen this:
msdn link
hmmz, just tried this and it still gave an error. If I use this however I can iterate over way more than 7k listitems:
private int GetItems(SPList list){
var query = new SPQuery();
query.Query = "";
query.QueryThrottleMode = SPQueryThrottleOption.Override;
var items = list.GetItems(query);
return items.Count;
}
so my advice is to just use the list.getitems
You just need to change your query.
//Keep your query inside <View></View> tag.
string query = "<View><Where><BeginsWith><FieldRef Name='Project' /><Value Type='Text'>ab</Value></BeginsWith></Where><View>"
SPQuery spquery = new SPQuery();
spquery.Query = query;
ContentIterator iterator = new ContentIterator();
iterator.ProcessListItems(list, spquery, ProcessListItem, ProcessListItemError)
Now run the program and it will work.
I wanted to delete all the Items from SharePoint List using Lists webservice,
i know we can do it by iterating all the items, my problem is that the, i have 25000 items in my list and wanted to delete it in one go, Is there any way to do this?
or is there a way to get all the attributes of List then delte the list and re-create the list with the previously saved attributes.
Thanks in Advance.
You could save the list as a template (List Settings -> Save list as template), then delete the list, then create a new list based on the template that you saved.
You could use the UpdateListItems method of the Lists web service, however it is still going to take a long time to delete all items at once.
Try the following snippet -
var batch = new StringBuilder();
batch.Append("<Batch OnError='Continue' ListVersion='1' ListName='{GUID}'>");
string itemTemplate = "<Method ID='1' Cmd='Delete'><Field Name='ID'>{0}</Field></Method>";
for (int i = 0; i < 300000; i++)
batch.Append(string.Format(itemTemplate, i));
batch.Append("</Batch>");
//query Lists service
This code assumes that your item's ID range is from 0 to 300000 - this will be your only option without iterating
all items (and getting their ID). However, with this much items even the StringBuilder will run into performance
problems, not to mention SharePoint.
Your best bet is to delete the site and re-create it like pmartin suggested it.
Here is the way we can do it simply:
XmlNode listItems = SharepointUtilities.GetListItems(sharePointCredentials, sharePointCredentials.SharePointListName);
var nodes = (from nd in listItems.ChildNodes.OfType<XmlNode>() where nd.NodeType.Equals(System.Xml.XmlNodeType.Element) select nd);
var itemIDs = from nd in nodes.FirstOrDefault().ChildNodes.OfType<XmlNode>() where nd.NodeType.Equals(System.Xml.XmlNodeType.Element) select nd.Attributes["ows_ID"].Value;
if (itemIDs.Count() > 0)
{
Lists spSrv = GetSharepointListsService(sharePointCredentials);
XmlDocument doc = new XmlDocument();
XmlElement batchElement = doc.CreateElement("Batch");
batchElement.SetAttribute("OnError", "Continue");
string batchCommand = "<Method ID='1' Cmd='Delete'><Field Name='ID'>";
batchCommand += string.Join("</Field></Method><Method ID='1' Cmd='Delete'><Field Name='ID'>", itemIDs.ToArray());
batchCommand += "</Field></Method>";
batchElement.InnerXml = batchCommand;
spSrv.UpdateListItems(sharePointCredentials.SharePointListName, batchElement);
}
Open the list in DataSheetView, select all records (ctrl+A) and Delete all records.
This is the shortest solution.
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 get a count of items in a list, based on a view. Every method I've tried so far only returns the grand total of the list. I've tried just about every method I've run across while searching, and everything ends up with the same results.
Here's one of the methods I've tried:
SPWeb web = SPContext.Current.Web;
SPView view = web.GetViewFromUrl("url to my view");
int count = view.ParentList.GetItems(view).Count;
My list has 28 items, but the view I'm referencing filters it and shows four items. I expect my count to be 4, not 28 - but 28 is what I always get.
Here's another method I've tried:
SPSite site = SPContext.Current.Site;
SPWeb web = site.OpenWeb();
SPQuery MyQuery = new SPQuery();
MyQuery.Query = "<Query><Where><Eq><FieldRef Name='strStatus' /><Value Type='Text'>submitted</Value></Eq></Where></Query>";
IEnumerable<SPListItem> results = web.Lists["Requests"].GetItems(MyQuery).Cast<SPListItem>();
// results.Count() is 28... should be 4
So in this method I'm skipping the view and just trying to pass in a CAML query. When testing my query in U2U, four results are returned as expected...
The larger picture is that I'm doing this inside of my custom menu control's OnMenuItemDataBound event handler. I don't know if that makes a difference at all, but the idea I'm heading towards is that each item that links to a view in a specific list, will show the count of items in that view next to the link.
Any ideas why I'm getting a list total instead of the filtered totals? Thanks!
If I remind correctly, you need to remove the <Query> from your SPQuery. The CAML Builders use it but its unnecessary in the actual SPQuery. Of course you need to make sure the fields exist.
MyQuery.Query = "<Where><Eq><FieldRef Name='strStatus' /><Value Type='Text'>submitted</Value></Eq></Where>";
I have a list that looks like:
Movie Year
----- ----
Fight Club 1999
The Matrix 1999
Pulp Fiction 1994
Using CAML and the SPQuery object I need to get a distinct list of items from the Year column which will populate a drop down control.
Searching around there doesn't appear to be a way of doing this within the CAML query. I'm wondering how people have gone about achieving this?
Another way to do this is to use DataView.ToTable-Method - its first parameter is the one that makes the list distinct.
SPList movies = SPContext.Current.Web.Lists["Movies"];
SPQuery query = new SPQuery();
query.Query = "<OrderBy><FieldRef Name='Year' /></OrderBy>";
DataTable tempTbl = movies.GetItems(query).GetDataTable();
DataView v = new DataView(tempTbl);
String[] columns = {"Year"};
DataTable tbl = v.ToTable(true, columns);
You can then proceed using the DataTable tbl.
If you want to bind the distinct results to a DataSource of for example a Repeater and retain the actual item via the ItemDataBound events' e.Item.DataItem method, the DataTable way is not going to work. Instead, and besides also when not wanting to bind it to a DataSource, you could also use Linq to define the distinct values.
// Retrieve the list. NEVER use the Web.Lists["Movies"] option as in the other examples as this will enumerate every list in your SPWeb and may cause serious performance issues
var list = SPContext.Current.Web.Lists.TryGetList("Movies");
// Make sure the list was successfully retrieved
if(list == null) return;
// Retrieve all items in the list
var items = list.GetItems();
// Filter the items in the results to only retain distinct items in an 2D array
var distinctItems = (from SPListItem item in items select item["Year"]).Distinct().ToArray()
// Bind results to the repeater
Repeater.DataSource = distinctItems;
Repeater.DataBind();
Remember that since there is no CAML support for distinct queries, each sample provided on this page will retrieve ALL items from the SPList. This may be fine for smaller lists, but for lists with thousands of listitems, this will seriously be a performance killer. Unfortunately there is no more optimized way of achieving the same.
There is no DISTINCT in CAML to populate your dropdown try using something like:
foreach (SPListItem listItem in listItems)
{
if ( null == ddlYear.Items.FindByText(listItem["Year"].ToString()) )
{
ListItem ThisItem = new ListItem();
ThisItem.Text = listItem["Year"].ToString();
ThisItem.Value = listItem["Year"].ToString();
ddlYear.Items.Add(ThisItem);
}
}
Assumes your dropdown is called ddlYear.
Can you switch from SPQuery to SPSiteDataQuery? You should be able to, without any problems.
After that, you can use standard ado.net behaviour:
SPSiteDataQuery query = new SPSiteDataQuery();
/// ... populate your query here. Make sure you add Year to the ViewFields.
DataTable table = SPContext.Current.Web.GetSiteData(query);
//create a new dataview for our table
DataView view = new DataView(table);
//and finally create a new datatable with unique values on the columns specified
DataTable tableUnique = view.ToTable(true, "Year");
After coming across post after post about how this was impossible, I've finally found a way. This has been tested in SharePoint Online. Here's a function that will get you all unique values for a column. It just requires you to pass in the list Id, View Id, internal list name, and a callback function.
function getUniqueColumnValues(listid, viewid, column, _callback){
var uniqueVals = [];
$.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_layouts/15/filter.aspx?ListId={" + listid + "}&FieldInternalName=" + column + "&ViewId={" + viewid + "}&FilterOnly=1&Filter=1",
method: "GET",
headers: { "Accept": "application/json; odata=verbose" }
}).then(function(response) {
$(response).find('OPTION').each(function(a,b){
if ($(b)[0].value) {
uniqueVals.push($(b)[0].value);
}
});
_callback(true,uniqueVals);
},function(){
_callback(false,"Error retrieving unique column values");
});
}
I was considering this problem earlier today, and the best solution I could think of uses the following algorithm (sorry, no code at the moment):
L is a list of known values (starts populated with the static Choice options when querying fill-in options, for example)
X is approximately the number of possible options
1. Create a query that excludes the items in L
1. Use the query to fetch X items from list (ordered as randomly as possible)
2. Add unique items to L
3. Repeat 1 - 3 until number of fetched items < X
This would reduce the total number of items returned significantly, at the cost of making more queries.
It doesn't much matter if X is entirely accurate, but the randomness is quite important. Essentially the first query is likely to include the most common options, so the second query will exclude these and is likely to include the next most common options and so on through the iterations.
In the best case, the first query includes all the options, then the second query will be empty. (X items retrieved in total, over 2 queries)
In the worst case (e.g. the query is ordered by the options we're looking for, and there are more than X items with each option) we'll make as many queries as there are options. Returning approximately X * X items in total.