/// <exception cref="NotSupportedException"><paramref name="workItemType"/> is not assignable to <see cref="IWorkItem"/>.</exception> protected override IEnumerable ExecuteRawQuery(Type workItemType, string queryString) { var workItems = WorkItemStore.Query(queryString); if (typeof(IIdentifiable).IsAssignableFrom(workItemType)) { return(WorkItemMapper.Create(workItemType, workItems)); } throw new NotSupportedException($"Unsupported type for performing relatives aware queries: {workItemType.Name}. To perform relatives aware queries the types involved must inherit from IIdentifiable."); }
private IEnumerable GetRelatives(IEnumerable <IIdentifiable> source, RelativesExpression relativesExpression, Type itemType, DateTime asOf) { var results = Activator .CreateInstance(typeof(List <>) .MakeGenericType(itemType)) as IList; var ids = source.Select(item => item.Id); if (!ids.Any()) { return(results); } var workItemLinks = WorkItemStore.QueryLinks(GetQueryStringForRelativesOf(ids, relativesExpression.AncestorType, relativesExpression.DescendentType, relativesExpression.Direction, asOf)); var map = new Dictionary <int, List <int> >(); workItemLinks.Where(link => link.SourceId == 0).ToList().ForEach(link => map.Add(link.TargetId, new List <int>())); foreach (var ancestorId in map.Keys) { map[ancestorId].AddRange(GetTransitiveLinks(ancestorId, workItemLinks).Select(child => child.TargetId)); } ids = ids.Union(workItemLinks.Select(link => link.SourceId)).Union(workItemLinks.Select(link => link.TargetId)).Where(id => id != 0); var workItems = HydrateAndFilterItems(ids, relativesExpression.AncestorType, relativesExpression.DescendentType, asOf); foreach (var ancestorId in map.Keys) { var id = ancestorId; // Get the ancestor from the list of hydrated work items var ancestorWorkItem = workItems.Single(item => item.Id == ancestorId); // Filter the work items to just those IDs that are in the map for this ancestor. // NOTE: Please note that the strategy is to start with the hydrated work items and filter to // those in the map, and NOT to lookup every work item in the map. The latter strategy would // break because the map also contains the IDs of Task Groups that have been filtered out. // This way we start with work items that we already know exist. var descendentWorkItems = workItems.Where(wi => map[id].Contains(wi.Id)); var ancestor = WorkItemMapper.Create(relativesExpression.AncestorType, new[] { ancestorWorkItem }).Cast <object>().Single(); var descendents = WorkItemMapper.Create(relativesExpression.DescendentType, descendentWorkItems); var properTypedDescendents = GenerateListOfType(descendents, itemType); var result = Activator.CreateInstance(itemType, ancestor, properTypedDescendents); results.Add(result); } return(results); }
public override void Map( Type targetWorkItemType, IEnumerable <KeyValuePair <IWorkItem, IIdentifiable> > workItemMappings, IWorkItemMapper workItemMapper) { var linksLookup = BuildLinksRelationships(targetWorkItemType, workItemMappings); // REVIEW: We don't have any cycle detection, this avoids causing stack overflows in those cases workItemMapper = new WorkItemMapper(workItemMapper.MapperStrategies.Except(new[] { this })); // If there were no items added to the lookup, don't bother querying VSO if (!linksLookup.Any()) { return; } // Load all the items var workItems = Store.Query(linksLookup.SelectMany(p => p.Value).Distinct()) .ToDictionary(k => k.Id, e => e); var idToMapTargetLookup = workItemMappings.ToDictionary(k => k.Key.Id, e => e); var accessor = TypeAccessor.Create(targetWorkItemType, true); // REVIEW: The recursion of links can cause mapping multiple times on the same values // For example, a common ancestor var previouslyMapped = new Dictionary <Tuple <int, RuntimeTypeHandle>, IIdentifiable>(); // Enumerate through items requiring a VSO lookup and map the objects // There are n-passes to map, where n=number of link types foreach (var item in linksLookup) { var sourceWorkItem = idToMapTargetLookup[item.Key.Item1].Key; var targetWorkItem = idToMapTargetLookup[item.Key.Item1].Value; #if DEBUG && TRACE Trace.TraceInformation("{0}: Mapping {1} on {2}", GetType().Name, item.Key.Item2, sourceWorkItem.Id); #endif foreach (var property in PropertiesOnWorkItemCache( _inspector, sourceWorkItem, targetWorkItemType, typeof(WorkItemLinkAttribute))) { var def = PropertyInfoLinkTypeCache(_inspector, property); if (def != null) { var propertyType = def.WorkItemType; var linkType = def.LinkName; var key = new Tuple <int, string>(sourceWorkItem.Id, linkType); List <int> linkIds; if (!linksLookup.TryGetValue(key, out linkIds)) { // Could not find any IDs for the given ID/LinkType continue; } var wi = linkIds // Only get the new items that need to be mapped .Where(p => !previouslyMapped.ContainsKey(new Tuple <int, RuntimeTypeHandle>(p, propertyType.TypeHandle))) .Select( s => { IWorkItem val; workItems.TryGetValue(s, out val); return(val); }).Where(p => p != null) .ToList(); var createdItems = workItemMapper.Create(propertyType, wi).ToList(); // Add the newly created items to the cache // This allows for lazy creation of common parents foreach (var createdItem in createdItems) { var key2 = new Tuple <int, RuntimeTypeHandle>(createdItem.Id, propertyType.TypeHandle); previouslyMapped[key2] = createdItem; } var existing = linkIds // Only get the new items that need to be mapped .Where( p => previouslyMapped.ContainsKey( new Tuple <int, RuntimeTypeHandle>(p, propertyType.TypeHandle))) .Select(s => previouslyMapped[new Tuple <int, RuntimeTypeHandle>(s, propertyType.TypeHandle)]); var allItems = createdItems.Union(existing).ToList(); // REVIEW: These steps are required as the type defined for the link may be different than targetWorkItemType // ReSharper disable SuggestVarOrType_SimpleTypes IList results = (IList)typeof(List <>) // ReSharper restore SuggestVarOrType_SimpleTypes .MakeGenericType(propertyType) .GetConstructor(new[] { typeof(int) }) .Invoke(new object[] { allItems.Count }); foreach (var link in allItems) { results.Add(link); } accessor[targetWorkItem, property.Name] = results; } } } }
protected virtual IEnumerable ExecuteRawQuery(Type workItemType, string queryString) { var workItems = WorkItemStore.Query(queryString); return(WorkItemMapper.Create(workItemType, workItems)); }
public IList Execute() { return(_mapper.Create <MockModel>(_items).ToList()); }
public IEnumerable <MockModel> Generic() { return(_mapper.Create <MockModel>(_item).ToList()); }