SharePoint CAML Query Maximum Size - sharepoint

I am running a sharepoint caml query where I want to check that a field on an item is equal to one of many values. I do this dynamically and may wish to check against many hundreds of values.
I found that when performing a query with 780 OR elements I got an error related to server memory. Obviously this is variable across environments, but I am looking for some guidelines suggesting a maximum query length to which I should cap.
Thanks!

How about using ContentIterator?
http://community.zevenseas.com/Blogs/Robin/Lists/Posts/Post.aspx?ID=122
It supports recursion for walking a tree of items and acting on them in some way.
This code does a "publish all" on the style library files whose "FeatureId" properties match a particular value:
SPList styleLibrary = rootWeb.Lists.TryGetList("Style Library");
SPFolder folder = styleLibrary.RootFolder;
ContentIterator ci = new ContentIterator();
ci.ProcessFilesInFolder(
styleLibrary,
folder,
true,
new ContentIterator.FileProcessor((SPFile f) =>
{
// Check the FeatureId property the file's been "stamped" with
if (f.Properties.ContainsKey("FeatureId"))
{
if (String.Equals(f.Properties["FeatureId"] as string, featureId, StringComparison.InvariantCultureIgnoreCase))
{
if (f.Level == SPFileLevel.Checkout)
f.CheckIn(String.Empty, SPCheckinType.MajorCheckIn);
if (f.Level == SPFileLevel.Draft)
f.Publish("");
}
}
}),
new ContentIterator.FileProcessorErrorCallout((SPFile f, Exception Ex) =>
{
//Define the action I need to do if an error occur
return false;
}));

You could get all folders by SPList.Folders, iterate over the folders and filter it by whatever...

Related

access indexfields, batchfields and batch variables in custom module

In my setup form I configure some settings for my custom module. The settings are stored in the custom storage of the batch class. Given the variable IBatchClass batchClass I can access the data by executing
string data = batchClass.get_CustomStorageString("myKey");
and set the data by executing
batchClass.set_CustomStorageString("myKey", "myValue");
When the custom module gets executed I want to access this data from the storage. The value I get returned is the key for the batchfield collection or indexfield collection or batch variables collection. When creating Kofax Export Connector scripts I would have access to the ReleaseSetupData object holding these collections.
Is it possible to access these fields during runtime?
private string GetFieldValue(string fieldName)
{
string fieldValue = string.Empty;
try
{
IIndexFields indexFields = null; // access them
fieldValue = indexFields[fieldName].ToString();
}
catch (Exception e)
{
}
try
{
IBatchFields batchFields = null; // access them
fieldValue = batchFields[fieldName].ToString();
}
catch (Exception e)
{
}
try
{
dynamic batchVariables = null; // access them
fieldValue = batchVariables[fieldName].ToString();
}
catch (Exception e)
{
}
return fieldValue;
}
The format contains a string like
"{#Charge}; {Current Date} {Current Time}; Scan Operator: {Scan
Operator's User ID}; Page: x/y"
and each field wrapped by {...} represents a field from one of these 3 collections.
Kofax exposes a batch as an XML, and DBLite is basically a wrapper for said XML. The structure is explained in AcBatch.htm and AcDocs.htm (to be found under the CaptureSV directory). Here's the basic idea (just documents are shown):
AscentCaptureRuntime
Batch
Documents
Document
For a standard server installation, the file would be located here: \\servername\CaptureSV\AcBatch.htm. A single document has child elements itself such as index fields, and multiple properties such as Confidence, FormTypeName, and PDFGenerationFileName.
Here's how to extract the elements from the active batch (your IBatch instance) as well as accessing all batch fields:
var runtime = activeBatch.ExtractRuntimeACDataElement(0);
var batch = runtime.FindChildElementByName("Batch");
foreach (IACDataElement item in batch.FindChildElementByName("BatchFields").FindChildElementsByName("BatchField"))
{
}
The same is true for index fields. However, as those reside on document level, you would need to drill down to the Documents element first, and then retrieve all Document children. The following example accesses all index fields as well, storing them in a dictionary named IndexFields:
var documents = batch.FindChildElementByName("Documents").FindChildElementsByName("Document");
var indexFields = DocumendocumentstData.FindChildElementByName("IndexFields").FindChildElementsByName("IndexField");
foreach (IACDataElement indexField in indexFields)
{
IndexFields.Add(indexField["Name"], indexField["Value"]);
}
With regard to Batch Variables such as {Scan Operator's User ID}, I am not sure. Worst case scenario is to assign them as default values to index or batch fields.

get old item name for renamed files using TFS API

My current tfs will be retired in next few months.I am using tfs api to create a parallel tfs on a new server from the existing one. I have folders and solutions that have been renamed. I am iterating items and based on their changetype(add, edit, delete, sourcerename etc), I am checking them in destination tfs.
I am not able to get Old filename for a file, in order to use PendRename when the item that is being iterated is Delete|SourceRename or Rename.
I tried the mentioned solution :
https://social.msdn.microsoft.com/Forums/vstudio/en-US/f9c7e7b4-b05f-4d3e-b8ea-cfbd316ef737/how-to-get-previous-path-of-renamedmoved-of-file-using-tfs-api?forum=tfsgeneral
But, my changeset has a lot of changes and hence identifying a particular file seems difficult.
Do we have something that interraltes two items (the deleted and renamed) ones other than the changeset, because there needs to be a uniquely identifier that associated the two items so that they may appear together in TFS history?
I read this at someplace and modified it for my purpose so that I can get parent branch for a given server item :
ItemSpec itemSpec = new ItemSpec(serverItem, RecursionType.None);
BranchHistoryTreeItem[][] results = sourceTFSHelper.VCS.GetBranchHistory(
new ItemSpec[] { itemSpec }, VersionSpec.Latest);
BranchHistoryTreeItem[] thisBranchResults = results[0];
foreach (BranchHistoryTreeItem treeItem in thisBranchResults)
{
BranchRelative requestedItem = FindRequestedItem(treeItem);
if (requestedItem != null)
{
return (requestedItem.BranchFromItem == null) ? null : requestedItem.BranchFromItem.ServerItem;
}
}
The support from TFS API can be definitely improved here. For the solution, you will have to look for the associated Delete change instance which is stored in the MergeSources container.
Below I pasted some sample code by which hopefully you will be inspired.
var changeInstances = VersionControlSvr.GetChangesForChangeset(
%YourChangesetId%,
false,
Int32.MaxValue,
null,
null,
true);
foreach (Change changeInstance in changeInstances)
{
Console.WriteLine(changeInstance);
//if (changeInstance.MergeSources != null && changeInstance.MergeSources.Count > 0)
//{
// var source = changeInstance.MergeSources.FirstOrDefault();
// Console.WriteLine($"{changeInstance.Item.ServerItem}");
// Console.WriteLine("was renamed from:");
// Console.WriteLine($"{source.ServerItem}");
// Console.WriteLine("::::::::::::::::::::::::::::::::::::::::::::::::::::::");
//}
}

Identify If User is Group using the client object model

I have a sharepoint field in a list that can be either a user or a group. Using the Server Object Model, I can identify easily whether the user is a group or not.
However, I cannot find a way to achieve this using the Managed Client Object model. Is there a way to know.
I only managed to make it work by looping the list of groups and checking if the there is a group with the name. Howver, this is not exactly correct or efficient. Maybe there is a way to find out using the ListItem of the user. But I did not see any fields that show that user is administrator. I have also tried EnsureUser. This crashes if the user is not a group. So I could work out by using a try/catch but this would be very bad programming.
Thanks,
Joseph
To do this get the list of users from ClientContext.Current.Web.SiteUserInfoList and then check the ContentType of each item that is returned to determine what it is.
Checking the content type is not very direct though, because all you actually get back from each item is a ContentTypeID, which you then have to look-up against the content types of the user list at ClientContext.Current.Web.SiteUserInfoList.ContentTypes. That look-up will return a ContentType object, and you can read from the Name property of that object to see what the list item is.
So an over simplified chunk of code to do this would be:
using Microsoft.SharePoint.Client;
...
ClientContext context = ClientContext.Current;
var q = from i in context.Web.SiteUserInfoList.GetItems(new CamlQuery()) select i;
IEnumerable<ListItem> Items = context.LoadQuery(q);
context.ExecuteQueryAsync((s, e) => {
foreach (ListItem i in Items) {
//This is the important bit:
ContentType contenttype = context.Web.SiteUserInfoList.ContentTypes.GetById(i["ContentTypeId"].ToString());
context.Load(contenttype); //It's another query so we have to load it too
switch (contenttype.Name) {
case "SharePointGroup":
//It's a SharePoint group
break;
case "Person":
//It's a user
break;
case "DomainGroup":
//It's an Active Directory Group or Membership Role
break;
default:
//It's a mystery;
break;
}
}
},
(s, e) => { /* Query failed */ }
);
You didn't specify your platform, but I did all of this in Silverlight using the SharePoint client object model. It stands to reason that the same would be possible in JavaScript as well.
Try Microsoft.SharePoint.Client.Utilities.Utility.SearchPrincipals(...):
var resultPrincipals = Utility.SearchPrincipals(clientContext, clientContext.Web, searchString, PrincipalType.All, PrincipalSource.All, null, maxResults);
The return type, PrincipalInfo, conveniently has a PrincipalType property which you can check for Group.

SPQuery and RowLimit

I have around 10000+ rows(Listitems) in a list I want to query.
I want to iterate each of the item in a timerJob - but I cant take all of them at a time
since : Object Model Override - NO, ListView threshold - 1000 - in the FARM level and i we cant change this.
What is the way for me to iterate all the 10000+ (like a batch) ??
You should use a ContentIterator. This will allow you to iterate over the contents of very large lists without triggering an SPQueryThrottledException.
For example:
SPList list = SPContext.Current.Web.Lists["MyList"];
// Build query using an iterator-defined WHERE clause
string query = string.Format("<Where><Eq><FieldRef Name='MyFieldName'/><Value Type='Text'>MyFieldValue</Value></Eq></Where>{0}", ContentIterator.ItemEnumerationOrderByNVPField);
// Instantiate iterator and use it to process the list
ContentIterator iterator = new ContentIterator();
iterator.ProcessListItems(list, query, ProcessListItem, ProcessListItemError);
Then you'd define your ProcessListItem and ProcessListItemError thusly:
static void ProcessListItem(SPListItem item) {
Console.WriteLine("ProcessListItem: Name {0}", item.Title);
}
static bool ProcessListItemError(SPListItem item, Exception e) {
Console.WriteLine("ERROR: message {0}", e.Message);
return true;
}
I'd also recommend you review Microsoft's Best Practices with SharePoint Server articles, in particular "Writing Efficient Code In SharePoint Server", which further discusses properly writing queries.

How do I perform a MOSS FullTextSqlQuery and filter people results by the Skills managed property?

I am having trouble with a MOSS FulltextSqlQuery when attempting to filter People results on the Skills Managed Property using the CONTAINS predicate. Let me demonstrate:
A query with no filters returns the expected result:
SELECT AccountName, Skills
from scope()
where freetext(defaultproperties,'+Bob')
And ("scope" = 'People')
Result
Total Rows: 1
ACCOUNTNAME: MYDOMAIN\Bob
SKILLS: Numchucks | ASP.Net | Application Architecture
But when I append a CONTAINS predicate, I no longer get the expected result:
SELECT AccountName, Skills
from scope()
where freetext(defaultproperties,'+Bob')
And ("scope" = 'People')
And (CONTAINS(Skills, 'Numchucks'))
Result
Total Rows: 0
I do realize I can accomplish this using the SOME ARRAY predicate, but I would like to know why this is not working with the CONTAINS predicate for the Skills property. I have been successful using the CONTAINS predicate with a custom crawled property that is indicated as 'Multi-valued'. The Skills property (though it seems to be multi-valued) is not indicated as such on the Crawled Properties page in the SSP admin site:
http:///ssp/admin/_layouts/schema.aspx?ConsoleView=crawledPropertiesView&category=People
Anyone have any ideas?
So with the help of Mark Cameron (Microsoft SharePoint Developer Support), I figured out that certain managed properties have to be enabled for full text search using the ManagedProperty object model API by setting the FullTextQueriable property to true. Below is the method that solved this issue for me. It could be included in a Console app or as a Farm or Web Application scoped Feature Receiver.
using Microsoft.Office.Server;
using Microsoft.Office.Server.Search.Administration;
private void EnsureFullTextQueriableManagedProperties(ServerContext serverContext)
{
var schema = new Schema(SearchContext.GetContext(serverContext));
var managedProperties = new[] { "SKILLS", "INTERESTS" };
foreach (ManagedProperty managedProperty in schema.AllManagedProperties)
{
if (!managedProperties.Contains(managedProperty.Name.ToUpper()))
continue;
if (managedProperty.FullTextQueriable)
continue;
try
{
managedProperty.FullTextQueriable = true;
managedProperty.Update();
Log.Info(m => m("Successfully set managed property {0} to be FullTextQueriable", managedProperty.Name));
}
catch (Exception e)
{
Log.Error(m => m("Error updating managed property {0}", managedProperty.Name), e);
}
}
}
SELECT AccountName, Skills
from scope()
where freetext(defaultproperties,'+Bob')
And ("scope" = 'People')
And (CONTAINS(Skills, 'Numchucks*'))
use the * in the end.
You also have a few more options to try:
The following list identifies
additional query elements that are
supported only with SQL search syntax
using the FullTextSqlQuery class:
FREETEXT()
CONTAINS()
LIKE
Source

Resources