0

ISortable インターフェイスを実装するクラスがいくつかあります。

public interface ISortable
{
    int Id { get; set; }
    int? Idx { get; set; }
}

私の DbContext クラスには、ISortable を実装するエンティティに対していくつかの追加処理を行う update メソッドがあります。

public void UpdateSingle<T>(T item) where T : class
{
    // If entity is Sortable, update the indexes of the records between the new and the old index of the updated entity
    var sortable = item as ISortable;
    if (sortable != null)
    {
        Detach(item);   // need to detach the entity from the context in order to retrieve the old values from DB
        var oldItem = Find<T>(sortable.Id) as ISortable;

        if (oldItem != null && sortable.Idx != oldItem.Idx)
        {
            var entities = FindAll<T>().ToList().Cast<ISortable>();

            var oldIdx = oldItem.Idx;
            var newIdx = sortable.Idx;

            if (newIdx > oldIdx)
            {
                var toUpdate = entities.Where(a => a.Idx <= newIdx && a.Idx > oldIdx).Select(a => a);
                foreach (var toUpdateEntity in toUpdate)
                {
                    toUpdateEntity.Idx = toUpdateEntity.Idx - 1;
                }
            }
            else
            {
                var toUpdate = entities.Where(a => a.Idx >= newIdx && a.Idx < oldIdx).Select(a => a);
                foreach (var toUpdateEntity in toUpdate)
                {
                    toUpdateEntity.Idx = toUpdateEntity.Idx + 1;
                }
            }
        }

        Detach(oldItem);
        Attach(item);   // re-attach to enable saving
    }

    Entry(item).State = EntityState.Modified;

    Commit();
}

私が疑問に思っているのは、次の行です。

var entities = FindAll<T>().ToList().Cast<ISortable>();

エンティティを ISortable にキャストするには、LINQ to SQL 式をリストに変換する必要があります。そして、これを実行するために ISortable にキャストする必要があります Where:

var toUpdate = entities.Where(a => a.Idx <= newIdx && a.Idx > oldIdx).Select(a => a);

Idx 属性は、インターフェースによって公開されます。

問題は、FindAll() で ToList() を呼び出すと、テーブル全体がメモリに読み込まれることです。

最初にテーブル全体をロードせず、汎用実装を失うことなく Where を実行する方法はありますか?

ここでの考え方は、「並べ替え可能な」すべてのエンティティの更新時に共通のアクションを実行したいということです。これが機能するには、さまざまなクラスを処理するために更新メソッドを汎用にする必要がありますが、必要なフィールドを公開するためのインターフェイスが必要です...これを行うためのより良い方法がある場合 (おそらくある)、お知らせください。 . :-)

4

3 に答える 3

0

メソッドのシグネチャを次のように変更するだけです。

public void UpdateSingle<T>(T item)
    where T : class, ISortable

次に、DB側でクエリを実行できるだけでなく(特定の条件を満たすアイテムを取得するためにコレクションをメモリにプルする必要はありません)、実行時にチェックを行うこともありません。コンパイル時Tに確実に実装さISortableれていることを確認します。

于 2013-07-01T17:22:56.653 に答える
0

問題は、FindAll() で ToList() を呼び出すと、テーブル全体がメモリに読み込まれることです。

AsEnumerableの代わりに使用しToListます。コンパイル時の型をIEnumerable<T>ではなく に変更するだけなIQueryable<T>ので、後続の操作はデータベースではなくメモリ内で実行されますが、一度に 1 つの項目のみが処理されます (項目は、後続の操作で必要に応じて DB から 1 つずつフェッチされます)。オペレーション)。

于 2013-07-01T12:47:33.830 に答える