List Distinct在LINQ而不是GroupBy中不起作用

时间:2017-03-20 10:38:52

标签: linq c#-4.0 entity-framework-6

提前致谢。我可以在使用 var 时获得所需的输出,但我希望通过使用列表中的区别<> 来获得所需的输出。

InventoryDe​​tails.cs

public class InventoryDetails
{
        public int? PersonalInventoryGroupId { get; set; }
        public int? PersonalInventoryBinId { get; set; }
}

InventoryController.cs

[HttpGet("GetInventory")]
public IActionResult GetInventory(int id)
{
    //Below code will return distinct record
    var inventory = (from i in _context.TempTbl
                      where i.TempId == id
                      select new
                      {
                          PersonalInventoryBinId = i.PersonalInventoryBinId,
                          PersonalInventoryGroupId = i.PersonalInventoryGroupId,
                      }).ToList().Distinct().ToList();

    //Below code is not doing distinct
    List<InventoryDetails> inventory = (from i in _context.TempTbl
                  where i.TempId == id
                  select new InventoryDetails
                  {
                      PersonalInventoryBinId = i.PersonalInventoryBinId,
                      PersonalInventoryGroupId = i.PersonalInventoryGroupId,
                  }).ToList().Distinct().ToList();
}

如果我使用var作为返回类型,那么我可以获得不同的记录。有人可以帮助它。

4 个答案:

答案 0 :(得分:0)

请尝试这样做可能有所帮助。

IList<InventoryDetails> inventory = _context.InventoryDetails.Where(x=>x.TempId == id).GroupBy(p => new {p.PersonalInventoryGroupId, p.PersonalInventoryBinId } )
  .Select(g => g.First())
  .ToList();

答案 1 :(得分:0)

您需要覆盖EqualsGetHashCode。 首先,让我们看一下AnonymousType与InventoryDe​​tails

        var AnonymousTypeObj1 = new { PersonalInventoryGroupId = 1, PersonalInventoryBinId = 1 };
        var AnonymousTypeObj2 = new { PersonalInventoryGroupId = 1, PersonalInventoryBinId = 1 };

        Console.WriteLine(AnonymousTypeObj1.Equals(AnonymousTypeObj2)); // True

        var InventoryDetailsObj1 = new InventoryDetails { PersonalInventoryBinId = 1, PersonalInventoryGroupId = 1 };
        var InvertoryDetailsObj2 = new InventoryDetails { PersonalInventoryBinId = 1, PersonalInventoryGroupId = 1 };

        Console.WriteLine(InventoryDetailsObj1.Equals(InvertoryDetailsObj2)); // False

您可以看到Equals的行为方式不同,使Distinct的行为有所不同。您在问题中提到的问题不是var,而是AnonoymizeType

要使Distinct按预期工作,您需要覆盖EqualsGetHashCode

    public class InventoryDetails
    {
        public int? PersonalInventoryGroupId { get; set; }
        public int? PersonalInventoryBinId { get; set; }

        public override bool Equals(object obj)
        {

            if (obj == null) return false;

            if (obj is InventoryDetails)
            {
                if (PersonalInventoryGroupId == (obj as InventoryDetails).PersonalInventoryGroupId 
                    && PersonalInventoryBinId == (obj as InventoryDetails).PersonalInventoryBinId)
                    return true;
            }

            return false;
        }

        public override int GetHashCode()
        {
            int hash = 17;
            hash = hash * 23 + PersonalInventoryBinId.GetHashCode();
            hash = hash * 23 + PersonalInventoryGroupId.GetHashCode();
            return hash;
        }
    }

答案 2 :(得分:0)

另一种方法是

 List<InventoryDetails> inventory = (from i in TempTbl
                                             where i.TempId == id
                                             select new InventoryDetails
                                             {                                                   
                                                 PersonalInventoryBinId = i.PersonalInventoryBinId,
                                                 PersonalInventoryGroupId = i.PersonalInventoryGroupId,
                                             }).AsQueryable().ToList().Distinct(new customComparer()).ToList();

 public class customComparer:IEqualityComparer<InventoryDetails>
{
    public bool Equals(InventoryDetails x, InventoryDetails y)
    {
        if (x.TempId == y.TempId && x.PersonalInventoryBinId == y.PersonalInventoryBinId 
            && x.PersonalInventoryGroupId == y.PersonalInventoryGroupId)
        {
            return true;
        }
        return false;
    }
    public int GetHashCode(InventoryDetails obj)
    {
        return string.Concat(obj.PersonalInventoryBinId.ToString(),
                            obj.PersonalInventoryGroupId.ToString(),
                            obj.TempId.ToString()).GetHashCode();
    }
}

答案 3 :(得分:0)

正如伊万的评论所说,在ToList之前致电Distinct,你会让生活变得困难。这可以防止SQL提供程序将Distinct调用合并到生成的SQL语句中。但这留下了一个问题:导致差异的原因是什么?

第一个查询生成匿名类型实例。根据{{​​3}},默认情况下,匿名类型(在C#中)在属性和属性值相等时是相等的(结构相等)。相反,默认情况下,引用类型(如InventoryDetails)在引用(例如内存地址)相等(引用相等标识)时是相等的。通过覆盖EqualsGetHashcode方法可以使 相等,就像有些人建议的那样。

但如果删除第一个ToList()

,那就没有必要了
var inventory = (from i in _context.TempTbl
    where i.TempId == id
    select new InventoryDetails
    {
        PersonalInventoryBinId = i.PersonalInventoryBinId,
        PersonalInventoryGroupId = i.PersonalInventoryGroupId,
    }).Distinct().ToList();

现在直到ToList()的整个语句都是IQueryable,可以转换为SQL。执行SQL并且数据库返回不同的原始记录结果集,EF从中生成InventoryDetails个对象。 C#运行时代码甚至从未意识到重复!