4

我正在用 WPF 编写一个应用程序。我正在使用 Entity Framework 5,想知道您是否可以就如何处理以下情况给我建议。

我基本上只有三个表:

项目 {ID,名称}

属性 {ID、名称、类型}

AttributeValue {ItemID, AttributeID, 值}

我们的客户想要为他的物品添加属性,这似乎工作得很好。现在他可以添加属性并为他的项目分配值。第一个问题:你认为这是好的设计吗?

现在的问题是如何在 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 秒),但速度要快得多。按数据网格中的属性对项目进行排序只需一秒钟。使用另一种方法需要很长时间。

我对解决方案不满意,您有什么建议吗?我会欣赏任何形式的批评(我知道两者都不是好的解决方案)。

谢谢,

托马斯

编辑

为了让第一个问题更清楚,一个小例子:

项目:Item1,Item2,Item3,... 属性:宽度,高度,速度,... AttributeValues:(Item1,宽度,100),(Item1,Height,200),(Item2,Width,100),(Item3 , 身高, 200), (Item3,Speed,40)

所以这是一个经典的多对多关系。一个属性可能出现在 0-many Items 中,并且 Item 可能有 0-many 属性。

4

2 回答 2

2

您的数据模型是一个非常通用的解决方案,并且有支持和反对它的论据,但如果没有更多背景很难判断,所以我将跳过这部分问题。

我可能会像您一样实现类似的缓存,但稍作修改。

  • 我不会使用全局静态缓存,而是每个实体一个字典,只缓存该实体的属性值。这样,如果实体超出范围,您不必关心从全局缓存中删除条目,因为缓存会与实体一起进行垃圾收集。

  • 我不会预先填充字典,而是首先尝试从缓存中获取值,如果它不存在,则搜索属性值列表并按需更新缓存。如果应用程序表现良好并且不会一次访问所有值 - 例如,因为在任何时候只有一些数据在网格中可见,而其他行不可见 - 这可以在延长的时间段内无缝分布缓存填充过程并使其不被用户注意到。

最后的想法 - 20,000 个项目,每个项目有 400 个属性?哪个用户应该能够使用一次显示多达 8,000,000 个值的应用程序?也许您还应该考虑重新设计用户界面和交互逻辑——没有人需要并且可以同时处理这么多信息。

于 2013-01-23T22:15:41.333 回答
0

回答您的第一个问题:为什么不合并 Attribute 和 AttributeValue?一个 AttributeValue 可以有更多的属性吗?我猜它是可以有多个属性的项目。

项目 {ID,名称}

属性 {ID、ItemID、名称、类型、值}


我试图给你写一个回答你的问题,但是当我深入研究你的问题时,我开始不确定你在做什么。您是否尝试在数据库中创建动态表?*

这是我的其余答案:


你需要弄清楚你的性能瓶颈在哪里。它是检索数据还是显示数据。

15 秒对于显示的数据来说听起来很长。恕我直言,它不应该超过 1 到 2 秒。

这里有几个提示:

DataGrid 是一个重量级的控件,可以做很多事情。我建议您将 ListView 与 GridView 一起使用,并根据您必须具备的任何要求自定义您。

ListView 默认是虚拟化的。在 4.0 中,如果您应用分组虚拟化将被禁用。在 4.5 中可以应用带有分组的虚拟化。

使用 SQL Profiler 优化数据库查询。查看执行了哪些查询。如果执行大量查询,这可能会导致性能下降。在 EF 中进行预加载(使用 .Include)可以帮助加快速度。记住正确的索引。

评论 Ladislav Mmka 的评论并不是全部真相。WPF 控件不支持数据虚拟化(仅在显示时获取数据)。它们仅支持所有数据都存在的普通虚拟化,但仅呈现项目的可见部分。两者差别很大。有一些解决方案试图在 WPF 中进行数据虚拟化。

于 2013-01-23T15:47:12.533 回答