加入不包含关系的表

时间:2016-10-25 00:56:21

标签: c# entity-framework linq ado.net navigational-properties

我有以下数据库:

enter image description here

  1. 表格消息:

    • 负责存储发送的邮件做不同的电子邮件地址。
  2. 表格电子邮件:

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

    • 用于存储用户的联系人。 (商店标记,约翰,汤姆等...)
  4. 表格ContactEmails

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

    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!
                };
    

    为了使我的查询执行得更快,我是否需要将所有联系人存储在字典中并将此查询分成2个查询?

    将所有联系人存储在字典中会使事情变得更有效率。但是从我不需要大部分数据库的数据库中恢复所有联系人会让我觉得我在浪费资源。

1 个答案:

答案 0 :(得分:3)

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

因此,如果我是对的,每次拨打tryGetContact(email.Email)时都会因为这一行而执行新的完整查询:

var contactEmail = db.ContactEmails.FirstOrDefault(x=>x.IdEmail==email);

在这种情况下,db.ContactEmails不是SQL查询中的连接的一部分,因此每次都会重新执行。

所以我要做的是添加另一个join以在Linq(和后续SQL)查询中包含ContactEmails。这应该是这样的:

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,
            };

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