Похоже, что поведение не изменилось и для TFS 2013. Я столкнулся с точно такой же проблемой, и это то, что я нашел с помощью инструмента разборки и немного удачи.
Каждый тип ссылки реализует метод Equals
по-своему. Насколько я могу судить, это комбинация внутренних полей, которая однозначно идентифицирует объект ссылки. Для Гиперссылки важен только целевой путь.
* * * * * RelatedLink
здесь особенный. Прежде всего, его метод Equals
сравнивает несколько внутренних полей, в частности, идентификатор источника и идентификатор цели.
Когда вы только что создали объект RelatedLink
, его целевой идентификатор указывает на null
. И это имеет смысл - вы не добавили ссылку на рабочий элемент и не знаете, с чем это связано.
Теперь во второй строке вашего кода вы вызываете метод Contains
, и он возвращает false
. Всегда false
для вновь созданной ссылки! Это связано с тем, что в методе Contains
реализован способ вызова метода Equals
, который сравнивает связанные ссылки по идентификатору источника и идентификатору цели. Но идентификатор цели ВСЕГДА null
для связанной ссылки, которая только что создана. С другой стороны, целевой идентификатор каждого отдельного объекта в коллекции workItem.Links
никогда не равен null
.
Следовательно, метод Contains
в этом случае бесполезен. В итоге я нашел уродливый обходной путь, но, по крайней мере, он не требует поддержки внешней коллекции с идентификаторами:
RelatedLink newLink = new RelatedLink(linkTypeEnd, id);
if (workItem.Links.Cast<Link>().FirstOrDefault(l => l.GetType() == typeof(RelatedLink) && ((RelatedLink)l).RelatedWorkItemId == relatedLink.RelatedWorkItemId) == null)
//if (workItem.Links.Contains(newLink))
return;
workItem.Links.Add(newLink);
Итак, вместо того, чтобы полагаться на метод Contains
, я проверяю данные, которые могут быть идентичными и могут привести к явной ошибке duplicate relation
.
P.S. Я понимаю, что получение ответа через 3 года не имеет значения. Надеемся, что это может помочь другим, кто переносит рабочие элементы из «хорошо известных систем» в TFS:)