2011-12-28 97 views
3

我在C#和Entity框架中工作。 我在我的數據庫中有一個名爲Genre的表格。以下是它的屬性: idGenre,名稱,idParentGenre。Linq查詢遞歸

例如。的值將是:

(idGenre = 1,名字= 「聲」,idParentGenre = 2)

(idGenre = 2,名字= 「搖滾」,idParentGenre = 2)

(idGenre = 3,名字= 「國家」,idParentGenre = 4)

(idGenre = 4,名字= 「民間」,idParentGenre = 5)

(idGenre = 5,名字= 「someOtherGenre」,idParentGenre = 5)

正如你所看到的,它是一棵樹。

現在,我有一個通過此表進行搜索的方法。輸入參數是idGenre和idParentGenre。如果該類型(idGenre)是idParentGenre的兒子/孫子/ grandgrandchild/...,我應該返回。

例如,我得到idGenre = 3,idParentGenre = 5,我應該返回true。

但是,在Linq中沒有遞歸。有什麼辦法可以做到這一點?

+0

你是什麼意思「遞歸Linq中」的意思。你能展示你的方法嗎?它有什麼問題? – alf 2011-12-28 20:57:44

+1

做它舊時尚的方式。 LINQ很棒,但它不能解決所有問題。 – cadrell0 2011-12-28 20:59:57

回答

4

我會做的方法,而不是處理使用LINQ的這個:

bool HasParent(int genre, int parent) 
{ 
    Genre item = db.Genres.FirstOrDefault(g => g.IdGenre == genre); 
    if (item == null) 
     return false; 

    // If there is no parent, return false, 
    // this is assuming it's defined as int? 
    if (!item.idParentGenre.HasValue) 
     return false; 

    if (item.idParentGenre.Value == parent) 
     return true; 

    return HasParent(item.idParentGenre, parent); 
} 

這使您可以在一個單一的遞歸函數處理這個問題。

2

它看起來像你試圖實現一棵樹,而不使用樹。

你有沒有考慮......使用樹?這裏有一個great question和一些答案,你可以建立關(其中包括與code

delegate void TreeVisitor<T>(T nodeData); 

class NTree<T> 
{ 
    T data; 
    LinkedList<NTree<T>> children; 

    public NTree(T data) 
    { 
     this.data = data; 
     children = new LinkedList<NTree<T>>(); 
    } 

    public void addChild(T data) 
    { 
     children.AddFirst(new NTree<T>(data)); 
    } 

    public NTree<T> getChild(int i) 
    { 
     foreach (NTree<T> n in children) 
      if (--i == 0) return n; 
     return null; 
    } 

    public void traverse(NTree<T> node, TreeVisitor<T> visitor) 
    { 
     visitor(node.data); 
     foreach (NTree<T> kid in node.children) 
      traverse(kid, visitor); 
    }   
} 
+1

我不能使用樹。爲了這個目的,我在我的數據庫中有一個表格。 – 2011-12-28 21:05:13

1

帶來流派的表中存儲(不能是大),並且遞歸遍歷它的idGenre之間創建一個映射及其後代的傳遞閉包,就像這樣:。

1: {1, 2} 
2: {2} 
3: {3, 4, 5} 
4: {4, 5} 
5: {5} 

上述數據保持只在內存您在啓動每次重新計算它,並更新到流派表

當需要在一個特定的類型來查詢所有歌曲,使用預先計算表中的idGenre in ...查詢,例如:

IEnumerable<Song> SongsWithGenreId(int idGenre) { 
    var idClosure = idToIdClosure[idGenre]; 
    return context.Songs.Where(song => idClosure.Contains(song.idGenre)); 
} 
+0

但這不是一個完美的解決方案。我已經有了一個地方可以放置父母的身份證(這個地方就是桌子),但我不認爲爲了同一個目的,另一個地方是好的。 – 2011-12-28 21:07:54

+0

@Srcee它不是「另一個地方」來存儲你的數據,它是一個相同數據的緩存,只有預處理。您的查詢速度非常快 - 迄今爲止建議的速度要快得多,因爲只有一次往返。所有的遞歸都會被放到'idToIdClosure'字典的結構中,這很好,因爲類型不會經常改變。 – dasblinkenlight 2011-12-28 21:12:48