I create a site collection column that itself has a lookup onto a list inside that site collection. I create this column using CSOM:
string contextUrl = "http://company.example.com/sites/mysite/subsite";
SharePointContext spContext = SharePointContextProvider.Current.GetSharePointContext(HttpContext.Current);
ClientContext clientContext = new ClientContext(contextUrl);
Web web = clientContext.Web;
clientContext.Load(web);
clientContext.ExecuteQuery();
Web rootWeb = clientContext.Site.RootWeb;
clientContext.Load(rootWeb);
// Add List containing target column
ListCreationInformation targetListInfo = new ListCreationInformation();
targetListInfo.Title = "TargetListTitle";
targetListInfo.TemplateType = (int)ListTemplateType.GenericList;
List targetList = web.Lists.Add(targetListInfo);
targetList.Update();
clientContext.Load(targetList);
clientContext.ExecuteQuery();
// Update Title
FieldCollection techListFields = targetList.Fields;
clientContext.Load(techListFields);
clientContext.ExecuteQuery();
// Create Site Lookupcolumns
var techListID = targetList.Id;
FieldCollection colSCFields = rootWeb.Fields;
clientContext.Load(colSCFields);
clientContext.ExecuteQuery();
var lookupSchema = "<Field Type='Lookup' DisplayName='Magic' Required='FALSE' List='" + techListID + "' ShowField='Title' StaticName='Magic' Name='Magic'/>";
colSCFields.AddFieldAsXml(lookupSchema, false, AddFieldOptions.AddFieldInternalNameHint);
clientContext.ExecuteQuery();
(for complete information I added all lines, but the crucial part start below "// Create Site Lookupcolumns")
The site column is being created, but when I use a lookup onto that column on a list inside a sub site (manually or by program) the dropdown from that lookup field does not display any content. (The behavior looks like a lookup column being created before the target column exists)
You need to specify WebId attribute value (set it to subsite ID) in the field xml definition, like this:
var lookupSchema = "<Field Type='Lookup' DisplayName='Magic' Required='FALSE' WebId='" + web.Id + "' List='" + techListID + "' ShowField='Title' StaticName='Magic' Name='Magic'/>";
Related
I have a list called "Books" with columns 'Name','AuthorName','ISBN' with type as text. Now I have another list called "BillTokenStore" and i want to add lookup column 'AuthorName' in "BillTokenStore". Below is what i have done.
using (ClientContext context = new ClientContext(webFullUrl: siteUrl))
{
context.Credentials = new SharePointOnlineCredentials(userName, GetPassWord());
Web web = context.Web;
ListCollection listCollection = web.Lists;
List list = listCollection.GetByTitle("BillTokenStore");
string schemaLookupField = #"<Field Type='Lookup' Name='InStock' StaticName='InStock' DisplayName='InStock' List = 'Books' ShowField = 'Title' /> ";
Field lookupField = list.Fields.AddFieldAsXml(schemaLookupField, true, AddFieldOptions.DefaultValue);
context.ExecuteQuery();
}
When i run this code, i am getting the error "value does not fall within the expected range sharepoint 2013". What is wrong here? Thanks in Advance.
Note: I am able to achieve the same thing thorough UI. I am also able to add other type of fields like choice,boolean and all through code.
You need to explicitly load the list and the fields of that list.
Also, we need to pass the GUID of the lookup column list.
Please try the below modified code:
using (ClientContext context = new ClientContext(webFullUrl: siteUrl))
{
context.Credentials = new SharePointOnlineCredentials(userName, GetPassWord());
Web web = context.Web;
List booksList = context.Web.Lists.GetByTitle("Books");
List list = context.Web.Lists.GetByTitle("BillTokenStore");
context.Load(list, l => l.Fields);
context.Load(booksList, b => b.Id);
context.ExecuteQuery();
string schemaLookupField = #"<Field Type='Lookup' Name='InStock' StaticName='InStock' DisplayName='InStock' List='"+ booksList.Id +"' ShowField = 'Title' />";
Field lookupField = list.Fields.AddFieldAsXml(schemaLookupField, true, AddFieldOptions.DefaultValue);
lookupField.Update();
context.Load(lookupField);
context.ExecuteQuery();
}
I'm trying to filter a SharePoint list so that only the items with the Management field, which holds a string, as "Yes" will show up, but whenever I get to the ctx.ExecuteQuery() statement, my program blows up. I believe my CAMLQuery is structured correctly, so I'm not sure if I'm simply using it wrong or if I'm missing something. Any help would be great! thanks! The code I currently have is posted below:
Web myWeb = ctx.Web;
List myList = myWeb.Lists.GetByTitle("Company Employees");
SPClient.View view = myList.DefaultView;
CamlQuery qry = new CamlQuery();
qry.ViewXml = "<Query>" + "< Where >" + "<Eq>" + "< FieldRef Name='Management'/>" + "< Value Type='Text'>Yes</ Value >" + "</Eq>" + "</ Where >" + "</ Query >";
myList.GetItems(qry);
ListItemCollection listItems = myList.GetItems(qry);
ctx.Load(listItems);
ctx.ExecuteQuery();
Your code appears to be missing the <View> tag which would wrap around your <Query> tag in the CAML.
With the addition of the <View> root element, the correct CAML XML would be as follows:
qry.ViewXml =
"<View>"+
"<Query>"+
"<Where>"+
"<Eq>"+
"<FieldRef Name='Management'/>"+
"<Value Type='Text'>Yes</Value>"+
"</Eq>"+
"</Where>"+
"</Query>"+
"</View>";
Additional Troubleshooting
To help troubleshoot, you can try running the same query through the JavaScript client object model.
Visit the SharePoint site in Internet Explorer and hit F5 to open up the developer tools.
On the Console tab, enter the following lines of code and execute (by pressing Enter or Ctrl+Enter) them one line at a time:
-
var ctx = new SP.ClientContext();
var list = ctx.get_web().get_lists().getByTitle("Company Employees");
var qry = new SP.CamlQuery();
qry.set_viewXml("<View><Query><Where><Eq><FieldRef Name=\"Management\"/><Value Type=\"Text\">Yes</Value></Eq></Where></Query></View>");
var items = list.getItems(qry);
ctx.load(items);
ctx.executeQueryAsync(function(){alert("success!");},function(sender,args){alert(args.get_message());});
POST HELP SOLUTION Thanks to your help, I was able to figure out how to create a new view with the desired filtering by using the following code. The main problem was with the Caml Query--I had to remove the and tags and then delete a few of the lines before creating the view. Below is my working solution:
Web myWeb = ctx.Web;
List myList = myWeb.Lists.GetByTitle("Company Employees");
SPClient.View view = myList.DefaultView;
CamlQuery qry = new CamlQuery();
qry.ViewXml =
"<Where><Eq><FieldRef Name=\"Management\"/><Value Type='Text'>Yes</Value></Eq></Where>";
ViewCollection viewColl = myList.Views;
string[] viewFields = { "Title", "Promoted", "Intern", "Management" };
ViewCreationInformation creationInfo = new ViewCreationInformation();
creationInfo.Title = "Management";
creationInfo.RowLimit = 50;
creationInfo.ViewFields = viewFields;
creationInfo.ViewTypeKind = ViewType.None;
creationInfo.SetAsDefaultView = false;
creationInfo.Query = qry.ViewXml;
viewColl.Add(creationInfo);
ctx.ExecuteQuery();
I'm trying to get Folder object by its path in SharePoint 2010 client application using Client Side Object Model (.Net 4.0).
I need to check whether folder described by 'folderPath' variable exists in the library and then get the Folder object for further operations. To enhance performance, I chose to use CAML query to filter the list.
My code:
IEnumerable<List> library = this.clientContext.LoadQuery(
this.clientContext.Web.Lists.Where(p => p.Title == this.documentLibrary));
this.clientContext.ExecuteQuery();
List libraryList = library.FirstOrDefault();
//code to handle libraryList == null
CamlQuery camlQuery = new CamlQuery();
camlQuery.ViewXml =
"<View Scope=\"RecursiveAll\">" +
"<Query>" +
"<Where>" +
"<And>" +
"<Eq>" +
"<FieldRef Name=\"FSObjType\"/>" +
"<Value Type=\"Integer\">1</Value>" +
"</Eq>" +
"<Eq>" +
"<FieldRef Name=\"FileRef\" />" +
"<Value Type=\"Text\">" + folderPath + "</Value>" +
"</Eq>" +
"</And>" +
"</Where>" +
"</Query>" +
"</View>";
ListItemCollection items = libraryList.GetItems(camlQuery);
clientContext.Load(items);
clientContext.ExecuteQuery();
To this point everything is OK. But I don't have any idea how get the 'Folder' object from an item. I tried to do it in this way:
Folder folder = items.FirtsOrDefault().Folder;
clientContext.Load(folder);
clientContext.ExecuteQuery();
and that way (used instead of last three lines from first code snippet):
ListItemCollection items = libraryList.GetItems(camlQuery);
clientContext.Load(items, collection => collection.Include(item => item.Folder));
clientContext.ExecuteQuery();
But in both cases I got an Exception:
1st: 'Field or property 'Folder' does not exist.'
2nd: 'Column 'Folder' does not exist. It may have been deleted by another user.'
Is there a way to do it? Or maybe I'm doing something wrong? Thanks in advance for the help.
It actually depends on which version of SharePoint is used.
SharePoint 2013
In SharePoint 2013 CSOM ListItem.Folder property gets a folder object that is associated with a folder item.
SharePoint 2010
In SharePoint 2010 CSOM Folder property is not exposed for ListItem object.
The following method could be used for retrieving Folder associated with ListItem:
/// <summary>
/// Get Parent Folder for List Item
/// </summary>
/// <param name="listItem"></param>
/// <returns></returns>
private static Folder GetListItemFolder(ListItem listItem)
{
var folderUrl = (string)listItem["FileDirRef"];
var parentFolder = listItem.ParentList.ParentWeb.GetFolderByServerRelativeUrl(folderUrl);
listItem.Context.Load(parentFolder);
listItem.Context.ExecuteQuery();
return parentFolder;
}
Example:
using (var context = new ClientContext(webUrl))
{
var list = context.Web.Lists.GetByTitle(listTitle);
var items = list.GetItems(CamlQuery.CreateAllItemsQuery());
context.Load(items);
context.ExecuteQuery();
foreach (var item in items)
{
var folder = GetListItemFolder(item); //get Folder
Console.WriteLine(folder.Name);
}
}
I have working code (thank you John Socha-Leialoha) that uses the TFS API to retrieve work items, along with all their linked work items (code below). However, what I'm trying to do is access the names of the linked Files (TFS calls it a "Versioned Item") for each work item. In the TFS GUI you can link a file to a work item. Say Work Item 1234 is linked to file foo.txt. Now when I run this query to find linked items, that file is not in the list - only other children WIs or parent WIs are returned. It's the same result if I create and run the query entirely in the GUI. How can I find out which files are linked to a given WI? The only way I can now is to look at the WI in the TFS GUI, and it shows in the Files list in the lower right.
Perhaps I just need to do a normal flat query, fetch the WI fields, and somehow the names of the linked files would be one of the fields of that WI? I don't need to download the linked file, I just need the filename/location.
Code to return all linked WIs is here:
public List<string> GetLinkedItems()
{
//executes a linked item query, returning work items, as well as the items that are link to them.
//gets digital asset work item that contains the given part number in the Assoc. Parts field
var result = new List<string>();
var tpc = new TfsTeamProjectCollection(new Uri(_tfsUri));
var workItemStore = (WorkItemStore) tpc.GetService(typeof (WorkItemStore));
//and [Schilling.TFS.TechPub.AssocParts] CONTAINS '101-4108'
var query =
"SELECT [System.Id], [System.Links.LinkType], [System.TeamProject]," +
" [System.WorkItemType], [System.Title], [System.AssignedTo]," +
" [System.State] FROM WorkItemLinks " +
" WHERE ([Source].[System.TeamProject] = 'Tech Pubs' AND " +
" [Source].[System.WorkItemType] = 'DigitalAsset' AND " +
" [Source].[System.State] <> '') And " +
" ([System.Links.LinkType] <> '') And " +
" ([Target].[System.WorkItemType] <> '') " +
" ORDER BY [System.Id] mode(MayContain)";
var treeQuery = new Query(workItemStore, query);
//Note we need to call RunLinkQuery here, not RunQuery, because we are doing a link item type of query
var links = treeQuery.RunLinkQuery();
//// Build the list of work items for which we want to retrieve more information//
int[] ids = (from WorkItemLinkInfo info in links
select info.TargetId).Distinct().ToArray();
//
// Next we want to create a new query that will retrieve all the column values from the original query, for
// each of the work item IDs returned by the original query.
//
var detailsWiql = new StringBuilder();
detailsWiql.AppendLine("SELECT");
bool first = true;
foreach (FieldDefinition field in treeQuery.DisplayFieldList)
{
detailsWiql.Append(" ");
if (!first)
detailsWiql.Append(",");
detailsWiql.AppendLine("[" + field.ReferenceName + "]");
first = false;
}
detailsWiql.AppendLine("FROM WorkItems");
//
// Get the work item details
//
var flatQuery = new Query(workItemStore, detailsWiql.ToString(), ids);
WorkItemCollection details = flatQuery.RunQuery();
return
(from WorkItem wi in details
select wi.Id + ", " + wi.Project.Name + ", " + wi.Title + ", " + wi.State).ToList();
}
Work item queries can only show WorkItemLinkType links. To get links of other types (i.e. files in source control), you need to go through the list of links in the WorkItem object itself. Here's a snippet of code that will get you the artifact of the file linked to the work item:
TfsTeamProjectCollection tpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(
new Uri("http://<server>:8080/tfs/<collection>"));
WorkItemStore wiStore = tpc.GetService<WorkItemStore>();
VersionControlServer vc = tpc.GetService<VersionControlServer>();
WorkItem task = wiStore.GetWorkItem(<work item with a linked file>);
var externalLinks = task.Links.OfType<ExternalLink>();
foreach (var link in externalLinks)
{
XmlDocument artifact = vc.ArtifactProvider.GetArtifactDocument(new Uri(link.LinkedArtifactUri));
}
The XML document contains all necessary information needed to grab the correct file version from the VersionControlServer using the GetItem() method.
I need to query a list in SharePoint where the columns may be added in the future.
For instance at the moment I have the following columns
Name, Job, interests, address
I want to be able to query this string dynamically using a parameter from the browser so if columns are added in the future I don’t have to change the code but just the parameter.
The address may look like this www.contoso.com/sites/mypage.aspx?property=Interests
And the code something on the line of this:
var SiteParameter = Request.QueryString["property"];
var ItemsFromList = from item in ListItems where item[try to put the parameter in here] select item;
I use SPmetal to get the list details, so if I press item. Visual Studio2010 will return the columns within the list.
This may be easier without SPMetal.
var qy = new SPQuery();
qy.Query =
"<Where><Eq>" +
"<FieldRef Name=`" + siteParameter + "'/>" +
// You may have to worry about the type of the field here, too.
"<Value Type='Text'>" + desiredValue + "</Value>" +
"</Eq></Where>";
var itemCollection = myList.GetItems(qy);