User表通常是我們在寫“XX管理系統”項目時必須要用到的,有的情況下人員的分類屬於樹形結構,就是除了最高層和最低層,中間層都有相對的父和子,設計數據庫的時候,我們通常會加一個parent_id這樣的字段。這樣我們就可以通過當前用戶的user_id查詢出他的直接下屬有哪些,或者通過parent_id查詢出他的直接上司是誰。
但是當我們想通過user_id去查詢出其所有下屬的時候,就不是能用一條簡單的sql能實現的了。如果項目要是.Net Framework3.5以下的,就是沒有Linq的時候,通常會在數據庫裡寫一個函數,然後在寫sql的時候直接調用函數就能得到一個篩選出來的結果集。如果是Linq呢?我想應該就是要寫一個靜態方法了,正好自己遇到了一個這樣的問題,也是剛接觸Linq,所以試著寫了一下。
不過無論是在數據庫中寫函數還是在項目中寫一個靜態方法,我想都是要用到遞歸去實現的。
我的思路就是傳入當前的user_id然後返回它的所有下屬的結果集。最後在這個結果集上去根據條件查詢。但是,在寫這個方法的過程中還是遇到了幾個問題:
1、如何將查詢出來的結果集var類型,轉換成List<T>類型
最開始我是這樣去寫的
/*大錯特錯*/ var list = from ....... where.... select...; ..... return list.ToList<T>();
現在看看我還是挺有創造力的哈,居然能寫出這麼個東西。
首先不說list.ToList<T>();本身就畫紅線,為什麼我要在最後 return 的時候才去ToList()呢?原因是我知道var 可以用“+=”運算符。這樣遞歸的時候將深一層的返回值直接+到一起,用起來方便一些。
啊~真是大錯特錯了,首先,按照我的思路,深一層返回的值已經是ToList類型了,所以不能再用+=運算符了.其次,好吧,我承認,我還是沒有太了解var是個什麼東西。其實在程序運行之後,list就會有一個明確的類型,是系統去自動判定出來的。var只是使我們編程的時候更方便一些,有點像程序蜜糖(忘記是從哪聽來的了),也就是說系統應該能識別出list是一個T類型對象的集合,而我這麼寫就有點畫蛇添足的意味了。
正解:
var list = (from ....... where.... select...).ToList(); ..... return list;
這樣,list 就會變成我想要的List<T>類型了,因為函數的返回值就是這個類型,所以正是我想要的。
2、提示報錯:Collection was modified; enumeration operation may not execute.
這個錯誤的原因是因為用foreach遍歷的時候,對Collection(這裡的temp)這個數據集進行了Add/Remove操作。這樣就有可能在未遍歷到最後的時候,就把這個Collection給修改了,隨之就報錯了。解決辦法有說用for代替foreach的,但是我還是覺得foreach要好些,所以創建了一個Collection這個結果集副本,然後一個用作遍歷,一個用作Add/Remove操作,當然,返回的是用後者。
注意創建副本的時候一定新new一個對象,而不是直接聲明之後賦值,否則跟沒寫一樣。
List<T> tmpList = list; //錯誤 List<T> tmpList = new List<T>(list);//正確
最後完整的代碼為:
contextdata ctdt = new contextdata(); public static List<db_userinfo> findallchildren(int parentid) { var list = (from c in ctdt.db_userinfo where c.parent_id == parentid select c).ToList(); List<db_userinfo> tmpList = new List<db_userinfo>(list); foreach (db_userinfo single in temp) { List<db_userinfo> tmpChildren = findallchildren(single.user_id); if (tmpChildren.Count != 0) { list.AddRange(tmpChildren); } } return list; }
這樣,在頁面的後台代碼.cs文件中,就可以直接把這個方法的返回值作為條件查詢中基礎數據集。如
var result = from c in findallchildren(userid) where.....select....;
應該還有更好的方法,希望比較懂的朋友能多傳授一下,歡迎蓋樓!~