【问题标题】:Make a DISTINCT join in LINQ在 LINQ 中加入 DISTINCT
【发布时间】:2019-07-30 08:44:01
【问题描述】:

我有一个绑定到 LinqToSql-Datasource 的 GridView。

数据源代表 3 个表,我在 Linq-Query 中使用 Join 选择这些表。 这些表格适用于个人、机构和会员 (mitgliedschaft)。

一个人可以拥有属于不同机构的各种会员资格。

My Query 获取所有 Memberships 但表格中仅显示个人或机构的信息,因此表格中有重复的行。

我只希望显示一个人,尽管例如有 3 个成员资格。 在 SQL 中,我会使用左连接或其他方式来完成,但我是 LINQ 新手。

我的查询是:

neonDataContext db = new neonDataContext();
                e.KeyExpression = "id";
                e.QueryableSource = from mitgliedschaft in db.mitgliedschaft

                                    join person in db.person on mitgliedschaft.person_id equals person.id
                                    join institution in db.institution on mitgliedschaft.verein_id equals institution.id

                                    select new
                                    {
                                        vorname = person.vorname,
                                        nachname = person.nachname,
                                        nameVerein = institution.name,
                                        vereinid = mitgliedschaft.verein_id,
                                        id = mitgliedschaft.id,
                                        verbandsnummer = person.verbandsMitgliedsNummer,
                                        strasse = person.strasse,
                                        plz = person.plz,
                                        ort = person.ort,
                                        geburtsdatum = person.geburtsdatum,
                                        geschlechtid = person.geschlechtid,
                                        statusid = mitgliedschaft.statusid,
                                        bezirk_id = mitgliedschaft.bezirk_id,
                                        kreis_id = mitgliedschaft.kreis_id,
                                        person_id = mitgliedschaft.person_id,
                                        deletedFlag = mitgliedschaft.deletedFlag
                                    };

有人可以告诉我如何对这样的查询进行区分或左连接吗?

【问题讨论】:

  • 使用 Groupby。小组应该给出不同的结果。
  • 在这种情况下如何使用 group by?
  • 在 from : (from ......select new {......}).GroupBy(x => ....) 周围加上括号
  • 当我以这种方式分组时,网格告诉我 DataSource 中的某些属性或字段名没有找到
  • 该组的属性是您“选择新”中的属性

标签: c# linq join distinct


【解决方案1】:

由于您要返回复杂对象的枚举,因此 Distinct() 运算符本身是不适用的。考虑创建一个类来表示代码中的 Person 实体并让它实现 IEquatable 接口。这将允许运行时通过您自己的自定义比较逻辑来决定两个 Person 对象实际上何时相同。

详情请看这篇文章:https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinct?view=netframework-4.8

然后您可以在结果集上使用 Distinct() 运算符:

neonDataContext db = new neonDataContext();
                e.KeyExpression = "id";
                e.QueryableSource = (from mitgliedschaft in db.mitgliedschaft

                                    join person in db.person on mitgliedschaft.person_id equals person.id
                                    join institution in db.institution on mitgliedschaft.verein_id equals institution.id

                                    select new Person()
                                    {
                                        vorname = person.vorname,
                                        nachname = person.nachname,
                                        nameVerein = institution.name,
                                        vereinid = mitgliedschaft.verein_id,
                                        id = mitgliedschaft.id,
                                        verbandsnummer = person.verbandsMitgliedsNummer,
                                        strasse = person.strasse,
                                        plz = person.plz,
                                        ort = person.ort,
                                        geburtsdatum = person.geburtsdatum,
                                        geschlechtid = person.geschlechtid,
                                        statusid = mitgliedschaft.statusid,
                                        bezirk_id = mitgliedschaft.bezirk_id,
                                        kreis_id = mitgliedschaft.kreis_id,
                                        person_id = mitgliedschaft.person_id,
                                        deletedFlag = mitgliedschaft.deletedFlag
                                    }).Distinct();

【讨论】:

  • 无法创建“select new Person()”,因为我需要 select 中的其他表
  • 您可以像在您自己的示例中一样初始化新Person的字段,可以访问表别名
  • 我是否必须为此创建一个类 Person()。我已经有了一个以这种方式命名的类,独立于 DataBase-Context
  • 您需要一个类来实现 IEquatable 接口。如果现有类的定义也适合这种情况,您可以考虑只使用它(在实现 IEquatable 之后)
  • 该类只需要选择查询中的属性吗?已经实现了,但现在我得到了“MissingPrimaryKeyException”
【解决方案2】:

尝试了几种实现目标的方法(以不同的方式实现 distinct 并实现 distinctBy-Extension)。 在我的情况下,唯一可行的方法是分组并选择第一个:

neonDataContext db = new neonDataContext();
                e.KeyExpression = "id";
                e.QueryableSource = (from mitgliedschaft in db.mitgliedschaft

                                     join person in db.person on mitgliedschaft.person_id equals person.id
                                     join institution in db.institution on mitgliedschaft.verein_id equals institution.id

                                     select new
                                     {
                                         vorname = person.vorname,
                                         nachname = person.nachname,
                                         nameVerein = institution.name,
                                         vereinid = mitgliedschaft.verein_id,
                                         id = mitgliedschaft.id,
                                         verbandsMitgliedsNummer = person.verbandsMitgliedsNummer,
                                         strasse = person.strasse,
                                         plz = person.plz,
                                         ort = person.ort,
                                         geburtsdatum = person.geburtsdatum,
                                         geschlechtid = person.geschlechtid,
                                         statusid = mitgliedschaft.statusid,
                                         bezirk_id = mitgliedschaft.bezirk_id,
                                         kreis_id = mitgliedschaft.kreis_id,
                                         person_id = mitgliedschaft.person_id.Value,
                                         deletedFlag = mitgliedschaft.deletedFlag
                                     }).GroupBy(p => p.person_id).Select(p => p.First());

【讨论】:

  • 如果你想按多个分组:GroupBy(p => new { pid = p.person_id, id = p.id})
【解决方案3】:

如果你想通过一个字段或多个字段来区分,比如person_id,你可以添加一个扩展函数:

public static class  CustomDistinct{
        public static IEnumerable<TSource> DistinctBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
        {
            HashSet<TKey> seenKeys = new HashSet<TKey>();
            foreach (TSource element in source)
            {
                if (seenKeys.Add(keySelector(element)))
                {
                    yield return element;
                }
            }
        }
    }

使用它:

(from ... select...).DistinctBy(p => p.person_id); //one field

(from ... select...).DistinctBy(p => new{p.person_id,p.id}); //multiple-field

【讨论】:

  • 但是如果“select new”是匿名的,我该如何使用它,就像我的情况一样?
  • 你可以像这样使用它:(from ... select new {...,deletedFlag = mitgliedschaft.deletedFlag}).DistinctBy(p =&gt; p.person_id);
  • 当我这样做时,整个 query.part 带有红色下划线。说这个匿名类型不能在“System.Linq.IQueryable”中进行隐式转换,因为已经有显式转换
  • 这是我的测试代码,运行成功:var list = (from com in comList join emp in empList on com.ID equals emp.ID select new { ComId = com.ComId, Name = emp.FName, Sex = emp.Sex, ID = emp.ID, }).DistinctBy(l =&gt;l.ComId);请提供您的代码。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-29
  • 2012-11-15
相关资源
最近更新 更多