C# 删除“;“重复”;左外联接上具有Linq的结果

C# 删除“;“重复”;左外联接上具有Linq的结果,c#,entity-framework,linq,C#,Entity Framework,Linq,我看了很多关于这方面的文章,要么提出的解决方案对我不起作用,要么我对它们的理解不够清楚。无论如何,冒着口是心非的危险,我提出我的问题供你们审查 我有一个联系人数据库,我想搜索 每个联系人都与一个人关联(暂时忽略机构关系) 每个联系人还与其他表中的多个电子邮件和电话记录相关联(每个电子邮件和电话都是联系人记录的专有项) 我希望能够返回符合电子邮件记录和/或电话记录查询的联系人。因此,联系人可能有多个电子邮件地址。如果我的查询“命中”任何电子邮件,我希望返回单个联系人以及结果中包含的与该联系人相关

我看了很多关于这方面的文章,要么提出的解决方案对我不起作用,要么我对它们的理解不够清楚。无论如何,冒着口是心非的危险,我提出我的问题供你们审查

我有一个联系人数据库,我想搜索

每个联系人都与一个人关联(暂时忽略机构关系) 每个联系人还与其他表中的多个电子邮件和电话记录相关联(每个电子邮件和电话都是联系人记录的专有项)

我希望能够返回符合电子邮件记录和/或电话记录查询的联系人。因此,联系人可能有多个电子邮件地址。如果我的查询“命中”任何电子邮件,我希望返回单个联系人以及结果中包含的与该联系人相关的所有电子邮件(和电话)

所以我在电子邮件域名“好莱坞”上搜索。有一个联系人的电子邮件域等于“好莱坞”。此联系人还有两个与之关联的其他电子邮件地址。我想返回一条包含所有这些记录的记录。(我是摩根·弗里曼的粉丝,所以我编造了以下数据——这是假的!)

当然,在SQLServerManagementStudio中运行这种查询将返回3条记录。每个与联系人关联的电子邮件记录对应一条。但是,我将结果投影到一个对象中,其中将放置多封电子邮件(和电话),这样我就不必为同一联系人处理多个对象

查询是在Linq中构造的。我添加了“组”行,以消除重复项

var query = from rContact in qryContacts
            group rContact by rContact.contact_id into grpContact

            join rPerson in ctx.people
                on grpContact.FirstOrDefault().person_id equals rPerson.person_id

            join rEmail in ctx.emails
                on grpContact.FirstOrDefault().contact_id equals rEmail.contact_id into emailGroup
                from subEmails in emailGroup.DefaultIfEmpty()

            select new PersonalContact
            {
                ID          = grpContact.FirstOrDefault().contact_id,
                Label       = grpContact.FirstOrDefault().label,
                Notes       = grpContact.FirstOrDefault().notes,
                Prefix      = rPerson.prefix,
                FirstName   = rPerson.first_name,
                MiddleName  = rPerson.middle_name,
                LastName    = rPerson.last_name,
                Suffix      = rPerson.suffix,
                AKA         = rPerson.aka,
                DOB         = rPerson.dob,
                IsFemale    = rPerson.is_female,
                Emails      = emailGroup.Select(e=> new Email
                    {
                        ID              = e.email_id,
                        Label           = e.label,
                        Notes           = e.notes,
                        Preferred       = e.is_preferred,
                        Category        = e.email_category,
                        LocalPart       = e.email_local_part,
                        Domain          = e.email_domain,
                        TopLevelDomain  = e.email_top_level_domain,
                    }),
            }
这没关系。。。它返回PersonalContact对象,按预期填充…只返回其中的3个!我以为按联系人分组可以消除重复项,但是。。。没有

下面是结果的样子(我只粘贴了一个,但我得到了三个)

当我将多部手机添加到联系人中时,问题才会变得更加复杂

任何帮助都将不胜感激

更新

我认为回答NetMage的问题“什么是qryContacts?你在哪里过滤电子邮件地址?”是值得的

我提出了以下模式,它允许我动态定义LINQ查询。。。某种程度上。我创建了一个包含表达式列表的变量。这允许我在运行时添加我想要的任何条件

var contactFilter = new List<Expression<Func<contact, bool>>>();
    contactFilter.Add(e => e.emails.Where(x=>x.email_domain == "gmail").FirstOrDefault() != null);
现在,我将过滤器内容添加到查询中

if (contactFilter != null)
{
    foreach (var item in contactFilter)
    {
        qryContacts = qryContacts.Where(item);
    }
}

然后在原始帖子中所示的基础上构造查询。希望这会有帮助。它有一些局限性,但对我来说,它是一种非常高效的模式,在您不知道将定义哪些字段的情况下,它简化了编写查询的任务。我对Linq和表达式基础的理解非常有限,因此我发现这种技术比其他一些“构建器”更容易实现。你觉得这项技术怎么样?希望听到一些反馈。

问题的解决方案(对我来说)是从emailGroup.DefaultIfEmpty()中的子电子邮件中删除
。。。老实说,我不完全清楚为什么会有不同,但现在一切都按照预期进行

var query = from rContact in qryContacts
    group rContact by rContact.contact_id into grpContact

    join rPerson in ctx.people
        on grpContact.FirstOrDefault().person_id equals rPerson.person_id

    join rEmail in ctx.emails
        on grpContact.FirstOrDefault().contact_id equals rEmail.contact_id into emailGroup
        // from subEmails in emailGroup.DefaultIfEmpty() <!-- REMOVE THIS LINE

    select new PersonalContact
    {
        ID          = grpContact.FirstOrDefault().contact_id,
        Label       = grpContact.FirstOrDefault().label,
        Notes       = grpContact.FirstOrDefault().notes,
        Prefix      = rPerson.prefix,
        FirstName   = rPerson.first_name,
        MiddleName  = rPerson.middle_name,
        LastName    = rPerson.last_name,
        Suffix      = rPerson.suffix,
        AKA         = rPerson.aka,
        DOB         = rPerson.dob,
        IsFemale    = rPerson.is_female,
        Emails      = emailGroup.Select(e=> new Email
            {
                 ID              = e.email_id,
                 Label           = e.label,
                 Notes           = e.notes,
                 Preferred       = e.is_preferred,
                 Category        = e.email_category,
                 LocalPart       = e.email_local_part,
                 Domain          = e.email_domain,
                 TopLevelDomain  = e.email_top_level_domain,
            }),
    }
var query=来自qryContacts中的rContact
按rContact.contact\u id将rContact分组到grpContact中
加入rPerson的ctx.people
在grpContact.FirstOrDefault()上。person\u id等于rPerson.person\u id
在ctx.email中加入rEmail
在grpContact.FirstOrDefault()上。contact_id等于rEmail.contact_id到emailGroup

//从emailGroup.DefaultIfEmpty()中的子电子邮件中删除问题的解决方案(对我来说)是从emailGroup.DefaultIfEmpty()中的子电子邮件中删除
。。。老实说,我不完全清楚为什么会有不同,但现在一切都按照预期进行

var query = from rContact in qryContacts
    group rContact by rContact.contact_id into grpContact

    join rPerson in ctx.people
        on grpContact.FirstOrDefault().person_id equals rPerson.person_id

    join rEmail in ctx.emails
        on grpContact.FirstOrDefault().contact_id equals rEmail.contact_id into emailGroup
        // from subEmails in emailGroup.DefaultIfEmpty() <!-- REMOVE THIS LINE

    select new PersonalContact
    {
        ID          = grpContact.FirstOrDefault().contact_id,
        Label       = grpContact.FirstOrDefault().label,
        Notes       = grpContact.FirstOrDefault().notes,
        Prefix      = rPerson.prefix,
        FirstName   = rPerson.first_name,
        MiddleName  = rPerson.middle_name,
        LastName    = rPerson.last_name,
        Suffix      = rPerson.suffix,
        AKA         = rPerson.aka,
        DOB         = rPerson.dob,
        IsFemale    = rPerson.is_female,
        Emails      = emailGroup.Select(e=> new Email
            {
                 ID              = e.email_id,
                 Label           = e.label,
                 Notes           = e.notes,
                 Preferred       = e.is_preferred,
                 Category        = e.email_category,
                 LocalPart       = e.email_local_part,
                 Domain          = e.email_domain,
                 TopLevelDomain  = e.email_top_level_domain,
            }),
    }
var query=来自qryContacts中的rContact
按rContact.contact\u id将rContact分组到grpContact中
加入rPerson的ctx.people
在grpContact.FirstOrDefault()上。person\u id等于rPerson.person\u id
在ctx.email中加入rEmail
在grpContact.FirstOrDefault()上。contact_id等于rEmail.contact_id到emailGroup

//从emailGroup.DefaultIfEmpty()中的子电子邮件中,group by实际上什么都不做-您正在按
联系人id
对联系人进行分组,并且每个
联系人id
应该只有一个条目,除非您已经收到多行。什么是
qryContacts
?您在哪里筛选电子邮件地址?使用响应更新OP。谢谢你的反馈!!快速提示:而不是
FirstOrDefault()!=空
使用
Any()
。您还可以将谓词折叠到
Any
e=>e.email.Any(x=>x.email\u domain==“gmail”)
。基于您的
qryContacts
结构,
GroupBy
对您没有任何帮助。您将获得一个过滤后的
ctx.contacts
列表,每个
contact\u id
仅以一条记录开始。group by实际上什么也不做-您正在按
contact\u id
对联系人进行分组,并且每个
contact\u id
应该只有一个条目,除非您已经收到多行。什么是
qryContacts
?您在哪里筛选电子邮件地址?使用响应更新OP。谢谢你的反馈!!快速提示:而不是
FirstOrDefault()!=空
使用
Any()
。您还可以将谓词折叠到
Any
e=>e.email.Any(x=>x.email\u domain==“gmail”)
。基于您的
qryContacts
结构,
GroupBy
对您没有任何帮助。您将获得一个过滤后的
ctx.contacts
列表,每个
contact\u id
仅以一条记录开始。来自
var query = from rContact in qryContacts
    group rContact by rContact.contact_id into grpContact

    join rPerson in ctx.people
        on grpContact.FirstOrDefault().person_id equals rPerson.person_id

    join rEmail in ctx.emails
        on grpContact.FirstOrDefault().contact_id equals rEmail.contact_id into emailGroup
        // from subEmails in emailGroup.DefaultIfEmpty() <!-- REMOVE THIS LINE

    select new PersonalContact
    {
        ID          = grpContact.FirstOrDefault().contact_id,
        Label       = grpContact.FirstOrDefault().label,
        Notes       = grpContact.FirstOrDefault().notes,
        Prefix      = rPerson.prefix,
        FirstName   = rPerson.first_name,
        MiddleName  = rPerson.middle_name,
        LastName    = rPerson.last_name,
        Suffix      = rPerson.suffix,
        AKA         = rPerson.aka,
        DOB         = rPerson.dob,
        IsFemale    = rPerson.is_female,
        Emails      = emailGroup.Select(e=> new Email
            {
                 ID              = e.email_id,
                 Label           = e.label,
                 Notes           = e.notes,
                 Preferred       = e.is_preferred,
                 Category        = e.email_category,
                 LocalPart       = e.email_local_part,
                 Domain          = e.email_domain,
                 TopLevelDomain  = e.email_top_level_domain,
            }),
    }