2010-10-06 40 views
4

我有一個類叫做Structure有沒有一種方法,使用LINQ/EF獲取父/子層次結構中最頂級的項目?

public class Structure 
{ 
    public int StructureId { get; set; } 
    public Structure Parent { get; set; } 
} 

正如你所看到的,Structure有父Structure。這個層次結構中可以有無限數量的結構。

有沒有什麼辦法,使用LINQ(與實體框架),在這個層次結構中獲得最頂級的結構?

目前,我不得不擊中數據庫幾次,以找到最上面的父母。最頂端的母公司是一個Structure用空Parent屬性:

Structure structure = structureRepository.Get(id); 
while (structure.Parent != null) 
{ 
    structure = structureRepository.Get(structure.Parent.StructureId); 
} 

// When we're here; `structure` is now the top most parent. 

那麼,有沒有任何優雅的方式來做到這一點使用LINQ/Lambda表達式?理想的情況下,開始用下面的代碼:

var structureQuery = from item in context.Structures 
        where item.StructureId == structureId 
        select item; 

我只是希望能夠寫出像下面這樣我只火了一個數據庫命中:

structureQuery = Magic(structureQuery); 
Structure topMostParent = structureQuery.Single(); 
+0

我不認爲這是可能的,但我很好奇其他人可能想出的解決方案...... – jeroenh 2010-10-06 15:22:39

+1

哪個數據庫,MSSQL? – 2010-10-06 15:22:59

+0

@Nick - MS SQL 2005. @jeroenh - 是的,我也不這麼認爲。我編寫了當前完成這項工作的存儲過程,並且它自己碰到了數據庫幾次。 – GenericTypeTea 2010-10-06 15:24:09

回答

2

我想我會得到最好的是從結構加載整個層次一重擊我想要的頂部父:

var structureQuery = from item in context.Structures 
         .Include(x => x.Parent) 
        where item.StructureId == structureId 
        select item; 

然後,只需使用代碼:

while (structure.Parent != null) 
{ 
    structure = structure.Parent; 
} 
-1

我喜歡這個問題,並能沒有想到這樣做的方式。但是,您是否可以在存儲庫類上實現這個功能?畢竟,頂端應該只有一個,如果需要它,那麼也許它應該是structureRepository.GetRoot()什麼的。

+0

感謝您的輸入,但它在我的資源庫中(我給出的代碼是一個示例,而不是我的資源庫類),這不是答案;也許你應該刪除它並將其表示爲註釋:)。 – GenericTypeTea 2010-10-06 15:25:29

-4

你可以使用LINQ取結構,例如

  var first3Customers = (
       from c in customers 
       select new {c.CustomerID, c.CustomerName}) 
      .Take(2); 
+2

你真的讀過這個問題嗎? – jeroenh 2010-10-06 15:37:05

+0

哈哈哈!我想(希望)有人的同伴壓力徽章瞄準在這裏... – teedyay 2010-10-06 16:15:26

0

我有類似的情況。我沒有設法直接用LINQ/EF解決它。相反,我通過使用遞歸公用表表達式創建數據庫視圖來解決,如here所述。我創建了一個用戶定義的函數,它將所有父項應用於子項(反之亦然),然後創建一個使用此用戶定義函數的視圖,該函數已導入到EF對象上下文中。

(免責聲明:簡化代碼,我其實沒有測試這個)

我有兩個表,說MyTable的(包含所有項目),並含有childID的,的ParentId關係

然後我定義MyParentChildTable以下UDF:

CREATE FUNCTION dbo.fn_getsupertree(@childid AS INT) 
    RETURNS @TREE TABLE 
(
    ChildId INT NOT NULL 
    ,ParentId INT NULL 
    ,Level INT NOT NULL 
) 
AS 
BEGIN 
    WITH Parent_Tree(ChildId, ParentId) 
    AS 
    ( 
    -- Anchor Member (AM) 
    SELECT ChildId, ParentId, 0 
    FROM MyParentChildTable 
    WHERE ChildId = @childid 

    UNION all 

    -- Recursive Member (RM) 
    SELECT info.ChildId, info.ParentId, tree.[Level]+1 
    FROM MyParentChildTable AS info 
     JOIN Parent_Tree AS tree 
     ON info.ChildId = tree.ParentId 
) 
    INSERT INTO @TREE 
    SELECT * FROM Parent_Tree; 

    RETURN 
END 

和以下觀點:

CREATE VIEW VwSuperTree AS (
SELECT tree.* 
FROM MyTable 
CROSS APPLY fn_getsupertree(MyTable.Id) as tree 
) 
GO 

這給了我每個孩子,所有父母都有他們的「樹木級別」(直接父母有1級,父母父母有2級,等等)。從這個角度來看,查詢具有最高級別的項目很容易。我只是在我的EF上下文中導入了視圖,以便能夠使用LINQ查詢它。

+0

是的,我已經有類似的東西了。我目前正試圖將盡可能多的存儲過程轉移到EF。這可能是那些必須作爲存儲過程保留的那些之一。 – GenericTypeTea 2010-10-06 15:39:29

2

這不是一個直接的答案,但是您遇到的問題與您存儲樹的方式有關。有幾種方法通過對數據進行不同的結構來簡化查詢。

一個是使用Nested Set Hierarchy,它可以簡化樹中的多種查詢。

另一種方法是存儲祖先/後裔/深度元組的非均值表。然後,該查詢將查找具有當前結構的元組作爲具有最大深度的後代。

+0

我正在使用MS SQL 2005.從未聽說過NSHs。 – GenericTypeTea 2010-10-06 15:48:11

+1

@GenericTypeTea這不是數據庫引擎功能,只是構建數據的一種方式,以便可以使用標準SQL輕鬆查詢。下面是關於SQL Server的討論:http://blogs.msdn.com/b/anthonybloesch/archive/2006/02/15/hierarchies-in-sql-server-2005.aspx – 2010-10-06 17:21:01

+0

有趣的方法 – jeroenh 2010-10-06 17:42:31

相關問題