Подтвердить что ты не робот

С# Использование .Select и .Where в одном заявлении LINQ

Мне нужно собрать Distinct Id из конкретной таблицы, используя LINQ. Уловка также нужна инструкция WHERE, которая должна фильтровать результаты, основанные только на требованиях, которые я задал. Относительно новичок в использовании LINQ, но я использую следующий код более или менее:

`private void WriteStuff(SqlHelper db, EmployeeHelper emp)
    {
        String checkFieldChange;
        AnIList tableClass = new AnIList(db, (int)emp.PersonId);
        var linq = tableClass.Items
            .Where(x => x.UserId == emp.UserId && x.Date > DateBeforeChanges && x.Date < DateAfterEffective && ((x.Field == Inserted)
                || (x.Field == Deleted)))

)).OrderByDescending(x => x.Id);
        if (linq != null)
        {
            foreach (TableClassChanges item in linq)
            {
                    AnotherIList payTxn = new AnotherIList(db, item.Id);
                    checkFieldChange = GetChangeType(item.FieldName);
                    //Other codes that will retrieve data from each item and write it into a text file
            }
        }
    }

Я попытался добавить .Distinct для var linq, но он все равно возвращает повторяющиеся элементы (имея в виду один и тот же идентификатор). Я прочитал множество сайтов и попробовал добавить .Select в запрос, но предложение .Where прерывается. Существуют и другие статьи, где запрос каким-то образом отличается тем, как он извлекает значения и помещает их в переменную. Я также пытался использовать .GroupBy, но я получаю "По крайней мере, один объект должен реализовать IComparable" при использовании Id в качестве ключа.

На самом деле запрос работает, и я могу выводить данные из столбцов с требуемыми спецификациями, но я просто не могу сделать .Distinct work (что единственное, что действительно отсутствует). Я попытался создать два vars с одним запуском отдельного вызова, а затем вложенным foreach, чтобы гарантировать, что значения просто уникальны, но тысячи записей для сбора влияния на производительность просто слишком много.

Я тоже не уверен, если мне придется переопределить или использовать IEnumerable для моего требования, и я подумал, что задаю вопрос на всякий случай, если будет более простой способ, или если возможно иметь оба. Выбрать и. Где работает только одно утверждение?

4b9b3361

Ответ 1

Чтобы Enumerable.Distinct работать для вашего типа, вы можете реализовать IEquatable<T> и предоставить подходящие определения для Equals и GetHashCode, иначе это будет использовать реализацию по умолчанию: сравнение для ссылочного равенства (при условии, что вы используете ссылочный тип).

Из руководства:

Метод Distinct (IEnumerable) возвращает неупорядоченную последовательность, которая не содержит повторяющихся значений. Для сравнения значений используется сопоставление по умолчанию для сравнения по умолчанию, по умолчанию.

По умолчанию сопоставление по умолчанию используется по умолчанию для сравнения значений типов, реализующих общий интерфейс IEquatable. Чтобы сравнить пользовательский тип данных, вам необходимо реализовать этот интерфейс и предоставить свои собственные методы GetHashCode и Equals для типа.

В вашем случае похоже, что вам просто нужно сравнить идентификаторы, но вы также можете сравнить другие поля также в зависимости от того, что это означает для вас, что два объекта "одинаковы".

Вы также можете использовать DistinctBy из morelinq.

Обратите внимание, что это LINQ только для объектов, но я предполагаю, что вы используете.

Еще один вариант - объединить GroupBy и First:

 var query = // your query here...
    .GroupBy(x => x.Id)
    .Select(g => g.First());

Это также работает, например, в LINQ to SQL.

Ответ 2

Вы добавили Select() после Where() или раньше?

Вы должны добавить его после, из-за логики concurrency:

 1 Take the entire table  
 2 Filter it accordingly  
 3 Select only the ID  
 4 Make them distinct.  

Если вы сделаете выбор сначала, предложение Where может содержать только атрибут ID, потому что все остальные атрибуты уже отредактированы.

Обновление: для ясности этот порядок операторов должен работать:

db.Items.Where(x=> x.userid == user_ID).Select(x=>x.Id).Distinct();

Возможно, нужно добавить .toList() в конце, но необязательно:)

Ответ 3

Пропустили ли вы IEqualityComparer<T> до .Distinct()?

Что-то вроде этого:

internal abstract class BaseComparer<T> : IEqualityComparer<T> {
    public bool Equals(T x, T y) {
        return GetHashCode(x) == GetHashCode(y);
    }

    public abstract int GetHashCode(T obj);
}

internal class DetailComparer : BaseComparer<StyleFeatureItem> {
    public override int GetHashCode(MyClass obj) {
        return obj.ID.GetHashCode();
    }
}

Использование:

list.Distinct(new DetailComparer())

Ответ 4

Поскольку вы пытаетесь сравнить два разных объекта, вам нужно сначала реализовать интерфейс IEqualityComparer. Вот пример кода в простом консольном приложении, которое использует различную и простую реализацию IEqualityComparer:

 class Program
{
    static void Main(string[] args)
    {
        List<Test> testData = new List<Test>()
        {
            new Test(1,"Test"),
            new Test(2, "Test"),
            new Test(2, "Test")
        };

        var result = testData.Where(x => x.Id > 1).Distinct(new MyComparer());
    }
}

public class MyComparer : IEqualityComparer<Test>
{
    public bool Equals(Test x, Test y)
    {
        return x.Id == y.Id;
    }

    public int GetHashCode(Test obj)
    {
        return string.Format("{0}{1}", obj.Id, obj.Name).GetHashCode();
    }
}


public class Test
{
    public Test(int id, string name)
    {
        this.id = id;
        this.name = name;
    }

    private int id;

    public int Id
    {
        get { return id; }
        set { id = value; }
    }
    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

Я надеюсь, что это поможет.