1

我有一个 class Org,它具有ParentId(指向消费者)和Orgs属性,以启用 Org 实例的层次结构。我也有一个类Customer,它有一个OrgId属性。给定任何名为的 Org 实例,Owner我如何检索该组织的所有 Customer 实例?也就是说,在 LINQ 之前,我会以Owner根为根对 Org 树进行“手动”遍历。我确信存在更简单的东西。

示例:如果我有一个名为“Film”的根级别组织,ID 为“1”,子组织名为“Horror”,ParentId 为“1”,ID 为 23,我想查询 Film 下的所有客户,所以我必须让所有客户的 OrgId 都为 1 和 23。

4

2 回答 2

1

Linq 不会帮助您,但 SQL Server 会。

创建一个 CTE 以生成一个扁平化的 Org Id 列表,例如:

CREATE PROCEDURE [dbo].[OrganizationIds]
    @rootId int

AS
    WITH OrgCte AS 
    ( 
        SELECT OrganizationId FROM Organizations where OrganizationId = @rootId
        UNION ALL 
        SELECT parent.OrganizationId FROM Organizations parent
        INNER JOIN OrgCte child ON parent.Parent_OrganizationId = Child.OrganizationId
    ) 
    SELECT * FROM OrgCte 

RETURN 0

现在将函数导入添加到映射到此存储过程的上下文中。这会在您的上下文中产生一个方法(返回的值是可为空的 int,因为原始 Parent_OrganizationId 被声明为 INT NULL):

public partial class TestEntities : ObjectContext
{
    public ObjectResult<int?> OrganizationIds(int? rootId)
    {
        ...

现在您可以使用这样的查询:

// get all org ids for specific root.  This needs to be a separate 
// query or LtoE throws an exception regarding nullable int.
var ids = OrganizationIds(2);

// now find all customers
Customers.Where (c => ids.Contains(c.Organization.OrganizationId)).Dump();
于 2012-05-20T13:39:54.433 回答
0

不幸的是,在实体框架中不是原生的。您需要构建自己的解决方案。可能您需要迭代到根目录。您可以通过要求 EF 一次性获得一定数量的父母来优化此算法,如下所示:

...
select new { x.Customer, x.Parent.Customer, x.Parent.Parent.Customer }

使用这种方法(这里:3),您仅限于静态固定数量的父级,但它将为您节省 2/3 的数据库往返。

编辑:我想我没有得到你的数据模型,但我希望这个想法很清楚。

编辑2:为了回应您的评论和编辑,我采用了这样的方法:

var rootOrg = ...;
var orgLevels = new [] {
 select o from db.Orgs where o == rootOrg, //level 0
 select o from db.Orgs where o.ParentOrg == rootOrg, //level 1
 select o from db.Orgs where o.ParentOrg.ParentOrg == rootOrg, //level 2
 select o from db.Orgs where o.ParentOrg.ParentOrg.ParentOrg == rootOrg, //level 3
};
var setOfAllOrgsInSubtree = orgLevels.Aggregate((a, b) => a.Union(b)); //query for all org levels

var customers = from c in db.Customers where setOfAllOrgsInSubtree.Contains(c.Org) select c;

请注意,这仅适用于有界的最大树深度。在实践中,通常是这种情况(如 10 或 20)。

性能不会很好,但它是一个 LINQ-to-Entities-only 解决方案。

于 2012-05-20T09:11:47.013 回答