Linq查询返回重复结果

时间:2017-02-28 17:17:46

标签: c# entity-framework linq

以下查询在第二个选择查询中返回重复结果。

国家/地区与联盟有0..1 to *的关系。

联赛与用户联盟有1 to *的关系。

    return from ul in userLeagues
            select new Map.Country
            {
                id = ul.Country.CountryId,
                name = ul.Country.Common_Name,
                leagues =  userLeagues.Where(x => x.CountryId.Value == ul.CountryId.Value)
                                     .Select(x => new Map.League
                                     {
                                         id = x.LeagueID,
                                         name = x.leagueNameEN,
                                     })

            };

我尝试使用Distinct但没有运气。 似乎要么必须使用distinct或groupby countryId

输出如

[
  {
    "id": 1,
    "name": "Europe",
    "leagues": [
      {
        "id": 2,
        "name": "Champions League",
      },
      {
        "id": 3,
        "name": "Europa league",
      }
    ]
  },
  {
    "id": 1,
    "name": "Europe",
    "leagues": [
      {
        "id": 2,
        "name": "Champions League",
      },
      {
        "id": 3,
        "name": "Europa league",
      }
    ]
  }
]

3 个答案:

答案 0 :(得分:2)

您需要按CountryIdCommon_Name对其进行分组,以获得预期结果:

var result = from ul in userLeagues
             group ul by new { ul.Country.CountryId, ul.Country.Common_Name } into g
             select new Map.Country
             {
                 id = g.Key.CountryId,
                 name = g.Key.Common_Name,
                 leagues = g.Select(x => new Map.League
                 {
                     id = x.LeagueID,
                     name = x.leagueNameEN,
                 })
             };

答案 1 :(得分:1)

想想你正在做什么:对于userLeagues中的每个联赛,你为联盟所属的国家创建Map.Country。如果三个联赛在法国,那就是三个法国队。法国是一个美好的国家,但我们不要过火。

相反,您希望从一个不同的国家/地区列表开始。对于每一个,创建一个Map.Country,并为Map.Country提供应该属于它的联盟列表。

首先,让CountryIEquatable<Country>目的实施Distinct

public class Country : IEquatable<Country>
{
    public bool Equals(Country other)
    {
        return other.CountryID == CountryID;
    }

其次,你想从一个不同的国家列表开始,然后用联盟填充它们。

var q =
    from ctry in userLeagues.Select(ul => ul.Country).Distinct()
    select new
    {
        id = ctry.CountryID,
        name = ctry.Common_Name,
        leagues = userLeagues.Where(x => x.Country == ctry)
                             .Select(x => new
                             {
                                 id = x.LeagueID,
                                 name = x.leagueNameEn
                             }).ToList()
    };

我没有重新创建你的Map.LeagueMap.Country类,我只使用了匿名对象,我就这样离开了,因为这段代码肯定能够正常工作。但填写你的班级名称是微不足道的。

如果使Country实现IEquatable<T>变得不切实际,只需编写一个快速相等比较器并使用它:

public class CountryComparer : IEqualityComparer<Country>
{
    public bool Equals(Country x, Country y)
    {
        return x.CountryID == y.CountryID;
    }

    public int GetHashCode(Country obj)
    {
        return obj.CountryID.GetHashCode();
    }
}

......就像这样:

var cc = new CountryComparer();

var q =
    from ctry in userLeagues.Select(ul => ul.Country).Distinct(cc)
    select new
    {
        id = ctry.CountryID,
        name = ctry.Common_Name,
        leagues = userLeagues.Where(x => cc.Equals(x.Country, ctry))
                             .Select(x => new
                             {
                                 id = x.LeagueID,
                                 name = x.leagueNameEn
                             }).ToList()
    };

这在逻辑上等同于GroupBy,这可能是一种更可敬的方式。但是在我做之前有人想到了这一点,所以他赢得了荣耀。

答案 2 :(得分:0)

我会说您需要撤消查询。因此,不要从userLeagues开始,而是从国家/地区开始并包含子级联赛。