我正在使用另一个网站上的代码:
How can I model this class in a database?
我在每个客观记录中都有一个名为“Rank”的字段。它告诉我什么位置。例如:
Objective "Geometry": Rank1
|_Objective "Squares": Rank1
|_Objective "Circles": Rank2
|_Objective "Triangle": Rank3
|_Objective "Types": Rank1
Objective "Algebra": Rank2
Objective "Trigonometry": Rank3
该等级告诉我节点的顺序。但我希望获得所有排名:
Objective "Geometry": Rank1
|_Objective "Squares": Rank1 -> 1.1
|_Objective "Circles": Rank2
|_Objective "Triangle": Rank3
|_Objective "Types": Rank1 -> 1.3.1
Objective "Algebra": Rank2
Objective "Trigonometry": Rank3 -> 3
我正在使用LINQ to SQL。
<TreeView Name="treeView1">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type data:Objective}" ItemsSource="{Binding Path=Objectives}" >
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
我需要一个linq函数,我可以在其中获取指定的节点。我的意思是,一个函数通过级别(1.2),(1.3.1)
获取节点如果存在,则返回节点,如果不为null。
更新1:
这不是真正的功能,但我意识到最好创建一个getNode函数。
private void AddButton_Click(object sender, RoutedEventArgs e)
{
NorthwindDataContext cd = new NorthwindDataContext();
int[] levels = LevelTextBox.Text.ToIntArray('.');
string newGroupName = NameTextBox.Text;
Objective currentObjective = null;
int? identity = null;
for (int i = 0; i < levels.Length - 1; i++ )
{
int currentRank = levels[i];
if (identity == null)
{
currentObjective = (from p in cd.Objective
where p.Level == currentRank && p.Parent_ObjectiveID == null
select p).SingleOrDefault();
}
else
{
currentObjective = (from p in cd.Objective
where p.Level == currentRank && p.Parent_ObjectiveID == identity
select p).SingleOrDefault();
}
if (currentObjective == null)
{
MessageBox.Show("Levels don't exist");
return;
}
else
{
identity = currentObjective.ObjectiveID;
}
}
if (currentObjective != null)
{
if (levels.Last() == currentObjective.Level)
{
MessageBox.Show("Level already exists");
return;
}
}
else
{
var aux = (from p in cd.Objective
where p.Parent_ObjectiveID == null && p.Level == levels.Last()
select p).SingleOrDefault();
if (aux != null)
{
MessageBox.Show("Level already exists");
return;
}
}
var newObjective = new Objective();
newObjective.Name = NameTextBox.Text;
newObjective.Level = levels.Last();
newObjective.Parent_ObjectiveID = currentObjective == null ? null : (int?)currentObjective.ObjectiveID ;
cd.Objective.InsertOnSubmit(newObjective);
cd.SubmitChanges();
}
更新2:
public Objective GetNode(params int[] indexes)
{
return GetNode(null, 0, indexes);
}
public Objective GetNode(int? parentid, int level, params int[] indexes)
{
NorthwindDataContext cd = new NorthwindDataContext();
Objective item = null;
if (indexes.Length == 0)
return null;
if (parentid == null)
{
item = (from p in cd.Objective
where p.Level == indexes[level] && p.Parent_ObjectiveID == null
select p).SingleOrDefault();
}
else
{
item = (from p in cd.Objective
where p.Level == indexes[level] && p.Parent_ObjectiveID == parentid
select p).SingleOrDefault();
}
if (item == null)
return null;
if (++level < indexes.Length)
item = GetNode(item.ObjectiveID, level, indexes);
return item;
}
答案 0 :(得分:1)
修改:
您可能最好传入NorthwindDataContext的实例,而不是每次传递都创建一个新实例。
你可以通过创建一个如下方法来做到这一点,该方法已被重构,因此它不需要递归,这应该对可读性部门有所帮助。
public Objective GetNode(IEnumerable<Objective> collection, params int[] indices)
{
Objective current = null;
for (int t = 0; t < indices.Length; t++)
{
Objective item = collection.SingleOrDefault(x => x.Parent == current && x.Rank == indices[t] - 1);
if (item == null)
return null;
}
return current;
}
被称为:GetNode(cd.Objective, LevelTextBox.Text.ToIntArray());
原件: 你可以使用这样的东西,它只是一个简单的扩展方法:
public static TreeViewItem Get(this TreeView tree, params int[] indexes)
{
if (tree == null)
return null;
if (indexes == null || indexes.Length == 0)
return null;
TreeViewItem i = tree.Items[indexes[0] - 1] as TreeViewItem;
for (int index = 1; index < indexes.Length; index++)
{
i = i.Items.Count >= indexes[index] - 1 ? i.Items[indexes[index] - 1] as TreeViewItem : null;
if (i == null)
return null;
}
return i;
}
并且会被treeView1.Get(1,3,1);
使用,或者在您的编辑时使用treeView1.Get(LevelTextBox.Text.Split('.').Select(x => int.Parse(x)).ToArray());
但是,对于无效输入,这会有零错误处理。
如果您无法确定所有项目都是TreeViewItem对象,则可以将tree.Items[...]
替换为tree.ItemContainerGenerator.ContainerFromIndex(...)
(与i.Items
相同
但是,这些更改将要求TreeView完全呈现。
答案 1 :(得分:1)
这是一种LINQ方式。
我假设Objective
的定义如此:
public class Objective
{
public int ObjectiveId { get; set; }
public int? Parent_ObjectiveId { get; set; }
public string Name { get; set; }
public int Rank { get; set; }
}
然后我创建了一个名为LevelObjective
的支持类来捕获关卡(即“1.3.1”),如下所示:
public class LevelObjective
{
public Objective Objective { get; set; }
public string Level { get; set; }
}
我开始时已定义了一系列目标:
var objectives = new []
{
new Objective { ObjectiveId = 1, Parent_ObjectiveId = null, Name = "Geometry", Rank = 1, },
new Objective { ObjectiveId = 2, Parent_ObjectiveId = 1, Name = "Squares", Rank = 1, },
new Objective { ObjectiveId = 3, Parent_ObjectiveId = 1, Name = "Circles", Rank = 2, },
new Objective { ObjectiveId = 4, Parent_ObjectiveId = 1, Name = "Triangle", Rank = 3, },
new Objective { ObjectiveId = 5, Parent_ObjectiveId = 4, Name = "Types", Rank = 1, },
new Objective { ObjectiveId = 6, Parent_ObjectiveId = null, Name = "Algebra", Rank = 2, },
new Objective { ObjectiveId = 7, Parent_ObjectiveId = null, Name = "Trigonometry", Rank = 3, },
};
接下来,我创建了一个查找以获取任何ID的孩子。
var lookup = objectives.ToLookup(x => x.Parent_ObjectiveId);
我用这个查找来创建一组顶级目标:
var roots = lookup[null]
.Select(o => new LevelObjective()
{
Objective = o,
Level = o.Rank.ToString(),
});
然后我定义了一个使层次结构变平的函数:
Func<
IEnumerable<LevelObjective>,
Func<LevelObjective, IEnumerable<LevelObjective>>,
IEnumerable<LevelObjective>> flatten = null;
flatten = (rs, f) =>
rs.Concat(
from r in rs
from c in flatten(f(r), f)
select c);
我已经将其中一个定义为使用泛型的扩展方法,但我只是重构为使用LevelObjective
的lambda表达式。
我现在定义了获取Func<LevelObjective, IEnumerable<LevelObjective>>
的孩子所需的LevelObjective
。
Func<LevelObjective, IEnumerable<LevelObjective>> getChildren = lo =>
from o in lookup[lo.Objective.ObjectiveId]
select new LevelObjective()
{
Objective = o,
Level = String.Format("{0}.{1}", lo.Level, o.Rank),
};
然后,我可以根据原始的LevelObjective
个对象创建Objective
个对象的完整列表。
var levelObjectives = flatten(roots, getChildren);
最后,我可以将其转换为从关卡到目标的地图。
var map = levelObjectives.ToLookup(x => x.Level, x => x.Objective);
现在,要找到任何目标,我只需要调用此代码:
var objective = map["1.3.1"].FirstOrDefault();
所以现在我有一个函数将为任何提供的级别键返回零个或多个目标。好消息是,这只会对数据库执行一次查询,并且会在o(1)时间内返回对map
函数的调用。
这对你有用吗?