CAML Query - Delete 1 Item - sharepoint

CAMLQuery: "<Query><Where><And><Eq><FieldRef Name='Item' />
<Value Type='Lookup'>" + itemid + "</Value></Eq><Eq>
<FieldRef Name='Author' /><Value Type='Integer'>
<UserID /></Value></Eq></And></Where><OrderBy>
<FieldRef Name='ID' Ascending='FALSE' /></OrderBy>
<RowLimit>1</RowLimit></Query>",
My issue is that it is delete multiple rows and not just one
All help appreicated

In the end I had to do quite a horrible workaround:
function DeleteItem(itemid) {
$().SPServices({
operation: "GetListItems",
async: false,
webURL: "MYURL",
listName: "Basket",
CAMLViewFields: "<ViewFields><FieldRef Name='Title' /><FieldRef Name='Item' /> <FieldRef Name='Item:Title' /></ViewFields>",
CAMLQuery: "<Query><Where><And><Eq><FieldRef Name='Item' /><Value Type='Lookup'>" + itemid + "</Value></Eq><Eq><FieldRef Name='Author' /><Value Type='Integer'><UserID /></Value></Eq></And></Where><OrderBy><FieldRef Name='ID' Ascending='FALSE' /></OrderBy></Query>",
completefunc: function (xData, Status) {
$(xData.responseXML).SPFilterNode("z:row").each(function() {
alert($(this).attr("ows_ID"));
$().SPServices.SPUpdateMultipleListItems({
listName: "Basket",
webURL: "MYURL",
CAMLRowLimit: 1,
CAMLQuery: "<Query><Where><Eq><FieldRef Name='ID' /><Value Type='Counter'>" + $(this).attr("ows_ID") + "</Value></Eq></Where></Query>",
batchCmd: "Delete",
completefunc: function(xData, Status) {
CountItems();
ViewBasket();
CreateSuccess('Item deleted');
if (event.preventDefault) { event.preventDefault(); } else { event.returnValue = false; } // Stop the form acting like it normally would (refreshing the page)
}});
return false;
});
}
});
return true;
}
Basically I had to do a get all items lookup, look through each one, delete it on the ID and break the loop after the first iteration. Horrible workaround but couldn't think of another way to do it.

Your question is not clear. What are you trying to achieve? GetListItems is to get the list items, not to delete. So if you want to delete items with a WHERE clause you have to call GetListItems first, and then call UpdateListItems in providing the ID of the items you want to delete. Is your "itemit" passed to DeleteItems will return only ONE record from the Basket list?
Your code should look like that :
function DeleteItem(itemid) {
$().SPServices({
operation: "GetListItems",
async: true, /* don't use FALSE ! */
webURL: "MYURL",
listName: "Basket",
CAMLViewFields: "<ViewFields><FieldRef Name='ID' /><FieldRef Name='Title' /><FieldRef Name='Item' /><FieldRef Name='Item:Title' /></ViewFields>",
CAMLQuery: "<Query><Where><And><Eq><FieldRef Name='Item' /><Value Type='Lookup'>" + itemid + "</Value></Eq><Eq><FieldRef Name='Author' /><Value Type='Integer'><UserID /></Value></Eq></And></Where><OrderBy><FieldRef Name='ID' Ascending='FALSE' /></OrderBy></Query>",
completefunc: function (xData, Status) {
// use `.eq(0)` to look at the first one only
$(xData.responseXML).SPFilterNode("z:row").eq(0).each(function() {
alert($(this).attr("ows_ID"));
var ID = $(this).attr("ows_ID");
// now delete it with `UpdateListItems`
$().SPServices({
operation: "UpdateListItems",
webURL: "MYURL",
listName: "Basket",
updates: '<Batch OnError="Continue" ListVersion="1" ViewName=""><Method ID="1" Cmd="Delete"><Field Name='ID'>"+ID+"</Field></Method></Batch>',
completefunc: function (xData, Status) {
alert("OK")
}
});
})
}
})
}
FYI I've created a library that is easier to use: http://aymkdn.github.io/SharepointPlus/
For your code it will look like :
function DeleteItem(itemid) {
// here I suppose that `itemid` will return only one record
$SP().list("Basket").remove({
where:"Item = '"+itemid+"'",
success:function() { alert("Done!") }
})
}

Related

CAML to search for pages returns all files and folders in a site

I am trying to write a simple web part for Sharepoint 2013 that searches for all pages of a certain content type and outputs a list of their titles. I am using a CAML query to search for that. But no matter what query, the result I have is just a list of all files and folders in this Sharepoint site.
Finally, I reduced the CAML query to a simple "find everything that starts with the letter T", but still the result is outputting all files and folders in the root level of the site.
What am I doing wrong?
protected override void CreateChildControls()
{
Label label1 = new Label();
try
{
SPQuery query = new SPQuery();
query.Query = #"<Query>
<Where>
<BeginsWith>
<FieldRef Name='Title'></FieldRef>
<Value Type='Text'>T</Value>
</BeginsWith>
</Where>
</Query>";
using (SPSite site = new SPSite("https://xxxxxx/sites/xxxxx/en/xxxx/"))
{
using (SPWeb web = site.OpenWeb())
{
PublishingWeb pubweb = PublishingWeb.GetPublishingWeb(web);
PublishingPageCollection collection = pubweb.GetPublishingPages(query);
//now output the results of the query
label1.Text = "Items: " + collection.Count.ToString();
for (int i = 0; i < collection.Count; i++)
{
label1.Text += collection[i].Title + "<br>";
}
}
}
}
catch (Exception ex)
{
label1.Text = ex.Message;
}
Controls.Add(label1);
}
Weirdly, you need to do two things:
1) Remove the opening and closing tag;
2) Make sure the query does not start or end with a blank line.
Then the results will change the the correct ones.

Filtering SharePoint ListItems based on Modified By

I am writing custom coding for retrieving SharePoint list items based on modified by field. Can any one tell me how to get on object modeling.The code is like
SPSite objsite = new SPSite("sitename");
SPWeb objweb = objsite.OpenWeb();
SPDocumentLibrary docs = objweb.Lists["Shared Documents"] as SPDocumentLibrary;
Console.WriteLine(docs.ItemCount);`enter code here`
SPQuery query = new SPQuery();
query.Query = #"<where><eq><FieldRef Name='peoplenames' LookupId='TRUE'/><Value Type='User'>1;#1</Value></eq></where>";
query.RowLimit = 5;`enter code here`
SPListItemCollection items = docs.GetItems(query);
if (items.Count == 0)
return;
else
{
foreach (SPListItem item in items)
{
Console.WriteLine(item["peoplenames"]);
}
}
When i am trying to print values it shows exception.
The modified by field internal name is Editor. Your CAML query should be something like this
<Where>
<Contains>
<FieldRef Name='Editor' LookupValue='TRUE' />
<Value Type='Text'>User Display Name</Value>
</Contains>
</Where>

Getting related entity count through FetchXML

I have the following fetchXML code for returning the total number of related entities. Main entity name is new_transaction and related entity name is new_transactionproduct.
The code below is placed in a web resource javascript but when this function is called it never gets to success or error portions, it simply hangs.
function countLineItems()
{
var ID = Xrm.Page.data.entity.getId();
var fetchXml = "<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' aggregate='true'>";
fetchXml += "<entity name='new_transactionproduct'>";
fetchXml += "<attribute name='new_name' alias='recordcount' aggregate='countcolumn' />";
fetchXml += "<filter type='and'>";
fetchXml += "<condition attribute='new_transactionid' operator='eq' value='" + ID + "' />";
fetchXml += "</filter>";
fetchXml += "</entity>";
fetchXml += "</fetch>";
alert(fetchXml);
XrmSvcToolkit.fetch({
fetchXml: fetchXml,
async: false,
successCallback: function (result) {
var countValue = result.entities[0].recordcount;
alert(countValue);
//Xrm.Page.getAttribute(new_totalqty).setValue(countValue);
},
errorCallback: function (error) {
throw error;
}
});
}
Just a quick side note you could always setup your fetchXML like below to minimise the amound of times you append to the string.
string fetchXml = #"<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' aggregate='true'>
<entity name='new_transactionproduct'>
<attribute name='new_name' alias='recordcount' aggregate='countcolumn' />
<filter type='and'>
<condition attribute='new_transactionid' operator='eq' value='" + ID + #"' />
</filter>
</entity>
</fetch>";
XrmSvcToolkit needed to be added as a web resource and referenced on the page.

SPListItemCollection.GetDataTable() doesn't return all columns?

I ran into an issue when using the GetDataTable() method. I'm trying to return the default SharePoint column "FileRef" in my results to use. I include it in my SPQuery.ViewFields
Query:
<Where><IsNotNull><FieldRef Name='FileRef'/></IsNotNull></Where>
ViewFields:
<FieldRef Name='Title' /><FieldRef Name='Category' /><FieldRef Name='FileRef' /><FieldRef Name='ID' /><FieldRef Name='Created' />
I can even see it returned in the items.XML but when I call GetDataTable() it is not put in the datatable.
SPListItemCollection items = list.GetItems(spq);
dtItems = items.GetDataTable();
Why isn't GetDataTable working correctly? Am I going to have to write my own conversion method?
You can use this code:Improving SharePoint's SPListItemCollection GetDataTable(), let's get all the fields I need
I'd recommend you a better solution
As SPListItemCollection has Xml proeprty that stores all item data, you can use this XSLT to get data in normal XML format and then create DataSet from XML.
This Idea can be converted to handy extension function:
using System.Data;
using System.Xml;
using System.Xml.Xsl;
using Microsoft.SharePoint;
namespace Balticovo.SharePoint
{
public static partial class Extensions
{
static string sFromRowsetToRegularXmlXslt =
"<xsl:stylesheet version=\"1.0\" " +
"xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" " +
"xmlns:s=\"uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882\" " +
"xmlns:z=\"#RowsetSchema\">" +
"<s:Schema id=\"RowsetSchema\"/>" +
"<xsl:output method=\"xml\" omit-xml-declaration=\"yes\" />" +
"<xsl:template match=\"/\">" +
"<xsl:text disable-output-escaping=\"yes\"><rows></xsl:text>" +
"<xsl:apply-templates select=\"//z:row\"/>" +
"<xsl:text disable-output-escaping=\"yes\"></rows></xsl:text>" +
"</xsl:template>" +
"<xsl:template match=\"z:row\">" +
"<xsl:text disable-output-escaping=\"yes\"><row></xsl:text>" +
"<xsl:apply-templates select=\"#*\"/>" +
"<xsl:text disable-output-escaping=\"yes\"></row></xsl:text>" +
"</xsl:template>" +
"<xsl:template match=\"#*\">" +
"<xsl:text disable-output-escaping=\"yes\"><</xsl:text>" +
"<xsl:value-of select=\"substring-after(name(), 'ows_')\"/>" +
"<xsl:text disable-output-escaping=\"yes\">></xsl:text>" +
"<xsl:value-of select=\".\"/>" +
"<xsl:text disable-output-escaping=\"yes\"></</xsl:text>" +
"<xsl:value-of select=\"substring-after(name(), 'ows_')\"/>" +
"<xsl:text disable-output-escaping=\"yes\">></xsl:text>" +
"</xsl:template>" +
"</xsl:stylesheet>";
public static DataTable GetFullDataTable(this SPListItemCollection itemCollection)
{
DataSet ds = new DataSet();
string xmlData = ConvertZRowToRegularXml(itemCollection.Xml);
if (string.IsNullOrEmpty(xmlData))
return null;
using (System.IO.StringReader sr = new System.IO.StringReader(xmlData))
{
ds.ReadXml(sr, XmlReadMode.Auto);
if (ds.Tables.Count == 0)
return null;
return ds.Tables[0];
}
}
static string ConvertZRowToRegularXml(string zRowData)
{
XslCompiledTransform transform = new XslCompiledTransform();
XmlDocument tidyXsl = new XmlDocument();
try
{
//Transformer
tidyXsl.LoadXml(Extensions.sFromRowsetToRegularXmlXslt);
transform.Load(tidyXsl);
//output (result) writers
using (System.IO.StringWriter sw = new System.IO.StringWriter())
{
using (XmlTextWriter tw = new XmlTextWriter(sw))
{
//Source (input) readers
using (System.IO.StringReader srZRow = new System.IO.StringReader(zRowData))
{
using (XmlTextReader xtrZRow = new XmlTextReader(srZRow))
{
//Transform
transform.Transform(xtrZRow, null, tw);
return sw.ToString();
}
}
}
}
}
catch
{
return null;
}
}
}
}
By the way, using this method, you will get, if needed, file attachment URL's (SPQuery.IncludeAttachmentUrls = true) not just TRUE/FALSE values as you would get it by using previously mentioned method.
Regarding Janis' answer - I'd remove the bits that do a substring on the ows_ and attempt to remove it, just use:-
"<xsl:value-of select=\"name()\"/>" +
because SP2010 now includes fields such as ETag which don't being with "ows_" and the solution fails. Very good solution otherwise.

CAML query that includes folders in result set

I'm trying to write a CAML query that executes against a specific SPList, scoped to a specific folder, recursive from that point, and returns all ListItems (which meet a criteria) and Folders.
Here's the code for the query which seems like it should work (formatted for readability):
SPQuery query = new SPQuery();
query.Query = "
<Where>
<Or>
<Contains>
<FieldRef Name=\"FileRef\" />
<Value Type=\"Text\">foo</Value>
</Contains>
<Eq>
<FieldRef Name=\"FSObjType\" />
<Value Type=\"Lookup\">1</Value>
</Eq>
</Or>
</Where>";
query.ViewFields = "
<FieldRef Name=\"CustomField1\" Nullable=\"TRUE\" />
<FieldRef Name=\"CustomField2\" Nullable=\"TRUE\" />
<FieldRef Name=\"CustomField3\" Nullable=\"TRUE\" />
";
query.RowLimit = 500;
query.ViewAttributes = "Scope=\"RecursiveAll\"";
query.Folder = startingFolder;
DataTable dt = myList.GetItems(query).GetDataTable();
So - this only returns the ListItems - no folders.
If I remove the other conditions from the query, only leaving the FSObjType=1, I get a COM exception "Cannot complete this action. Please try again."
If I then remove the ViewFields, leaving only the Scope=RecursiveAll and FSObjType=1, I get an empty result set back.
Everyone is close, but not quite right.
using (SPSite site = new SPSite("http://server/site"))
{
SPWeb web = site.RootWeb; // See disposal guidance http://blogs.msdn.com/b/rogerla/archive/2008/10/04/updated-spsite-rootweb-dispose-guidance.aspx
SPQuery query = new SPQuery();
query.Query = #"
<Where>
<BeginsWith>
<FieldRef Name='ContentTypeId' />
<Value Type='ContentTypeId'>0x0120</Value>
</BeginsWith>
</Where>";
query.ViewAttributes = "Scope='RecursiveAll'";
SPList list = web.Lists[listId];
SPListItemCollection items = list.GetItems(query);
// Do stuff with your folders
}
First of all, using this FieldRef is wrong:
<FieldRef Name='ContentType' /><Value Type='Text'>Folder</Value>
because the folder content type can be inherited. Therefore, you need to compare against the content type ID, like this:
<Where>
<BeginsWith>
<FieldRef Name='ContentTypeId' />
<Value Type='ContentTypeId'>0x0120</Value>
</BeginsWith>
</Where>
And then, set the view attribute Scope to RecursiveAll
<View Scope='RecursiveAll'>...</View>
That should return any item whose content type inherits from Folder (0x0120)
I don't have my dev image to test against, so I might need to revise this later; but I think you could try
query.ViewAttributes = "Scope=\"Recursive\"";
Retrieving the items will allow you to use SPUtility.GetUrlDirectory(url) to get the folder path for a given item, and parse the folder hierarchy from there.
You could try basing your caml query on the Folder Content Type instead,
<FieldRef Name='ContentType' /><Value Type='Text'>Folder</Value>
whilst keeping the
Query.ViewAttributes = "Scope=\"RecursiveAll\"";
I've solved this putting:
<QueryOptions>
<IncludeAttachmentUrls>True</IncludeAttachmentUrls>
<Folder/> </QueryOptions>
As query option
I found my question about it on stack overflow:
How can I iterate recursively though a sharepoint list using webservices?
If I remove the other conditions from the query, only leaving the FSObjType=1, I get a COM exception "Cannot complete this action. Please try again."
Did you remove the <Or> tags when you did this? If not it will not run correctly.
Regardless, that does not solve your problem. Have you tried leaving the query empty? Does it return anything?
I have been working on something similar and ran into an issue as well, perhaps it's somewhat related.
This still seems to an issue in SP 2010. Here's workaround code that will work for 2007 or 2010, based on this MSDN Forums post that uses the web services:
private static SPListItem RecurseIntoFolders(SPList list, SPFolder parentFolder, string fileReference)
{
var query = new SPQuery
{
Query = "<Where>" +
"<Eq><FieldRef Name='FSObjType'/><Value Type='Lookup'>1</Value></Eq>" +
"</Where>",
ViewFields = String.Format("<FieldRef Name='{0}' />", FileReferenceInternalFieldName),
ViewAttributes = "Scope='RecursiveAll'",
Folder = parentFolder
};
var items = list.GetItems(query);
if (items.Count == 0)
return null;
foreach (SPListItem item in items)
{
parentFolder = item.Folder;
// TODO: Any other checking that this is the item we want
return item;
}
return RecurseIntoFolders(list, parentFolder, fileReference);
}
static string GetParentFolder(SPListItem itemToFind, SPFolder folder)
{
SPQuery query = new SPQuery();
// query.Query = "<OrderBy><FieldRef Name='Title'/></OrderBy>";
query.Query = "<Where><Eq><FieldRef Name=\"ID\"/><Value Type=\"Integer\">"+ itemToFind.ID +"</Value></Eq></Where>";
query.Folder = folder;
query.ViewAttributes = "Scope=\"Recursive\"";
SPListItemCollection items = itemToFind.ParentList.GetItems(query);
int intpartentFolderID=0 ;
if (items.Count > 0)
{
foreach (SPListItem item in items)
{
SPFile f = item.Web.GetFile(item.Url);
string test11 = f.ParentFolder.Name;
intpartentFolderID = f.ParentFolder.Item.ID;
//string test1 = item.File.ParentFolder.Name;
return (intpartentFolderID.ToString());
}
}
return (intpartentFolderID.ToString());
}

Resources