How to get ALL fields of a WorkItem? - c#

I'm trying to retrieve the Risks field from the tabs in TFS, however, when I print all the Fields, I can't see the Risks .
I've tried accessing it directly via WorkItem.Fields["FieldName"] butno luck.
Any ideas?

You can use WIQL Queries to get the values of all fields. Here is a list of all Work item field index . Below is a sample with how to get all work items and all fields for a particular project:
using Microsoft.TeamFoundation.WorkItemTracking.Client;
Query query = new Query(
workItemStore,
"select * from issue where System.TeamProject = #project",
new Dictionary<string, string>() { { "project", project.Name } }
);
var workItemCollection = query.RunQuery();
foreach(var workItem in workItemCollection)
{
/*Get work item properties you are interested in*/
foreach(var field in workItem.Fields)
{
/*Get field value*/
info += String.Format("Field name: {0} Value: {1}\n", field.name, field.Value);
}
}

I am a bit late, I guess, but since it might still help somebody, I'm going to post this anyways. Even if you haven't specified, if you're in the frontend or backend.
tl;dr: try to omit the fields parameter in the request.
Background: I wanted to provide more workitem-details in the pull requests details-view, so I created a userscript for TamperMonkey. That means I don't have "direct" access to TFS, since I am only accessing the frontend via JavaScript.
Like you, I also noticed that TFS doesn't output all fields. To solve that, I then modified the TFS ajax request with jQuery to omit the fields-parameter. Then TFS started returning all existing fields for the work item.
I found the info in the TFS documentation for work-items
fields (string)
A comma-separated list of up to 100 fields to get with each work item.
If not specified, all fields are returned.
In case that actually is your use-case, I am also providing the script that I wrote to modify the ajax request:
// by Joel Richard -> http://stackoverflow.com/a/26849194/4524280
function parseParams(str) {
return str.split('&').reduce(function (params, param) {
var paramSplit = param.split('=').map(function (value) {
return decodeURIComponent(value.replace('+', ' '));
});
params[paramSplit[0]] = paramSplit[1];
return params;
}, {});
}
$.ajaxPrefilter(function( options, originalOptions, jqXHR ) {
// Modify ajax request to return all fields... definitely not a hack :D
if(options && options.url && options.url.indexOf('_apis/wit/workItems') >= 0) {
var parsedData = parseParams(options.data);
delete parsedData.fields;
options.data = $.param(parsedData);
}
});
$(document).ajaxComplete(function(event, request, settings) {
// trigger after ajax is complete to get values
if(settings && settings.url && settings.url.indexOf('_apis/wit/workItems') >= 0 && request.responseJSON) {
var workItemsData = request.responseJSON.value;
// -> workItemsData.fields contains all existing fields
}
});
Just for the protocol: I don't think anyone should use $.ajaxPrefilter in "normal" use-cases, but in this case, I didn't have much options available.

Related

Redis Optimization with .NET, and a concrete example of How to Store and get an element from Hash

I have more than 15000 POCO elements stored in a Redis List. I'm using ServiceStack in order to save and get them. However, I'm not pleased about the response times that I have when I get them into a grid. As I read , it would be better to store these object in hash - but unfortunately I could not find any good example for my case :(
This is the method I use, in order to get them into my grid
public IEnumerable<BookingRequestGridViewModel> GetAll()
{
try
{
var redisManager = new RedisManagerPool(Global.RedisConnector);
using (var redis = redisManager.GetClient())
{
var redisEntities = redis.As<BookingRequestModel>();
var result =redisEntities.Lists["BookingRequests"].GetAll().Select(z=> new BookingRequestGridViewModel
{
CreatedDate =z.CreatedDate,
DropOffBranchName =z.DropOffBranch !=null ? z.DropOffBranch.Name : string.Empty,
DropOffDate =z.DropOffDate,
DropOffLocationName = z.DropOffLocation != null ? z.DropOffLocation.Name : string.Empty,
Id =z.Id.Value,
Number =z.Number,
PickupBranchName =z.PickUpBranch !=null ? z.PickUpBranch.Name :string.Empty,
PickUpDate =z.PickUpDate,
PickupLocationName = z.PickUpLocation != null ? z.PickUpLocation.Name : string.Empty
}).OrderBy(z=>z.Id);
return result;
}
}
catch (Exception ex)
{
return null;
}
}
Note that I use redisEntities.Lists["BookingRequests"].GetAll() which is causing performance issues (I would like to use just redisEntities.Lists["BookingRequests"] but I lose last updates from grid - after editing)
I would like to know if saving them into list is a good approach as for me it's very important to have a fast grid (I have now 1 second at paging which is huge).
Please, advice!
Firstly you should not create a new Redis Client Manager like RedisManagerPool instance each time, there should only be a singleton instance of RedisManagerPool in your App which all clients are resolved from.
But otherwise I would rethink your data access strategy, downloading 15K items in a batch is not an ideal strategy. You can create indexes by storing ids in Sets or you could store items in a sorted set with a value that you can page against like an incrementing id, e.g:
var redisEntities = redis.As<BookingRequestModel>();
var bookings = redisEntities.SortedSets["bookings"];
foreach (var item in new BookingRequestModel[0])
{
redisEntities.AddItemToSortedSet(bookings, item, item.Id);
}
That way you will be able to fetch them in batches, e.g:
var batch = bookings.GetRangeByLowestScore(fromId, toId, skip, take);

Documentdb stored proc cross partition query

I have a stored procedure which gives me a document count (count.js on github). I have partitioned my collection. Due to this, I now have to pass the partition key in as an option to run the stored procedure.
Can and how should I enable crosspartition queries in the stored procedure (ie, collection(EnableCrossPartitionQuery = true)) so that I don't have to specify the partition key?
There is no way to do fan-out stored procedure execution in DocumentDB. The run against a single partition. I ran into this dilemma when trying to switch to partitioned collections and had to make some adjustments. Here are some options:
Download a 1 for every record and sum/count them client-side
Rerun the stored procedure for each unique partition key. In my case, this was not as bad as it sounds since the partition key is a tenantID and I only have a dozen of those and only expect a few hundred max.
I'm not sure about this one since I haven't tried it with partitioned collections, but each query now returns the resource usage of the collection in the x-ms-resource-usage header. That header has a documentsSize sub-header. You could use that divided by the average size of your documents to get an approximate count. There may even be a count record in that header information by now.
Also, there is an x-ms-item-count header but I'm not sure how that behaves. If you send a query for all the records in the entire partitioned collection and set the max-item-count to 1, you'll only get back one record and it shouldn't cost you a lot in RUs, but I don't know how that header behaves. Does it return a 1 in that case? Or does it return the total number of documents all the pages of the query would eventually return if you bothered to request every page. A quick experiment should confirm this.
Below you can find some example code that should allow you to read all records cross partion. The magic is inside the doForAll function, and at the top you can see how it is called.
// SAMPLE STORED PROCEDURE
function sample(prefix) {
var share = { counter: 0, hasEntityName : 0, isXXX: 0, partitions: {}, prefix };
doForAll({
filter: function limiter(record){
if (record && record.entityName === 'XXX') return true;
else return false;
},
callback: function handleRecord(record) {
//Keep track of this partition...
let partitionKey = record.partitionKey;
if (share.partitions[partitionKey])
share.partitions[partitionKey]++;
else
share.partitions[partitionKey] = 1;
//update some counters...
share.counter++;
if (record.entityName !== undefined) share.hasEntityName++;
if (record.entityName === 'XXX') share.isXXX++;
},
finaly: function whenAllIsDone() {
console.log("counter = " + share.counter + ". ");
console.log("has entity name: "+ share.hasEntityName+ ". ")
console.log("is XXX: " + share.isXXX+ ". ")
var parts = Object.getOwnPropertyNames(share.partitions)
console.log("partition keys: " + parts.length + " ...");
getContext()
.getResponse()
.setBody(share);
}
});
//The magic function...
//also see: https://azure.github.io/azure-cosmosdb-js-server/Collection.html
function doForAll(task, ctoken) {
if (!task) throw "Expected one parameter of type: { filter?: (rec?)=>boolean, callback?: (rec?) => void, finaly?: () => void }";
//Note:
//the "__" symbol is an alias for var collection = getContext().getCollection(); = aliased by __
var result = getContext()
.getCollection()
.chain()
.filter(task.filter || function (rec) { return true; })
.map(task.callback || function (rec) { return undefined; })
.value({ continuation: ctoken }, function afterBatchCallback (err, feed, options) {
if (err) throw err;
if (options.continuation)
doForAll(task, options.continuation);
else if (task.finaly)
task.finaly();
});
if (!result.isAccepted)
throw "catastrophic failure";
}
}
PS: it may to know how the data looks like that is used for the example.
This is an example of such a document:
{
"id": "123",
"partitionKey": "PART_1",
"entityName": "EXAMPLE_ENTITY",
"veryInterestingInfo": "The 'id' property is also the collections id, the 'partitionKey' property happens to be the collections partition key, and all the records in this collection have a 'entityName' property which contains a (non-unique) string"
}

Using the Rally REST API, how to query and return a *complete* JSON object?

I'm using the .NET API. By complete, I mean a JSON like this one (formatted already, I think it is needed credentials to see it inside the webservice).
It is just a matter of adding more fields to fetch when I instantiate the Request object?
Request storyRequest = new Request("hierarchicalrequirement")
{
/* Fields to Fetch*/
Fetch = new List<string>() { "Name", "FormattedID", "Children", "Owner", "ScheduleState" },
// keep adding field here...
/* Add a query - quering the US with ID equals to '_formattedID'*/
Query = new Query("FormattedID", Query.Operator.Equals, _formattedID)
};
Thanks in advance!
EDIT
I would like to query by the user story ID, just in case it is not clear.
When building a request, you should filter the field you want to fetch in the Fetch property.
The keys:
_rallyAPIMajor
_rallyAPIMinor
_ref
_objectVersion
_refObjectName
Are always return by any request. You can leave the Fetch empty, and return all 45 keys (45 for "hierarchicalrequirement") or you can filter the ones you need.

Newbie performance issue with foreach ...need advice

This section simply reads from an excel spreadsheet. This part works fine with no performance issues.
IEnumerable<ImportViewModel> so=data.Select(row=>new ImportViewModel{
PersonId=(row.Field<string>("person_id")),
ValidationResult = ""
}).ToList();
Before I pass to a View I want to set ValidationResult so I have this piece of code. If I comment this out the model is passed to the view quickly. When I use the foreach it will take over a minute. If I hardcode a value for item.PersonId then it runs quickly. I know I'm doing something wrong, just not sure where to start and what the best practice is that I should be following.
foreach (var item in so)
{
if (db.Entity.Any(w => w.ID == item.PersonId))
{
item.ValidationResult = "Successful";
}
else
{
item.ValidationResult = "Error: ";
}
}
return View(so.ToList());
You are now performing a database call per item in your list. This is really hard on your database and thus your performance. Try to itterate trough your excel result, gather all users and select them in one query. Make a list from this query result (else the query call is performed every time you access the list). Then perform a match between the result list and your excel.
You need to do something like this :
var ids = so.Select(i=>i.PersonId).Distinct().ToList();
// Hitting Database just for this time to get all Users Ids
var usersIds = db.Entity.Where(u=>ids.Contains(u.ID)).Select(u=>u.ID).ToList();
foreach (var item in so)
{
if (usersIds.Contains(item.PersonId))
{
item.ValidationResult = "Successful";
}
else
{
item.ValidationResult = "Error: ";
}
}
return View(so.ToList());

Solrnet: problem when search field value is query operator (eq. or, and)

To be more precise I will be working with example...
Clean query is: (type:77 AND (zipCode:12345 OR name:OR))
When querying on Solr Admin page this throws exception:
org.apache.lucene.queryParser.ParseException: Cannot parse...
So on Solr Admin page I changed query to:
(type:"77" AND (zipCode:"12345" OR name:"OR"))
which worked as a charm
Now I have a problem to do the same stuff with solrnet. I am using SolrQueryByField class for querying. When I am working with
new SolrQueryByField("name", "OR")
I get Solrnet.Exceptions.InvalidFieldException which is in accordance with Solr Admin page, but when I am working with
new SolrQueryByField("name", "\"OR\"")
I get wrong results. By inspecting network traffic I found out that http get request is different (for brevity only name field name and value are given):
name%3A%22OR%22 => from Solr Admin page
name%3a%5c%22OR%5c%22 => from solrnet
My question is: what sholud I do to prevent solrnet from adding %5C (backslash) to query string?
Thanks in advance
SolrQueryByField produces quoted/escaped values. If you have some special case where this is not desirable (such as this case) you can use SolrQuery, e.g. :
Query.Field("type").Is(77) && (Query.Field("zipCode").Is("12345") || Query.Simple("name:\"OR\""))
Please try to pass the string array that contains multiple field names and search text in the below method. It will return the solrnet query for search with multiple filed name with OR condition.
public ISolrQuery BuildQuery(string[] SearchFields, string SearchText)
{
try
{
AbstractSolrQuery firstQuery = new SolrQueryByField(SearchFields[0], SearchText) { Quoted = false };
for (var i = 1; i < parameters.SearchFields.Length; i++)
{
firstQuery = firstQuery || new SolrQueryByField(SearchFields[i], SearchText) { Quoted = false };
}
return firstQuery;
}

Categories

Resources