how to get Hiearchical structure in WIQL workitem - c#

i have a hiearchial strurcture in TFS like this
where a 1 Feature can have 'N' number of Product backlog items and single product Product backlogitem can have 'N' number of task/bugs
tree structure
Feature1->
PB1->
Task1,task2,task3
my Query
string querystring = string.Format("select [System.Id], [System.Title],[Story.Author],[Story.Owner],[System.AssignedTo]," +
" [System.WorkItemType],[Microsoft.VSTS.Scheduling.StoryPoints],[Microsoft.VSTS.Common.Priority]," +
"[Microsoft.VSTS.Scheduling.Effort], [Actual.Effort.Completed]" +
",[System.State]," +
"[System.IterationPath]" +
" FROM WorkItemLinks" +
" WHERE" +
" ([Source].[System.TeamProject]='{0}'" +
" and [Source].[System.IterationPath] UNDER 'MRI_SCRUM_GIT\\Pluse Pheonix\\Sprint 1'" +
" and [Source].[System.WorkitemType]<>'' " +
")" +
" and ([System.Links.LinkType]='System.LinkTypes.Hierarchy-Forward')" +
" and ([Target].[System.WorkItemType] <> '' )" +
" ORDER BY [System.Id] " +
" mode (Recursive)", projectname);
Now how do i get all the fields in C# code like the below image

Here is already a code snippet on the following website:
https://learn.microsoft.com/en-us/vsts/integrate/quickstarts/work-item-quickstart
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi;
using Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models;
using Microsoft.VisualStudio.Services.Common;
using Microsoft.VisualStudio.Services.WebApi.Patch.Json;
using Microsoft.VisualStudio.Services.WebApi.Patch;
using Microsoft.VisualStudio.Services.WebApi;
using System.Net.Http.Headers;
using System.Net.Http;
using Newtonsoft.Json;
public class ExecuteQuery
{
readonly string _uri;
readonly string _personalAccessToken;
readonly string _project;
/// <summary>
/// Constructor. Manually set values to match your account.
/// </summary>
public ExecuteQuery()
{
_uri = "https://accountname.visualstudio.com";
_personalAccessToken = "personal access token";
_project = "project name";
}
/// <summary>
/// Execute a WIQL query to return a list of bugs using the .NET client library
/// </summary>
/// <returns>List of Microsoft.TeamFoundation.WorkItemTracking.WebApi.Models.WorkItem</returns>
public List<WorkItem> RunGetBugsQueryUsingClientLib()
{
Uri uri = new Uri(_uri);
string personalAccessToken = _personalAccessToken;
string project = _project;
VssBasicCredential credentials = new VssBasicCredential("", _personalAccessToken);
//create a wiql object and build our query
Wiql wiql = new Wiql()
{
Query = "Select [State], [Title] " +
"From WorkItems " +
"Where [Work Item Type] = 'Bug' " +
"And [System.TeamProject] = '" + project + "' " +
"And [System.State] <> 'Closed' " +
"Order By [State] Asc, [Changed Date] Desc"
};
//create instance of work item tracking http client
using (WorkItemTrackingHttpClient workItemTrackingHttpClient = new WorkItemTrackingHttpClient(uri, credentials))
{
//execute the query to get the list of work items in the results
WorkItemQueryResult workItemQueryResult = workItemTrackingHttpClient.QueryByWiqlAsync(wiql).Result;
//some error handling
if (workItemQueryResult.WorkItems.Count() != 0)
{
//need to get the list of our work item ids and put them into an array
List<int> list = new List<int>();
foreach (var item in workItemQueryResult.WorkItems)
{
list.Add(item.Id);
}
int[] arr = list.ToArray();
//build a list of the fields we want to see
string[] fields = new string[3];
fields[0] = "System.Id";
fields[1] = "System.Title";
fields[2] = "System.State";
//get work items for the ids found in query
var workItems = workItemTrackingHttpClient.GetWorkItemsAsync(arr, fields, workItemQueryResult.AsOf).Result;
Console.WriteLine("Query Results: {0} items found", workItems.Count);
//loop though work items and write to console
foreach (var workItem in workItems)
{
Console.WriteLine("{0} {1} {2}", workItem.Id, workItem.Fields["System.Title"], workItem.Fields["System.State"]);
}
return workItems;
}
return null;
}
}
}

Related

Concat without blank in C# Linq

I am concatenating different Address fields in my LINQ Query to get one Address with merge.
public static IList GetOfferList()
{
using (var objEntity = new dbContext())
{
string[] ListCategoryID = CategoryID.Split(',');
return (from TBL.OfferMaster
select new
{
PrimaryID = OM.OfferID,
Address = OM.StreetAddress + " ," + OM.City + " ," + OM.State + " ," + OM.Country + " ," + OM.ZipCode,
}).ToList();
}
}
Currently i get fields like
Address=Fákafen 11 ,Reykjavik , ,Iceland ,108,
Or
Address: " , , , ,",;
I want
Address=Fákafen 11 ,Reykjavik ,Iceland ,108
means blank fields not required.
I would do this.
Address = string.Join(" ," (new string[] {OM.StreetAddress, OM.City, OM.State, OM.Country, OM.ZipCode})
.Where(x=> !string.IsNullOrEmpty(x)));
Use this:
var results = (from TBL.OfferMaster
select new
{
PrimaryID = OM.OfferID,
Address = String.Join(", ", (new string[] { OM.StreetAddress, OM.City, OM.State, OM.Country, OM.ZipCode })
.Where(x => !String.IsNullOrWhiteSpace(x))),
}).ToList();

Merge 2 XML Files Into Same Elements C#

I need to create a WebService that takes the name of a city as input and returns Location, Country and Weather information of the City. The thing is that the ID, Location, Country is in one XML file and all weather details in another.
<City>
<ID>city1</ID>
<Grid_ref>NG 895608</Grid_ref>
<Name>Berlin</Name>
<Country>Germany</Country>
</City>
<cityWeather>
<ID>city1</ID>
<temperature>20</temperature>
<wind>2</wind>
</cityWeather>
Using c# is it possible to merge everything into 1 file using ID or is there some other way I can do it? I would then search the XML file once, as having 2 different files mixes me up.
You can use DataSet. I suppose you have two XML files. CityWeather.xml et City.xml, you can make this
try
{
XmlTextReader xmlreader1 = new XmlTextReader("C:\\Books1.xml");
XmlTextReader xmlreader2 = new XmlTextReader("C:\\Books2.xml");
DataSet ds = new DataSet();
ds.ReadXml(xmlreader1);
DataSet ds2 = new DataSet();
ds2.ReadXml(xmlreader2);
ds.Merge(ds2);
ds.WriteXml("C:\\Books.xml");
Console.WriteLine("Completed merging XML documents");
}
catch (System.Exception ex)
{
Console.Write(ex.Message);
}
Console.Read();
You can make any changes that meet your need
hope it helps
Use add
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string cityXML =
"<Root>" +
"<City>" +
"<ID>city1</ID>" +
"<Grid_ref>NG 895608</Grid_ref>" +
"<Name>Berlin</Name>" +
"<Country>Germany</Country>" +
"</City>" +
"<City>" +
"<ID>city2</ID>" +
"<Grid_ref>F 5608</Grid_ref>" +
"<Name>Paris</Name>" +
"<Country>France</Country>" +
"</City>" +
"<City>" +
"<ID>city3</ID>" +
"<Grid_ref>RR 608</Grid_ref>" +
"<Name>Rome</Name>" +
"<Country>Italy</Country>" +
"</City>" +
"</Root>";
XElement cities = XElement.Parse(cityXML);
string weatherXML =
"<Root>" +
"<cityWeather>" +
"<ID>city1</ID>" +
"<temperature>20</temperature>" +
"<wind>2</wind>" +
"</cityWeather>" +
"<cityWeather>" +
"<ID>city2</ID>" +
"<temperature>30</temperature>" +
"<wind>3</wind>" +
"</cityWeather>" +
"<cityWeather>" +
"<ID>city3</ID>" +
"<temperature>40</temperature>" +
"<wind>4</wind>" +
"</cityWeather>" +
"</Root>";
XElement weather = XElement.Parse(weatherXML);
List<XElement> cityList = cities.Descendants("City").ToList();
foreach(XElement city in cityList)
{
XElement matchedCity = weather.Descendants("cityWeather").Where(x =>
x.Element("ID").Value == city.Element("ID").Value).FirstOrDefault();
if(matchedCity != null) city.Add(matchedCity);
}
}
}
}
​

Entity Framework not writing to Database

I'm trying to take a JSON response, deserialize it, and store in a localdb. Everything is working, but its not writing the data to my database. I can't seem to figure out why its not as I'm not getting any errors.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using DataFetcher.DataFieldsInClasses;
using DataFetcher.EF_Models;
using Newtonsoft.Json;
namespace DataFetcher
{
class Program
{
static void Main(string[] args)
{
var teamNames = new TeamsList();
teamNames.teamList.Sort();
for (int i = 0; i < 30; i++)
{
var cities = teamNames.teamList.ElementAt(i);
//URL for each indivual team
string URL = #"http://nhlwc.cdnak.neulion.com/fs1/nhl/league/teamroster/" + cities + "/iphone/clubroster.json";
WebRequest wrGETURL;
wrGETURL = WebRequest.Create(URL);
HttpWebResponse response = wrGETURL.GetResponse() as HttpWebResponse;
StreamReader responseStream = new StreamReader(response.GetResponseStream());
var result = responseStream.ReadToEnd();
//var parsedInformation = JsonConvert.DeserializeObject<RootObject>(result);
foreach (var forwardData in JsonConvert.DeserializeObject<RootObject>(result).forwards)
{
//test output
Console.WriteLine(forwardData.id + " " + " " + forwardData.position + " " + forwardData.name + " " + forwardData.twitterURL + " " + forwardData.height + " " + forwardData.birthdate);
//write to database using EF
using (var _temp_Player = new DataFetcherDBEntities())
{
//var players = _temp_Player.Set<Player>();
_temp_Player.Players.Attach(new Player
{
player_id = forwardData.id,
name = forwardData.name,
age = forwardData.age,
birthdate = forwardData.birthdate,
birthplace = forwardData.birthplace,
weight = forwardData.weight,
height = forwardData.height,
number = forwardData.number,
position = forwardData.position,
imageUrl = forwardData.imageUrl,
twitterURL = forwardData.twitterURL,
twitterHandle = forwardData.twitterHandle
});
_temp_Player.SaveChanges();
}
}
}
Console.ReadKey();
}
}
}
Any tips/ideas?
P.S I'm still learning and self-taught.
*Edit, I copied the localdb to "...DataFetcher\bin\Debug\Databases" and my new error is ""Violation of PRIMARY KEY constraint 'PK__tmp_ms_x__44DA120C6655986D'. Cannot insert duplicate key in object 'dbo.Player'. The duplicate key value is (8473492).\r\nThe statement has been terminated."}"
Which doesn't make sense to me as every player has a unique ID (player_id = forwardData.id)
You need to use _temp_Player.Players.Add instead of Attach.
When you Attach, you need to set the entity state for the EF to detect that it is a new record and insert it into the database during Save Changes.

Pass multiple data from one function to label in C#

I have a function that retrieves multiple lines of data and I want to display them in a label. My function is as shown below.
public static string GetItemByQuery(IAmazonSimpleDB simpleDBClient, string domainName)
{
SelectResponse response = simpleDBClient.Select(new SelectRequest()
{
SelectExpression = "Select * from " + domainName
});
String res = domainName + " has: ";
foreach (Item item in response.Items)
{
res = item.Name + ": ";
foreach (Amazon.SimpleDB.Model.Attribute attribute in item.Attributes)
{
res += "{" + attribute.Name + ", " + attribute.Value + "}, ";
}
res = res.Remove(res.Length - 2);
}
return res;
}
So far I can only return a string which is the last line of the retrieved data. How can I retrieve all the records? I tries arraylist, but it seems that the AWS web application doesn't allow me to use arraylist. Can anyone please help me to solve this??
Return it as as a Enumberable,
List<String> Results ;
Your method would be
public static List<String> GetItemByQuery(IAmazonSimpleDB simpleDBClient, string domainName)
{
List<String> Results = null;
SelectResponse response = simpleDBClient.Select(new SelectRequest()
{
SelectExpression = "Select * from " + domainName
});
String res = domainName + " has: ";
foreach (Item item in response.Items)
{
Results = new List<String>();
res = item.Name + ": ";
foreach (Amazon.SimpleDB.Model.Attribute attribute in item.Attributes)
{
res += "{" + attribute.Name + ", " + attribute.Value + "}, ";
}
res = res.Remove(res.Length - 2);
Results.Add(res);
}
return Results;
}

How do you display items from a list in a message box?

I am working on a project that needs to display a list of people that have above average income. The source data is a List<IncomeData> (id is the unique id for the person):
public struct IncomeData
{
public string id;
public double household;
public income;
}
public double belowAverage = 0, total, belowAveragePercent;
IncomeData surveyStruct;
List<IncomeData> surveyList = new List<IncomeData>();
List<string> aboveAverage = new List<string>();
Here is how I determine if a person has above average income. If a person has above average income, I add the id and income from the temporary instance of the surveyStruct to the above average list of string values:
//Determine poverty.
if (surveyStruct.income - 3480 * surveyStruct.household <= 6730)
{
belowAverage += 1;
}
else if (surveyStruct.income - 3480 * surveyStruct.household >= 6730)
{
aboveAverage.Add(surveyStruct.id);
aboveAverage.Add(surveyStruct.income.ToString());
}
And here is the code that displays the desired information in a message box. (The aboveAverage list is added in here, too.)
private void reportsToolStripMenuItem_Click(object sender, EventArgs e)
{
//Display reports 1, 2, and 3.
MessageBox.Show("Your Entry:\nID Code: " + surveyStruct.id +
"\nHousehold: " + surveyStruct.household.ToString() +
" people\nIncome: " + surveyStruct.income.ToString("C") +
"\n\nPeople Above Average:\n" + aboveAverage +
"\n\nAnd " + belowAveragePercent + "% of people are below average.");
}
Now, here's the problem: Instead of a seeing a list of values in the message box, I am seeing System.Collections.Generic.List`1[System.String] where the IDs and incomes of the above average people should be. Can somebody please tell me what I am doing wrong and how I can display a list values in a message box?
At the end of your question you ask: How I can display a List<IncomeData> in a message box?
So, the core of your question is converting your list of values to a string so that you can pass that string as an argument to MessageBox.Show().
The LINQ Extension Method Enumerable.Aggregate() offers an ideal solution for this problem. Say your List<IncomeData> looks something like this (I've omitted the household field for brevity):
var incomes = new List<IncomeData>() {
new IncomeData("abc0123", 15500),
new IncomeData("def4567", 12300),
new IncomeData("ghi8901", 17100)
};
The following LINQ query will convert that List<IncomeData> into a string:
string message = incomes.
Select(inc => inc.ToString()).
Aggregate((buffer, next) => buffer + "\n" + next.ToString());
To eliminate the need to call Select(), you can instead use the two-argument version of Enumerable.Aggregate(). This approach also allows you to specify a heading as the seed value for your accumulator:
string message2 = incomes.
Aggregate(
"Income data per person:",
(buffer, next) => buffer + "\n" + next.ToString());
That is equivalent to the following where the argument types have been made explicit:
string message = incomes.
Aggregate<IncomeData, string>(
"Income data per person:",
(string buffer, IncomeData next) => buffer + "\n" + next.ToString());
See the following (and online demo) for a complete working example preceded by its expected output.
Expected Output
Income data per person:
Id: abc0123, Income:15500
Id: def4567, Income:12300
Id: ghi8901, Income:17100
Demonstration Program
using System;
using System.Collections.Generic;
using System.Linq;
namespace LinqAggregateDemo
{
public class Program
{
public static void Main(string[] args)
{
var incomes = new List<IncomeData>() {
new IncomeData("abc0123", 15500),
new IncomeData("def4567", 12300),
new IncomeData("ghi8901", 17100)
};
string message = incomes.
Select(inc => inc.ToString()).
Aggregate((buffer, next) => buffer + "\n" + next.ToString());
Console.WriteLine("Income data per person:\n" + message);
}
public struct IncomeData
{
public readonly string Id;
public readonly int Income;
public IncomeData(string id, int income)
{
this.Id = id;
this.Income = income;
}
public override string ToString()
{
return String.Format(
"Id: {0}, Income:{1}",
this.Id,
this.Income);
}
}
}
}
First, make aboveAverage a List<IncomeData>, and add the IncomeDatas that match into that list.
Then, you need to define a ToString for your custom struct, something like this:
public override void string ToString()
{
return string.Format("The id is {0}, the household is {1} and the income is {2}.", id, household, income);
}
Then, in your MessageBox.Show call, you need to replace aboveAverage with
aboveAverage.Aggregate((a,b) => a.ToString() + Enviroment.NewLine + b.ToString())
Should make it show properly.
Sorry about the formatting,I'm on mobile.
StringBuilder is one choice:
StringBuilder aboveAverage = new StringBuilder();
//Determine poverty.
if (surveyStruct.income - 3480 * surveyStruct.household <= 6730)
{
belowAverage += 1;
}
else if (surveyStruct.income - 3480 * surveyStruct.household >= 6730)
{
aboveAverage.Append(string.Format("id: %s, income: %s\n",
surveyStruct.id, surveyStruct.income.ToString());
}
And you will need a ToString() for the string builder, like this:
MessageBox.Show("Your Entry:\nID Code: " + surveyStruct.id + "\nHousehold: " + surveyStruct.household.ToString() + " people\nIncome: " + surveyStruct.income.ToString("C") + "\n\nPeople Above Average:\n" + aboveAverage.ToString() + "\n\nAnd " + belowAveragePercent + "% of people are below average.");
You could do it with join if you leave aboveAverage as a list, like this:
string.Join(aboveAverage,Environment.NewLine);
In your current code -- but that would not look so nice.
You could also do it with Linq, you want to see that?
Ok, here is a sexy one line version: (all questions should have a one line linq answer):
(the using and indent don't count, they are just there to make the code more readable!)
using NL = Environment.NewLine;
    
string indent = "    ";
MessageBox.Show(
"Your Entry:" + NL +
"ID Code: " + surveyStruct.id + NL +
"Household: " + surveyStruct.household.ToString() + " people" + NL +
"Income: " + surveyStruct.income.ToString("C") + NL + NL +
"People Above Average:" + NL +
indent + string.Join(NL+indent,
surveyList.Where(s => (s.income - 3480) * s.household >= 6730)
.Select(s => "ID: "+s.id+" $"+s.income.ToString).ToArray()) + NL +
"And " + (surveyList.Where(s => ((s.income - 3480) * s.household) <= 6730).Count() / surveyList.Count()) * 100 + "% of people are below average.");

Categories

Resources