我正在WPF中编写一个应用程序。我正在使用Entity Framework 5,并且想知道您是否可以就如何处理以下情况向我提出建议。
我基本上只有三张桌子:
项{ID,Name}
属性{ID,名称,类型}
AttributeValue {ItemID,AttributeID,Value}
我们的客户想要为他的商品添加属性,这看起来效果很好。现在,他可以添加属性并为其项目分配值。第一个问题:你认为这是好设计吗?
现在的问题是如何在WPF DataGrid中显示项目并将所有属性显示为列。这就是我们现在所拥有的:
我们以编程方式生成列:
foreach (var attribute in db.Attributes)
{
datagrid.Columns.Add(new DataGridTextColumn
{
Header = attribute.Name,
Binding = new Binding { Path = new PropertyPath(string.Format("[{0}]", attribute.ID)) }
});
}
这很好用。现在的问题是如何在Items-Class中实现索引器。我们有一个选项,在大量数据的情况下变得非常慢(20.000个项目,400个属性,每个项目都有100个值):
public AttributeValue this[int i]
{
get
{
return AttributeValues.FirstOrDefault(aa => aa.AttributID == i);
}
}
就像我说的,这有效,但速度很慢。而不是总是查询属性值我想到缓存所有内容之前显示如下:
var items = db.Items.AsNoTracking().ToArray();
CachedValues.Values = new Dictionary<int, Dictionary<int, AttributeValue>>(items.Length);
foreach (var item in items)
{
var attributevalues = db.AttributeValue.AsNoTracking().Where(w => w.ArtikelID == item.ID).ToArray();
CachedValues.Values[item.ID] = new Dictionary<int, AttributeValue>(attributevalues.Length);
foreach (var value in attributevalues)
{
CachedValues.Values[item.ID][value.AttributeID] = value;
}
}
我使用静态类作为缓存:
public static class CachedValues
{
public static Dictionary<int, Dictionary<int, ArtikelAttribut>> Values;
}
然后在Items-Class中我可以访问缓存:
public AttributeValue this[int i]
{
get
{
AttributeValue val = null;
CachedValues.Values[ID].TryGetValue(i, out val);
return val;
}
}
显然,初始化缓存需要一些时间(15秒),但后来要快得多。按datagrids中的属性对项目进行排序只需要一秒钟。用另一种方法花了很长时间。
我对解决方案不满意,你有什么建议吗?我会赞赏任何批评(我知道两者都不是好的解决方案)。
谢谢,
托马斯
修改
使第一个问题更清楚一个小例子:
项目:Item1,Item2,Item3,...... 属性:宽度,高度,速度,...... AttributeValues :( Item1,Width,100),(Item1,Height,200),(Item2,Width,100),(Item3,Height,200),(Item3,Speed,40)
所以这是一个经典的多对多关系。一个属性可能出现在0-many Items中,而Item可能有0多个属性。
答案 0 :(得分:2)
你的数据模型是一个非常通用的解决方案,有支持和反对它的论据,但如果没有更多背景,很难判断,所以我将跳过这部分问题。
我可能会像你一样实现类似的缓存,但稍作修改。
我不会使用全局静态缓存,而是每个实体只使用一个字典缓存此实体的属性值。这样,如果实体超出范围,您就不必关心从全局缓存中删除条目,因为缓存会与实体一起收集垃圾。
我不会预先填充字典,而是首先尝试从缓存中获取值,如果不存在,请搜索属性值列表并根据需要更新缓存。如果应用程序运行良好并且不能同时访问所有值 - 例如,因为只有一些数据在网格中可见,而其他行不可见 - 这可以在一段延长的时间内无缝地分配缓存填充过程并使用户无法察觉。
最后的想法 - 20,000个项目,每个400个属性?哪个用户应该能够同时处理多达8,000,000个值的应用程序?也许您还应该考虑重新设计用户界面和交互逻辑 - 没有人需要并且可以一次处理那么多信息。
答案 1 :(得分:0)
回答第一个问题:为什么不合并属性和AttributeValue? AttributeValue可以有更多属性吗?我想这是可以有多个属性的Item。
项{ID,Name}
属性{ID,ItemID,名称,类型,值}
我试图给你一个问题的答案,但是当我挖掘你的问题时,我开始不确定你在做什么。您是否尝试在数据库中创建动态表?*
以下是我的其余答案:
您需要弄清楚性能瓶颈在哪里。是检索数据还是显示数据?
15秒对于显示的数据听起来很多。它不应该超过1到2秒,恕我直言。
以下是一些提示:
DataGrid是一个重量级控件,可以做很多事情。我建议你使用带有GridView的ListView,并根据你必须拥有的要求定制你。
默认情况下,ListView是虚拟化的。在4.0中如果您应用分组虚拟化将被禁用。在4.5中,可以应用具有分组的虚拟化。
使用SQL事件探查器优化数据库查询。查看执行的查询。如果执行大量查询,则可能导致性能下降。在EF(使用.Include)中进行急切加载可以帮助加快速度。记住正确的索引。
评论Ladislav Mmka的评论并非全部真相。 WPF控件不支持数据虚拟化(仅在显示时获取数据)。它们仅支持存在所有数据的正常虚拟化,但仅呈现项目的可视部分。两者之间差异很大。有些解决方案试图在WPF中进行数据虚拟化。