4

私はWPFでアプリケーションを書いています。Entity Framework 5 を使用していますが、次のような場合の対処方法についてアドバイスをいただけないでしょうか。

私は基本的に3つのテーブルしか持っていません:

アイテム {ID、名前}

属性 {ID、名前、タイプ}

AttributeValue {アイテムID、属性ID、値}

クライアントは自分のアイテムに属性を追加したいと考えており、これは非常にうまく機能しているようです。これで、属性を追加して、それらに値をアイテムに割り当てることができます。最初の質問: これは良いデザインだと思いますか?

問題は、アイテムを 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 の値がある) で非常に遅くなるオプションが 1 つあります。

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 秒) がかかりますが、その後ははるかに高速です。データグリッドの属性で項目を並べ替えるのに 1 秒しかかかりません。他のアプローチでは、それは何年もかかりました。

解決策に満足していません。何か提案はありますか? どんな種類の批判も歓迎します (どちらも良い解決策ではないことはわかっています)。

ありがとう、

トーマス

編集

最初の質問をより明確にするために、小さな例を示します。

項目: Item1,Item2,Item3,... 属性: Width, Height, Speed, ... AttributeValues: (Item1, Width, 100), (Item1,Height,200), (Item2,Width,100), (Item3 , 高さ, 200), (Item3,Speed,40)

つまり、これは典型的な多対多の関係です。属性は 0-many アイテムに表示される場合があり、Item は 0-many 属性を持つ場合があります。

4

2 に答える 2

2

あなたのデータモデルは非常に一般的な解決策であり、賛否両論がありますが、背景がないと判断するのは難しいので、質問のこの部分はスキップします。

私はおそらくあなたと同様のキャッシュを実装したでしょうが、いくつかの変更が加えられています.

  • グローバルな静的キャッシュは使用せず、エンティティごとに 1 つのディクショナリを使用して、このエンティティのプロパティ値のみをキャッシュします。この方法では、キャッシュがエンティティと一緒にガベージ コレクションを取得するため、エンティティが範囲外になった場合に、グローバル キャッシュからエントリを削除することを気にする必要がありません。

  • ディクショナリを事前設定するのではなく、まずキャッシュから値を取得しようとします。値が存在しない場合は、プロパティ値リストを検索し、必要に応じてキャッシュを更新します。アプリケーションの動作が良好で、一度にすべての値にアクセスしない場合 (たとえば、グリッド内で常に一部のデータしか表示されず、他の行が表示されないなど)、これにより、キャッシュの作成プロセスが長時間にわたってシームレスに分散される可能性があります。ユーザーに気付かれないようにします。

最終的な考え - それぞれ 400 の属性を持つ 20,000 のアイテム? 一度に最大 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 プロファイラーを使用してデータベース クエリを最適化します。どのクエリが実行されたかを確認します。多くのクエリが実行されると、パフォーマンスが低下する可能性があります。EF で (.Include を使用して) 熱心な読み込みを行うと、速度が向上する可能性があります。適切なインデックスを覚えておいてください。

Ladislav Mmka のコメントにコメントすることは、完全な真実ではありません。WPF コントロールはデータの仮想化をサポートしていません (データは表示されている場合にのみフェッチされます)。すべてのデータが存在する通常の仮想化のみをサポートしますが、アイテムの表示可能な部分のみがレンダリングされます。両者の大きな違い。WPF でデータの仮想化を試みるソリューションがあります。

于 2013-01-23T15:47:12.533 に答える