Запрос LINQ возвращает дубликат, несмотря на Distinct ()

У меня есть следующий запрос, который привязывается к DropDownList;

if (!Page.IsPostBack)
        {
            var branchTags =
                (
                    from t in context.ContactSet
                    orderby t.py3_BranchArea
                    where t.py3_BranchArea != null
                    select new
                    {
                        BranchTagCode = t.py3_BranchArea,
                        BranchTag = (t.FormattedValues != null && t.FormattedValues.Contains("py3_brancharea") ? t.FormattedValues["py3_brancharea"] : null)
                    }
                ).Distinct();
            ddlBranchTags.DataSource = branchTags;
            ddlBranchTags.DataBind();
        }

По какой-то причине мы все еще помещаем 2 строки, которые визуально совпадают. Возможно, в CRM есть два объекта с одинаковым именем. Но, если я использую отдельный в запросе и возвращаю только py3_brancharea, тогда, конечно, Distinct должен запускаться на фактических возвращенных записях?

Итак, это наводит на мысль - и мои ограниченные знания LINQ - что это из-за строки:

BranchTagCode = t.py3_BranchArea

Но это необходимо вызвать, чтобы можно было вызвать FormattedValues.

Как тогда мне получить отчетливый набор результатов, основанный исключительно на BranchTag?


person Phill Healey    schedule 30.04.2013    source источник


Ответы (6)


Если Distinct() не работает, возможно, проблема связана с методами переопределения конкретных классов gethashcode() или equals(), которые либо настроены неправильно, либо полностью опущены. В настраиваемом классе вам, скорее всего, потребуется указать эти переопределения, чтобы Distinct() и другие подобные методы работали правильно.

Вы также можете попытаться использовать предложение where или любое другое, чтобы различать дубликаты. Что может быть решением проблемы Distinct().

Чтобы подробнее объяснить, как настроить метод Distinct() с пользовательскими классами. Вам нужно будет внутри класса, который вы ищете, установить методы переопределения GetHashCode() и Equals(). Эти методы или методы уровня объекта, которые должны быть в каждом отдельном классе, несмотря ни на что. Чтобы начать, перейдите к соответствующему классу и введите следующее:

public override bool Equals(object obj), затем public override int GetHashCode()

Допустим, у вас есть этот простой класс до переопределений:

class foo{
   int H {get;set;}
   public foo(int _h){
        H = _h;
   }
}

Теперь это будет выглядеть так:

class foo{
   int H {get;set;}
   int K {get;set;}

   public override bool Equals(object obj){
         if(obj == null) return false;
         foo test = (foo)obj);
         if(test == null) return false;
         
         if(this.H == obj.H && this.K == obj.K) return true;
   }
   public override int GetHashCode(){
         int hashH = H.GetHashCode();
         int hashK = K.GetHashCode();

         return hashH ^ hashK;
   }

   public foo(int _h){
        H = _h;
   }
}

Теперь вы можете использовать Distinct() для Ienumerable типов, содержащих класс foo, вот так:

 List<foo> FooList = new List<foo>(Collection of 9 Foos);
 var res = FooList.Distinct();
person Nomad101    schedule 30.04.2013
comment
Есть шанс привести пример. Я новичок в LINQ и в настоящее время борюсь с этой проблемой. Спасибо. - person Phill Healey; 30.04.2013

Другой, гораздо более простой способ, который сработал для меня, но может работать не во всех ситуациях, - это использовать этот метод ребят (GroupBy() и First()):

Поиск отдельных элементов в списке

Он создает List<Customer> customers с FirstName и LastName. Затем группирует их все по FirstName и берет первый элемент из каждой группы!

`
List< Customer > customers = new List< Customer >;
{
    new Customer {FirstName = "John", LastName = "Doe"},
    new Customer {FirstName = "Jane", LastName = "Doe"},
    new Customer {FirstName = "John", LastName = "Doe"},
    new Customer {FirstName = "Jay",  LastName = null},
    new Customer {FirstName = "Jay",  LastName = "Doe"}
};
`

Потом:

`
var distinctCustomers = customers.GroupBy(s => s.FirstName)
                                 .Select(s => s.First());
`

В моей ситуации мне пришлось использовать FirstOrDefault().

person hvaughan3    schedule 28.11.2014

Возможно ли, что два результата разные, имеют ли они одинаковый код тега ветвления и тег ветки?

Вы могли бы реализовать собственный компаратор равенства и передать его в отличную (), чтобы он сравнивал только нужное вам поле? это немного сложнее из-за анонимного типа в вашем операторе select, но этот ответ имеет способ вокруг этого.

person Matt    schedule 30.04.2013
comment
Да, я верю, что это так. Вот почему я написал. Надеюсь найти способ сделать отличное только на втором поле. Ссылка выглядит так, как будто у нее есть потенциал. Спасибо. - person Phill Healey; 30.04.2013
comment
На самом деле, эта ссылка, к сожалению, не работает. Также при проверке в CRM поля не дублируются. Так что не знаю, как я могу выделить по результатам. - person Phill Healey; 30.04.2013
comment
Не могли бы вы предоставить больше кода, чтобы дать нам пример, демонстрирующий проблему? Какие результаты вызывают проблему? Сможете ли вы воспроизвести это, если замените контекст сущности простым списком, содержащим два объекта, являющихся проблемой? - person Matt; 01.05.2013
comment
В основном это список региональных офисов и их соответствующие идентификаторы в CRM. По какой-то причине в одной из веток есть другой экземпляр с отдельным идентификатором, но с тем же именем. На самом деле я не вижу эту другую ветку в CRM, поэтому она выглядит как какая-то реликвия, привязанная к чьей-то учетной записи. Таким образом, хотя все возвращенные идентификаторы веток различны, их имена совпадают. Мне нужно удалить этот лишний, но я не хочу его жестко кодировать (например, удалить его вручную). - person Phill Healey; 01.05.2013
comment
Вы имеете в виду, что BranchTagCodes разные, но BranchTags одинаковы для двух результатов? - person Matt; 01.05.2013
comment
Это означает, что отдельный вызов выполняется правильно, два результата различаются. Вы можете реализовать компаратор проверки на равенство, который смотрит только на BranchTags, но при этом выбирает одну из записей, а другой BranchTagCode отбрасывает. Вы должны решить, какой из них оставить ... - person Matt; 02.05.2013
comment
Честно говоря, я сказал это в своем ОП. Об этом и был мой пост. - person Phill Healey; 02.05.2013
comment
Да, хорошо, поэтому вам нужно создать реализацию IEqualityComparer, которая выбирает правильный BranchTagCode. Учитывая 2 записи с одинаковым BranchTag, выберите правильную. Какой из них вам подходит? - person Matt; 02.05.2013

Сравнение равенства по умолчанию для анонимных типов чувствительно к регистру. У возвращаемых значений, которые вы ожидаете, другой регистр? Как предположил Мэтт, в противном случае вы можете захотеть взглянуть на настраиваемую реализацию IEqualityComparer в настраиваемом классе.

person Darren Lewis    schedule 30.04.2013
comment
Тот же корпус, поэтому не знаю, почему это может вызвать проблему. - person Phill Healey; 30.04.2013

Я изменил свой код с

.Distinct().ToList();

to

.ToList().Distinct().ToList();

и теперь можно избежать дублирования. Не уверен, в чем причина.

person TPG    schedule 09.04.2019

Другая возможность заключается в том, что объект Entity имеет ключ определения, который не является уникальным.

person roncansan    schedule 03.10.2019