【问题标题】:Few GroupJoin in one query几个 GroupJoin 一次查询
【发布时间】:2011-02-26 20:36:56
【问题描述】:

我正在尝试用几个一致的 GroupJoin 编写 ObjectQuery,这意味着应该有一个主表选择 + 几个额外的 LEFT JOIN。我正在使用 SelectMany 方法执行以下操作,因为没有它我无法访问字段 RoleID :

var routesQuery = entities.Routes.Join(
                    entities.Locales,
                    Routes => Routes.LocaleID,
                    Locales => Locales.LocaleID,
                    (Routes, Locales) => new { Routes = Routes }
                ).GroupJoin(
                    entities.LinkRolesPermissions,
                    Routes => Routes.Routes.RouteID,
                    LinkRolesPermissions => LinkRolesPermissions.EntityID,
                    (Routes, LinkRolesPermissions) => new 
                    { 
                        LinkRolesPermissions = LinkRolesPermissions,
                        RoleID = LinkRolesPermissions.SelectMany(
                            LRS => LRS.RoleID,
                            (LRS, RoleID) => new { RoleID = LRS.RoleID }
                        )
                    }
                )
                .SelectMany(
                    LinkRolesPermissions => LinkRolesPermissions.RoleID, 
                    (LinkRolesPermissions, RoleID) => new { RoleID = RoleID }
                 ).GroupJoin(
                    entities.aspnet_Roles, 
                    LRS => LRS.RoleID, 
                    RLS => RLS.RoleId, 
                    (LRS, RLS) => new { LRS = LRS }
                );

一切正常,但它以某种方式作为 INNER JOIN 工作,我意识到 SelectMany 方法会导致这种行为。它生成这个查询:

SELECT  1 AS [C1],  1 AS [C2],  [Extent3].[RoleID] AS [RoleID] FROM   [dbo].[Routes] AS [Extent1] 
INNER JOIN [dbo].[Locales] AS [Extent2] ON ([Extent1].[LocaleID] = [Extent2].[LocaleID]) OR (([Extent1].[LocaleID] IS NULL) AND ([Extent2].[LocaleID] IS NULL)) 
INNER JOIN [dbo].[LinkRolesPermissions] AS [Extent3] ON ([Extent1].[RouteID] = [Extent3].[EntityID]) OR (([Extent1].[RouteID] IS NULL) AND ([Extent3].[EntityID] IS NULL))

我删除它并收到以下错误:

var routesQuery = entities.Routes.Join(
                    entities.Locales,
                    Routes => Routes.LocaleID,
                    Locales => Locales.LocaleID,
                    (Routes, Locales) => new { Routes = Routes }
                ).GroupJoin(
                    entities.LinkRolesPermissions,
                    Routes => Routes.Routes.RouteID,
                    LinkRolesPermissions => LinkRolesPermissions.EntityID,
                    (Routes, LinkRolesPermissions) => new 
                    { 
                        LinkRolesPermissions = LinkRolesPermissions,
                        RoleID = LinkRolesPermissions.SelectMany(
                            LRS => LRS.RoleID,
                            (LRS, RoleID) => new { RoleID = LRS.RoleID }
                        )
                    }
                )
                .GroupJoin(
                    entities.aspnet_Roles, 
                    LRS => LRS.RoleID, 
                    RLS => RLS.RoleId, 
                    (LRS, RLS) => new { LRS = LRS }
                );

方法的类型参数 'System.Linq.Enumerable.SelectMany(System.Collections.Generic.IEnumerable, System.Func>, System.Func)' 不能从用法推断。尝试 指定类型参数 明确的。

请有人向我解释一下这种行为,并在可能的情况下建议如何解决它。

提前致谢。

【问题讨论】:

    标签: c# extension-methods left-join objectquery


    【解决方案1】:

    您正试图急切地加载相关对象。使用 Include 方法来做到这一点。

    http://msdn.microsoft.com/en-us/library/bb896272.aspx

    IQueryable<Route> query = 
      from route in entities.Routes.Include("LinkRolesPermissions.aspnet_Roles")
      where route.Locales.Any()
      select route;
    

    为此,您必须设置导航属性。

    http://msdn.microsoft.com/en-us/library/bb738520.aspx


    PS:你不必每次都投影成匿名类型:

    (Routes, Locales) => new { Routes = Routes } 
    

    可能

    (Routes, Locales) => Routes
    

    【讨论】:

    • 我认为我可以使用仅包含我合并表的字段的名称是相同的。在我的情况下,领域是不同的。 LRS => LRS.RoleID,RLS => RLS.RoleId。它也可能是 - LRS => LRS.RoleID, RLS => RLS.EntityID
    • 好吧,在这种情况下,您将创建两个导航属性。每个导航属性将代表不同的关系。
    【解决方案2】:

    好吧,继续折磨 LINQ 可能很有用,尽管现在它似乎没用,而且 LINQ 可能仅适用于包含一个表的短查询。它是为数组和 XML、IMO 创建的。

    对于真正的 SQL 查询,最好使用在 EF 实体中初始化的直接 SQL 查询,如下所示:

    ObjectQuery<DbDataRecord> query = new ObjectQuery<DbDataRecord>
    (
    "SELECT c.Name,c.City, d.Name FROM ContosoEntities.Customer as c " + 
    "LEFT JOIN ContosoEntities.Products as d ON d.Name = c.Name " + 
    "WHERE c.Country=@ctry", ent
    );
    query.Parameters.Add(new ObjectParameter("ctry", "Australia"));
    

    此处列出的所有 EF 变体:

    【讨论】:

    • P.S. “包含”方法以几何级数连接表格(已知错误),因此只适合连接一个表格,如果有多个表格,那么实际上每个表格将被合并多次,因为“包含”将在当前使用查询。
    猜你喜欢
    • 2012-11-03
    • 1970-01-01
    • 2012-08-31
    • 2023-03-07
    • 2019-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多