I am using below flat query to get bug details for array of work item ids passed as argument.
Below query works perfectly fine, but it throws error in some cases "TF26180: An item with this ID already exists in the input Array"
Reason is, ids array has duplicate ids, which is expected in my case. Is there any way to ignore this check or by pass this ?
var flatQuery = new Query(_store, detailsWiql.ToString(), ids);
WorkItemCollection workitems = flatQuery.RunQuery();
foreach (WorkItem wi in workitems)
{
WorkItemType worktype = wi.Type;
worktypename = worktype.Name;
}
Thanks in advance
I don't think we can ignore or by pass this check, the exception is defined in Microsoft.TeamFoundation.WorkItemTracking.Common assembly. See https://www.powershellgallery.com/packages/PSPlus.Tfs/0.0.1.104/Content/Microsoft.TeamFoundation.WorkItemTracking.Common.xml
There is a doubt here, why you have duplicated work items?
Generally, the work item ID is unique in TFS server.
I suggest you delete the duplicated work items first, backup them if needed, then create new work items to track the related tasks/features.
UPDATE:
As a workaround, you can try using the WIQL query with REST API to get the IDs first, See A flat query. The write code to serach work item details with ID in loop. See Get a workitem with REST API.
Besides, you can have a try with the Wiql Editor, it can query the basic work item information directly.
I had a similar issue, so when I was creating the ids array, I just ensured it was distinct:
// Capture ids of results in an array
var ids = (from WorkItemLinkInfo info in result select info.TargetId).Distinct().ToArray();
// Query a list of WorkItem IDs we want more info about
wiql = #"SELECT * FROM WorkItems";
q = new Query(App.workItemStore, wiql, ids);
var workItems = q.RunQuery();
Related
I have a plannerTask and in its Details it has a CheckList. I use it to programatically insert CheckListItems in it, and it all works like a charm when inserting or retrieving the tasks.
My problem arrives when I am going to insert a new CheckListItem and the CheckList already has 20 items. It returns a MaximumChecklistItemsOnTask (because it is forbidden to insert more than 20 items in a check list).
Solution could be to remove the oldest item, but I am not able to do it. I have tried this:
var elementToRemove = oldDetails.Checklist.Where(c => c.Value.IsChecked).OrderBy(c => c.Value.LastModifiedDateTime).First();
oldDetails.Checklist = oldDetails.Checklist.Where(c => c.Value.LastModifiedDateTime <> elementToRemove.Value.LastModifiedDateTime);
But it throws a casting error in the second line:
Unable to cast object of type
'WhereEnumerableIterator1[System.Collections.Generic.KeyValuePair2[System.String,Microsoft.Graph.PlannerChecklistItem]]'
to type 'Microsoft.Graph.PlannerChecklistItems'.
Which is the right way to remove the oldest element from the ChecklistItem?
UPDATE:
In first place I retrieve a plannerTask from the server. Then I get the details from this plannerTask. So oldDetails is a plannertaskdetails object (https://learn.microsoft.com/en-us/graph/api/resources/plannertaskdetails?view=graph-rest-1.0). Inside the plannertaskdetails object (oldDetails), I have the plannerchecklistitems object (oldDetails.Checklist): https://learn.microsoft.com/en-us/graph/api/resources/plannerchecklistitems?view=graph-rest-1.0.
If plannerchecklistitems were just a List, it would be as easy as list.Remove(item), but it is not a normal list, and that is why I am not able to remove the item.
UPDATE 2:
I have found this way to remove the item from oldDetails:
oldDetails.Checklist.AdditionalData.Remove(elementToRemove.Key)
But, the the way I send the changes to the server is this:
await graphClient.Planner.Tasks(plannerTask.Id).Details.Request().Header("If-Match", oldDetails.GetEtag).UpdateAsync(newDetails)
As it is a PATCH request (not a PUT one), I only have in newDetails the records that have changed, it is, the new records. How could I specify there that a record has been deleted from the list? Sorry if my English is not good enough to express myself properly, but what I mean is that newDetails is not the full list, it only contains the records that must be added and I do not know how to specify in that request that one record must be deleted.
I have next situation and I am stack.
I am using Microsoft.TeamFoundation classes to get workitems from stored query with c#. I know server name, project name and stored query name. So I can execute stored query and receive all WorkItems.
But than I have to create a direct link to this item. According to the documentation, this link should be like
http:// ServerName:8080/tfs/CollectionName/ProjectName/_workitems/edit/Id
So, before executing query I know ServerName, ProjectName and work item's Id. But I cant find ProjectName anywhere.
So my question is. How, knowing ServerName, ProjectName, WorkItemId and Stored Query name get CollectionName?
Or. How to create link to the work item knowing ItemsId?
P.S. GetArtifactUrl is not the right way.
Thanks for help!
Afraid there is no such API to achieve this. However, as a workaround, you can list all collection's name through client API such as below:
Uri configurationServerUri = new Uri(URL);
TfsConfigurationServer configurationServer = TfsConfigurationServerFactory.GetConfigurationServer(configurationServerUri);
ITeamProjectCollectionService tpcService = configurationServer.GetService<ITeamProjectCollectionService>();
foreach (TeamProjectCollection tpc in tpcService.GetCollections())
{
ListCollection.Add(tpc.Name);
}
More ways for your reference:
How to get all collections from TFS
Retrieve the List of Team Project Collections from TFS 2010 Client APIs
Hopefully the title says it all. I've retrieved the results of adhoc queries using the WorkItemStore.Query() method and created Query objects via the new syntax. However after examining the object model for Query objects, QueryFolders, QueryItems and the WorkItemStore I can't find a way to create and save a WIQL query to the store/TFS Server.
Any suggestions?
You can use QueryHierarchy.Save Method to save the query. For example:
QueryDefinition query = new QueryDefinition("My Query", "Select * from WorkItems Where [System.AssignedTo] = #me", parentFolder);
myproject.QueryHierarchy.Save();
Check blog for more information: http://blogs.msdn.com/b/team_foundation/archive/2010/06/16/work-item-tracking-queries-object-model-in-2010.aspx
I am writing a tool that needs to access all the revisions of a TFS workitem template.
The Workitem has a Revisons collection, and Rev property that returns the number of revisions.
When I try and do a foreach through the collection, even though it contains 6 "entries" in my test workitem, the collection is empty.
To work around this I am using the GetWorkItem(WorkItemID, RevisionID), incrementing the revision ID in a for loop to get the revisions. It seems crazy taht I have to do this and there collection that doesn't contain what it is supposed to.
Am I missing something here, or is this simply a bug in the TFS client API.
After much digging, it is quite clear to me now that if you want to get all the revisions of a work item, you must explicitly load the revision(2) that you want, and this makes the revisions collection pretty much useless.
Depending on how your retrieving the work item it may only be partially loaded. Try calling the Open method on the work item before accessing the Revisions collection.
Where are you getting the workitem? I know when I was getting version history of files with sourceControl.QueryHistory I had to set one of my parameters (bool include Changes) to true in order to get the changes in the changeset.
I'm using the Microsoft.TeamFoundation.Controls.PickWorkItemsControl to select the work items I need. After that the revsionsCollectoin is compleet. Maybe this helps:
// select the workitems using the picker
ArrayList workItems = _workItemPicker.Control.SelectedWorkItems();
// after that use a foreach and output all history included in each revision
private void PrintHistory(WorkItem workitem)
{
RevisionCollection revisions = workitem.Revisions;
foreach (Revision revision in revisions)
{
String history = (String) revision.Fields["History"].Value;
Console.WriteLine("**** Revision {0}", revision.Fields["Title"], revision.Fields["Changed Date"]);
foreach (Field field in revision.Fields)
{
Console.WriteLine("* field {0}:{1} ", field.Name, field.Value);
}
Console.WriteLine("****");
Console.WriteLine();
}
}
I have coded three select statements in stored procedure in Microsoft SQL Server 2005. Both select statements return multiple number of records and table list for select statements is different. One select records from a master table and the other from a child table. In C# code I want to get all these records and put all the data in one object. I am using SqlDataReader. Is it possible with it or should i do something else.
You use the NextResult method on the datareader to navigate with multiple results from a query.
To loop through all data you would do something like this:
var moreResults = true;
while (moreResults)
{
while (reader.Read())
{
...
}
moreResults = reader.NextResult();
}
So with that as a background, and assuming the master resultset comes first, populating master and detail objects could be done like this:
First, build up a dictionary of the Master records:
var masters = new Dictionary<int, Master>();
var idOrdinal = reader.GetOrdinal("id");
while (reader.Read())
{
var id = reader.GetInt32(idOrdinal);
masters.Add(id, new Master{Id=id, ....});
}
Next, move on to detail records and add those to their corresponding master:
reader.NextResult();
var masterIdOrdinal = reader.GetOrdinal("masterId");
while (reader.Read())
{
var masterId = reader.GetInt32(masterIdOrdinal);
var master = masters[masterId];
master.Details.Add(new Detail{....});
}
You should obviously replace column names with what you have in your data as well as supply the full initialization of Master and Detail objects.
If the detail resultset is sorted on master id, the last loop could be optimized to only lookup each master once from the dictionary. If the resultsets are small though, the gain would not be that huge.
...one select records from master table
and other from child table .in c# code
i want to get all this record and put
all this data in one object...
Peter's solution works to solve the basic problem of retrieving multiple results with a single DataReader. However, If you want to save your data to an object which replicates the relationship between the Master-Details tables, you should be using a DataSet instead.
DataSets can contain multiple DataTables and provide full support for inherent relationships between the tables by allowing creation of DataRelations between the tables. Then you can get related records for each scenario by calling GetChildRows() or GetParentRows() from the Master or Details tables respectively.
There are probably many samples online that illustrate how to do this. Here's one discussion thread from my Group where I have listed the steps and provided some code to demonstrate the procedure.