C# 连接不包含关系的表

C# 连接不包含关系的表,c#,entity-framework,linq,ado.net,navigational-properties,C#,Entity Framework,Linq,Ado.net,Navigational Properties,我有以下数据库: 表消息: 负责存储发送到不同电子邮件地址的邮件 表格电子邮件: 仅负责存储电子邮件地址(主键=电子邮件) (toEmail与表格电子邮件有关系)(SotresFoo@gmail.com, Foo2@gmail.com等等……) 表格联系人: 用于存储用户的联系人。(存储马克、约翰、汤姆等) 表格联系人电子邮件 需要此表,因为联系人可能有多个电子邮件地址。(存储在表电子邮件中找到的ID) 无论如何,问题是: 我想创建一个查询,选择在特定日期发送的所有邮件我想在查

我有以下数据库:

  • 表消息:

    • 负责存储发送到不同电子邮件地址的邮件
  • 表格电子邮件:

    • 仅负责存储电子邮件地址(主键=电子邮件) (toEmail与表格电子邮件有关系)(SotresFoo@gmail.com, Foo2@gmail.com等等……)
  • 表格联系人:

    • 用于存储用户的联系人。(存储马克、约翰、汤姆等)
  • 表格联系人电子邮件

    • 需要此表,因为联系人可能有多个电子邮件地址。(存储在表电子邮件中找到的ID)
  • 无论如何,问题是: 我想创建一个查询,选择在特定日期发送的所有邮件我想在查询中包括联系人姓名(如果存在)。我已将以下查询装箱,但速度太慢:

    Func<string, Contact> tryGetContact = (email)=>{
        var contactEmail = db.ContactEmails.FirstOrDefault(x=>x.IdEmail==email);
        if(contactEmail==null)
           return null;
        return contactEmail.Contact; // navigational property created by entity framework.
    };
    
    var query = from msg in db.Messages
                join email in db.Emails on msg.ToEmail equals email.Email
                where msg.Date < "some date" && msg.Date > "some other date" 
                select new
                {
                    MessageSubject = msg.Subject,
                    ToEmail = email.Email,
                    Contact = tryGetContact(email.Email) // this slows down the query!
                };
    
    Func-tryGetContact=(电子邮件)=>{
    var contactEmail=db.ContactEmails.FirstOrDefault(x=>x.IdEmail==email);
    如果(contactEmail==null)
    返回null;
    return contactEmail.Contact;//实体框架创建的导航属性。
    };
    var query=来自db.Messages中的消息
    加入数据库中的电子邮件。msg.ToEmail上的电子邮件等于email.email
    其中消息日期<“某个日期”和消息日期>“某个其他日期”
    选择新的
    {
    MessageSubject=msg.Subject,
    ToEmail=email.email,
    Contact=tryGetContact(email.email)//这会减慢查询速度!
    };
    
    为了加快查询的执行速度,是否需要将所有联系人存储在字典中,并将此查询分为两个查询


    将所有联系人存储在字典中将使事情更加高效。但是从数据库中检索我不需要的所有联系人会让我觉得我在浪费资源

    如果我们能够看到Linq查询生成的实际SQL,那么就更容易确定是什么减慢了查询的速度。但是,我想这可能与您的
    tryGetContact
    Func有关,它与查询的主要部分不共享相同的上下文

    因此,如果我是对的,每次您调用
    tryGetContact(email.email)
    时,都会执行一个新的完整查询,因为这行代码:

    var contactEmail = db.ContactEmails.FirstOrDefault(x=>x.IdEmail==email);
    
    在这种情况下,
    db.ContactEmails
    不是SQL查询中联接的一部分,因此每次都会重新执行它

    因此,我要做的是添加另一个
    join
    ,将
    ContactEmails
    包含在Linq(以及随后的SQL)查询中。这应该是这样的:

    var query = from msg in db.Messages
                join email in db.Emails on msg.ToEmail equals email.Email
                join contactEmail in db.ContactEmails on contactEmail.IdEmail equals email.Email
                where msg.Date < "some date" && msg.Date > "some other date" 
                select new
                {
                    MessageSubject = msg.Subject,
                    ToEmail = email.Email,
                    Contact = (contactEmail==null) ? contactEmail.Contact : null,
                };
    
    var query=from msg in db.Messages
    加入数据库中的电子邮件。msg.ToEmail上的电子邮件等于email.email
    在db中加入contactEmail。contactEmail上的ContactEmails.IdEmail等于email.email
    其中消息日期<“某个日期”和消息日期>“某个其他日期”
    选择新的
    {
    MessageSubject=msg.Subject,
    ToEmail=email.email,
    Contact=(contactEmail==null)?contactEmail.Contact:null,
    };
    

    如果这不起作用,您可能希望对所有
    tryGetContact
    调用只执行一次
    db.ContactEmails
    ,并将结果存储在集合中(或哈希集以获得更好的性能)。

    您是否使用基于服务器的数据库,如MS SQL server?如果是这样,使用存储过程或直接查询会更快。您的数据库中是否对ContactEmails.IdEmail编制了索引?无论您如何编写请求,如果您至少没有定义该索引,就不会获得良好的性能。是的,我只有一个MS SQL server数据库。问题是,有时我会向不属于任何联系人的电子邮件地址发送消息。这就是为什么我的数据库中没有这种关系。是的,我相信“ContactEmails.IdEmail”是索引的。换句话说,为了创建该字段,表Emails上的email必须存在。那么,听起来像是在
    ContactEmails.IdEmail
    上定义了外键。但这并不一定意味着该列上定义了索引。你能核实一下吗?我遗漏了什么吗?但是你不是在
    联系人电子邮件上执行内部连接,如果没有电子邮件的现有联系人,则有效地过滤掉结果吗?是的,这会减慢事情的发展。我必须将联系人存储在哈希集中,然后在内存中执行所有操作。谢谢你的帮助!你是对的,但是这应该通过外部连接来避免。很高兴能帮助Tono Nam!