在单个LINQ语句中使用.Select和.Where

时间:2012-02-23 09:34:08

标签: c# linq unique distinct

我需要使用LINQ从特定的表中收集Distinct Id。问题是我还需要一个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
        }
    }
}

我尝试为var linq添加.Distinct但它仍然返回重复的项目(意味着具有相同的Id)。我已阅读了很多网站,并尝试在查询中添加.Select,但.Where子句会中断。还有其他一些文章,其中查询与检索值并将其放在var中的方式有​​所不同。我也尝试使用.GroupBy但是当我使用Id作为密钥时,我得到“至少有一个对象必须实现IComparable”。

查询实际上有效,我能够从我需要的规范输出列中的数据,但我似乎无法使.Distinct工作(这是唯一真正缺少的)。我尝试创建两个vars,其中一个触发一个不同的调用,然后有一个嵌套的foreach以确保值只是唯一的,但是收集性能影响的数千条记录太多了。

我不确定是否必须覆盖或使用IEnumerable以满足我的要求,并且我认为我会问这个问题,以防万一有更简单的方法,或者是否可以同时使用这两种方法。选择和。只是在一个声明中工作?

5 个答案:

答案 0 :(得分:35)

您是否在Select()之后或之前添加了Where()

由于并发逻辑,您应该在之后添加它:

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

如果您执行Select,则Where子句只能包含ID属性,因为所有其他属性都已被删除。

更新:为清楚起见,这个运营商的顺序应该有效:

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

可能想在最后添加.toList(),但这是可选的:)

答案 1 :(得分:11)

为了让Enumerable.Distinct适用于您的类型,您可以实施IEquatable<T>并为EqualsGetHashCode提供合适的定义,否则它将使用默认实现:比较参考相等性(假设您使用的是引用类型)。

从手册:

  

Distinct(IEnumerable)方法返回一个不包含重复值的无序序列。它使用默认的相等比较器Default来比较值。

     

默认的相等比较器Default用于比较实现IEquatable泛型接口的类型的值。要比较自定义数据类型,您需要实现此接口并为该类型提供自己的GetHashCode和Equals方法。

在您的情况下,您可能只需要比较ID,但您可能还想比较其他字段,具体取决于两个对象的含义是什么&#34;相同&#34;。< / p>

您还可以考虑使用DistinctBy中的morelinq

请注意,这只是LINQ to Objects,但我认为你正在使用它。

另一个选择是合并GroupByFirst

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

例如,这也适用于LINQ to SQL。

答案 2 :(得分:1)

您是否已将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())

答案 3 :(得分:1)

由于您要尝试比较两个不同的对象,因此首先需要实现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; }
    }
}

我希望有所帮助。

答案 4 :(得分:-1)

您可以像这样使用 LINQ 轻松查询

考虑这个 JSON

{
    "items": [
        {
            "id": "10",
            "name": "one"
        },
        {
            "id": "12",
            "name": "two"
        }
    ]
}

像这样把它放在一个名为 json 的变量中,

JObject json = JObject.Parse("{'items':[{'id':'10','name':'one'},{'id':'12','name':'two'}]}");

您可以使用以下 LINQ 查询从名称为 "one" 的项目中选择所有 ID

var Ids =
    from item in json["items"]
    where (string)item["name"] == "one"
    select item["id"];

然后,您将在 IEnumerable 列表中获得结果

相关问题