我在C#和Entity框架中工作。 我的数据库中有一个名为Genre的表。这是它的属性: idGenre,name,idParentGenre。
例如。价值观将是:
(idGenre = 1,name =“acoustic”,idParentGenre = 2)
(idGenre = 2,name =“rock”,idParentGenre = 2)
(idGenre = 3,name =“country”,idParentGenre = 4)
(idGenre = 4,name =“folk”,idParentGenre = 5)
(idGenre = 5,name =“someOtherGenre”,idParentGenre = 5)
正如你所看到的,它是一种树。
现在,我有一个搜索这个表的方法。输入参数是idGenre和idParentGenre。如果类型(idGenre)是idParentGenre的儿子/孙子/ grandgrandchild / ...我应该返回。
例如,我得到idGenre = 3,idParentGenre = 5,我应该返回true。
然而,Linq没有递归。有没有办法可以做到这一点?
答案 0 :(得分: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);
}
这使您可以在单个递归函数中处理此问题。
答案 1 :(得分: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);
}
}
答案 2 :(得分: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));
}