Checking exception before using GETITEMBYID() - sharepoint

I am getting item by getiembyid...but I want to check before using it that whether item exist or not...I don't want to use query as main purpose of using Getitembyid is performance.....any idea how to achieve this...
itemid = Response.QueryString["loc"];
SPList mylist = myweb.GetList(SPUrlUtility.CombineUrl(myweb.ServerRelativeUrl, "/Lists/Location"));
//now id itemid does not exist it throws exception...so i want to check before using following statement that itemid exist...I know i can check throw SPQuery but as i said above because of performance issue only i m using itemid....
SPListItem myitem = mylist.GetItemById(Convert.ToInt32(itemid));
Any idea how to achieve this?

SPQuery by no way will make your code slow, infact every other SharePoint article on net advice you to use SPQuery to gain Performance. To make things still more interesting GetItemByID internally use SPQuery to fetch the Item back to you,following is part of code taken from the GetItemByID function
SPQuery query = new SPQuery();
query.Query = "<Where><Eq><FieldRef Name=\"ID\"></FieldRef><Value Type=\"Integer\">" + id.ToString(CultureInfo.InvariantCulture) + "</Value></Eq></Where>";
Important to note here is SPQuery has a Internal property called SingleItemId which takes Id of the Item Id you want to fetch, further tracing of how it being used cannot be found as the call finally lands up in COM Object.
Being said that you have two options
Option 1:
Wrap your GetItemByID code inside the catch block and check for exception,if one occurs you can mark a flag to denote that Item Id is invalid and take action for it.
Option 2:Use SPQuery, you can test the time difference GetItemByID & using SPQuery, you will see that there is no and just a very very little.

Related

how to use content iterator in sharepoit 2010

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.

Sharepoint SPQuery problem

I'm trying to use GetItems() method on a SPList and I pass SPQuery to it. The problem is, it return all the items from my SPList instead of just the filtered ones. My query looks like this:
<WHERE><Eq><FieldRef Name='Type' /><Value Type='Text'>Analysis</Value></Eq></WHERE>
Thye typye of the'Type' column is Single line of text, which i believe translates to Text in CAML. Then I just do the standard stuff:
SPQuery q = new SPQuery();
q.Query = CAMLQuery.ToString();
var filtered = _NoticeList.GetItems(q);
filtered.Count is 4 instead of 2... perhaps someone cann se whats wrong with this code
I think CAML is Case sensitive so it'd have to be:
<Where><Eq><FieldRef Name='Type' /><Value Type='Text'>Analysis</Value></Eq></Where>
Otherwise you could try renaming the 'Type' field, because it might be interpreted as an internal field.

How to find item count in a SPFolder?

I have a List that stores items in a folder hierarchy.
I notice that SPFolder.Files.Count is always zero.
Is there a way to find out how many list items are there in a folder?
I presume you are looking for direct children and not descendants (like items within a sub-folder).
Do you also want to include sub-folders in the count? In which case you can use: SPFolder.ItemCount.
If you just want only the direct child listItems which are not subfolders then you can do something like the following:
using (SPSite site = new SPSite(mySPSite))
{
SPWeb web = site.OpenWeb();
SPList list = web.Lists[myList];
SPFolder folderInstance = list.RootFolder.SubFolders[folderUrl];
SPQuery query = new SPQuery() ;
query.Folder = folderInstance;
SPListItemCollection items = list.GetItems(query) ;
Console.WriteLine(items.Count);
}
I haven't tried it. You might have to add a where clause to eliminate folders, if the query is returning that.
If you want to include all list-items, even within subfolders, set the SPQuery.ViewAttributes field as query.ViewAttributes = "Scope=\"Recursive\"";
Did you try to get the SPListItem from the SPFolder and check the values from the SPBuiltInFieldId.ItemChildCount and SPBuiltInFieldId.FolderChildCount fields?
Something like this:
SPFolder folder = ...;
int? noOfItems = folder.Item[SPBuiltInFieldId.ItemChildCount] as int?;
int? noOfFolders = folder.Item[SPBuiltInFieldId.FolderChildCount] as int?;
See
SPBuiltInFieldId.ItemChildCount Field
SPBuiltInFieldId.FolderChildCount Field
for more info.
From Microsoft
Using the SPList.ItemCount property is
the recommended way to retrieve the
number of items in a list. As a side
effect of tuning this property for
performance, however, the property can
occasionally return unexpected
results. For example, if you require
the exact number of items, you should
use ...
I wonder if the same applies to SPFolder.ItemCount ?

SharePoint's List.GetItems(view) returns ALL items instead of filtered view items

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>";

What is the best way to retrieve distinct / unique values using SPQuery?

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.

Resources