【问题标题】:Linq to sql - generates wrong sql?Linq to sql - 生成错误的sql?
【发布时间】:2010-06-25 15:38:19
【问题描述】:

我有带有表 Employee、Phone 和 Email 的 SQL 2008 服务器,其中 Employee 与 Phone 和 Email 是一对多的关系(因此员工可以有很多电话号码和电子邮件)。

现在我想用所有电话和电子邮件查询员工:

var query = (from e in db.Employee select new EmployeeDTO { Id = e.Id, Name = e.Name, Phones = e.Phones, Emails = e.Emails }).ToList();

但是 linq 将其转换为非常丑陋的 sql,它使用电话表进行左连接,但随后在单独的查询中查询每个员工的电子邮件,例如:

SELECT [t0].[EmployeeID], [t0].[Name], [t1].[Phone] (
    SELECT COUNT(*)
    FROM [dbo].[Phone] AS [t2]
    WHERE [t2].[EmployeeID] = [t0].[EmployeeID]
    ) AS [value]
FROM [dbo].[Employee] AS [t0]
LEFT OUTER JOIN [dbo].[Phone] AS [t1] ON [t1].[EmployeeID] = [t0].[EmployeeID]
ORDER BY [t0].[EmployeeID], [t1].[PhoneID]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.4926

SELECT [t0].[EmailID], [t0].[Email]
FROM [dbo].[Email] AS [t0]
WHERE [t0].[EmployeeID] = @x1
-- @x1: Input UniqueIdentifier (Size = 0; Prec = 0; Scale = 0) [1ed2e9a0-ca4b-4912-8f8e-000ed8d0b2af]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.4926

SELECT [t0].[EmailID], [t0].[Email]
FROM [dbo].[Email] AS [t0]
WHERE [t0].[EmployeeID]= @x1
-- @x1: Input UniqueIdentifier (Size = 0; Prec = 0; Scale = 0) [2203192b-05ef-4b59-b4b4-0010e26a8119]
-- Context: SqlProvider(Sql2008) Model: AttributedMetaModel Build: 3.5.30729.4926

我需要的是简单的sql:

SELECT [t0].[EmployeeID], [t0].[Name], [t1].[Phone], [t2].[Email]
FROM [dbo].[Employee] AS [t0]
LEFT OUTER JOIN [dbo].[Phone] AS [t1] ON [t1].[EmployeeID] = [t0].[EmployeeID]
LEFT OUTER JOIN [dbo].[Email] AS [t2] ON [t2].[EmployeeID] = [t0].[EmployeeID]

如何在不对结果进行分组的情况下编写这样的 linq 查询? 我知道如何进行多个左连接,但是我需要按 EmployeeID 对结果进行分组。

【问题讨论】:

    标签: linq linq-to-sql


    【解决方案1】:

    你试过这样做吗?

    var query = (from e in db.Employee
        join p in db.Phones on e.EmployeeID equals p.EmployeeID into tmpPhones
        from phones in tmpPhones.DefaultIfEmpty()
        join m in db.Emails on e.EmployeeID equals m.EmployeeID into tmpEmails
        from emails in tmpEmails.DefaultIfEmpty()
    
                 select new EmployeeDTO
                 {
                     Id = e.Id,
                     Name = e.Name,
                     Phones = phones,
                     Emails = emails
                 }).ToList();
    

    您需要的是 LoadWith 来处理多个一对多关系,但这不起作用 -

    http://social.msdn.microsoft.com/forums/en-US/linqprojectgeneral/thread/a68744f6-e1f3-4d28-82eb-87b8187ec0a8/

    跳圈应该可行 -

     var query = (from e in db.Employee
            join p in db.Phones on e.EmployeeID equals p.EmployeeID into tmpPhones
            from phones in tmpPhones.DefaultIfEmpty()
            join m in db.Emails on e.EmployeeID equals m.EmployeeID into tmpEmails
            from emails in tmpEmails.DefaultIfEmpty()
            group e by e into eGrp
    
                     select new EmployeeDTO
                     {
                         Id = eGrp.Key.Id,
                         Name = eGrp.Key.Name,
                         Phones = eGrp.Select(x => x.Phones),
                         Emails = eGrp.Select(x => x.Emails)
                     }).ToList();
    

    【讨论】:

    • 是的,我已经尝试过了,这是迄今为止最好的解决方案,但是在这里我需要按 EmployeeId 对结果进行分组以获取不同的员工,因为此查询返回的不是不同的记录!如果您有 1 名员工使用 2 部电话和 2 封电子邮件,您会在结果中获得 4 条记录,并且需要对它们进行分组。如果您只查询电话,那么 Linq 会自动为您分组,您会得到 1 名员工和 2 部电话。不过谢谢你的回复。
    猜你喜欢
    • 1970-01-01
    • 2011-05-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多