6

だから、これはエッジケースのように見えるかもしれませんが、私はこれが可能かどうか単に疑問に思っています。私が持っているのは、静的セットと遅延セットの組み合わせで、IEnumerableたとえば次のようにラップされています。

public IEnumerable<T> MakeMyQuery<T>()
{
    // returns a List<T>
    var someStaticData = LoadMyStaticDataFromDatabase();

    // Returns IEnumerable<T>, but from another resource
    var deferredQuery = CreateADeferredQueryUsingYieldReturn(); 

    return someStaticData.Concat(deferredQuery);
}

したがって、ここで何が起こるかというと.Take(someNumber)、列挙型を呼び出すと、遅延コンポーネントの評価を試みる前に、最初に静的データから要素が返されます。事実上、時間のかかる可能性のある生成タスクを列挙型の背後に「隠して」、これらの要素を取得する必要はありません。LINQの性質が延期されているため、実際には評価されません。

ただし、後で使用するためにこのクエリをキャッシュすることはできないと思います(Iteratorの状態がキャッシュに保持されるとは思いませんか?)または、結果を列挙せずにこれを行う簡単な方法はありますか?保存する?

理想的には、私のフローは次のようになります。

public List<T> SomeMethod<T>(int numberOfGuys)
{
     IEnumerable<T> query = null;

     if(// Is in Cache)
       query = Cache["MyQuery"];
     else
     {
         query = MakeMyQuery();
         Cache["MyQuery"] = query;
     }

     return query.Take(numberOfGuys).ToList();
}

したがって、同じクエリを何度も再利用してデータを要求できますが、DBを再クエリする必要がない可能性があります。これを行う方法はありますか?

4

5 に答える 5

2

query.Take(numberOfGuys).ToList()結果を新しいリストにキャッシュしたいと思います。呼び出す前MakeMyQuery()に、キャッシュされたリスト内の要素の数を確認し (存在する場合)、キャッシュされたリスト内の要素の数がそれ以上である場合は、キャッシュされたリストから をnumberOfGuys返しnumberOfGuysます。それ以外の場合は、キャッシュされたリストを の新しい結果に置き換えますquery.Take(numberOfGuys).ToList()

default.krammer が指摘したように、実際にキャッシュしたいのはLoadMyStaticDataFromDatabase()、 ifnumberOfGuysが常に より小さいため、 がによって返される数値よりも大きくなるLoadMyStaticDataFromDatabase()まで DB に繰り返しアクセスすることになるため、おそらく本当にキャッシュしたい結果です。したがって、メソッドでのキャッシングとでのキャッシングを組み合わせて行うことができます。これにより、DB を 1 回だけヒットできますが、.numberOfGuysLoadMyStaticDataFromDatabase()LoadMyStaticDataFromDatabase()MakeMyQuery<T>()query.Take(numberOfGuys).ToList()SomeMethod<T>(int numberOfGuys)IEnumerable<T>

于 2013-02-15T20:58:31.547 に答える
0

これは少し古風かもしれませんが、ADO.NETレイヤーのDataSetとDataTableが切断されたレイヤーであるため、データベースからADO.NETDataSetを埋めることができる可能性があります。次に、データセットは、アプリケーションによって決定された時間メモリに保持される可能性があります。次に、それをデータベースにポストバックできます。データセットを作成し、エンティティ、ADO.NET接続レイヤー、またはLinq to SQLレイヤーから入力します。データセットは入力済みであり、必要に応じてさらに新しいデータを入力し、最終的なクエリでデータベースと比較してマージします。変更。

しばらく前に、Linq、ADO.NET、およびxmlシリアル化を組み合わせて、基本的にADO.NETから組み込みのxmlシリアル化を使用してデータをxmlファイルにシリアル化するプロジェクトを行ったことを知っています。次に、LinqtoXMLで読み取ります。XMLファイルは基本的にファイル形式のキャッシュであり、データベース内のキー値を表す個別の要素をカウントすることで変更を加えて更新したという点で、あなたが言っていることと似ていました。カウントがオフの場合は更新され、それ以外の場合は同じままでした。これは、何百万もの行の大規模なセットには適用できませんでしたが、私が常にアクセスできるようにしたかった小さなものには、素晴らしく、かなり高速でした。

.NET 4.0DataAccessの70-516MSPressの本には、オンラインで見つけることができれば、キャッシュに関する本の終わり近くにラボがあることを知っています。これは基本的にデータベースを対象とし、前回からの変更を収集し、それを処理して、最後にマージします。そうすれば、メモリ内では小さいが、作業の変更を追跡する差分を常に使用できます。

于 2013-02-15T20:16:11.797 に答える
0

はい、反復に値をキャッシュすると可能です。

次のようになります。

var lazyList = MakeMyQuery<int>().ToLazyList();
var list1 = lazyList.Take(2).Sum();
var list2 = lazyList.Take(3).Sum();
var list3 = lazyList.Take(1).Sum();

この場合: f

  • 最初の 3 つの項目は、合計 1 回のみ MakeMyQuery から生成されます。
  • 4 番目のアイテムは生成されていません。

遅延リストの実装例はこちらです。

于 2013-10-12T20:42:53.987 に答える
0

たぶん、私はあなたの質問を完全には理解していません。もしそうなら、私に知らせてください、私は私の答えを再定式化します。

あなたが書いたものは、すでにあなたが望むように振る舞うと信じています。次のおもちゃの例を考えてみましょう(表示するコードに似ています)。テストはしていませんが、Take項目が 4 つ未満の場合はSuperExpensiveQuery.

static IEnumerable<int> SuperExpensiveQuery()
{
    Console.WriteLine("super expensive query (#1)");
    yield return 100;
    Console.WriteLine("super expensive query (#2)");
    yield return 200;
    Console.WriteLine("super expensive query (#3)");
    yield return 300;
    Console.WriteLine("super expensive query (#4)");
}

static IEnumerable<int> MakeMyQuery()
{
    var someStaticData = new int[] { 1, 2, 3 };
    var deferredQuery = SuperExpensiveQuery();
    return someStaticData.Concat(deferredQuery);
}

static void Test()
{
    var query = MakeMyQuery();
    for (int i = 0; i <= 7; i++)
    {
        Console.WriteLine("BEGIN Take({0})", i);
        foreach (var n in query.Take(i))
            Console.WriteLine("    {0}", n);
        Console.WriteLine("END Take({0})", i);
    }
    Console.ReadLine();
}
于 2013-02-15T21:04:38.377 に答える
0

私のプロジェクトの1つで同様の要件がありました。私が最終的にやったのは、各コンポーネントの DAL で継承する DataAccesLayer (DAL) キャッシュ ベースを作成することです。キャッシュを保持する別のキャッシング クラスがあります。すべてのオブジェクトに ID と名前があることに注意してください。必要に応じて基本クラスを調整できます。

DAL 基本クラス:

public abstract class DALBaseCache<T>
    {
        public List<T> ItemList
        {
            get
            {
                List<T> itemList = DALCache.GetItem<List<T>>(typeof(T).Name + "Cache");

                if (itemList != null)
                    return itemList;
                else
                {
                    itemList = GetItemList();
                    DALCache.SetItem(typeof(T).Name + "Cache", itemList);
                    return itemList;
                }
            }
        }

        /// <summary>
        /// Get a list of all the Items
        /// </summary>
        /// <returns></returns>
        protected abstract List<T> GetItemList();

        /// <summary>
        /// Get the Item based on the ID
        /// </summary>
        /// <param name="name">ID of the Item to retrieve</param>
        /// <returns>The Item with the given ID</returns>
        public T GetItem(int id)
        {
            return (from item in ItemList
                    where (int)item.GetType().GetProperty("ID").GetValue(item, null) == id
                    select item).SingleOrDefault();
        }

        /// <summary>
        /// Get the Item based on the Name
        /// </summary>
        /// <param name="name">Name of the Item to retrieve</param>
        /// <returns>The Item with the given Name</returns>
        public T GetItem(string name)
        {
            return (from item in ItemList
                    where (string)item.GetType().GetProperty("Name").GetValue(item, null) == name
                    select item).SingleOrDefault();
        }
    }

次に、基本的にクエリの辞書を保持するキャッシュ クラス

public static class DALCache
{
    static Dictionary<string, object> _AppCache = new Dictionary<string, object>();

    public static T GetItem<T>(string key)
    {
        if(_AppCache.ContainsKey(key))
        {
            return (T) _AppCache[key];
        }
        else
        {
            return default(T);
        }
    }

    public static void SetItem(string key, object obj)
    {
        _AppCache.Add(key, obj);
    }
}

最後に、キャッシュされたリストを使用した実装です。私は EF を使用して CustomerType リストを取得し、残りのアプリケーション ライフのためにキャッシュします。これは必要に応じて変更できます。

public class CustomerTypeDAL: DALBaseCache<CustomerType>
{
    protected override List<CustomerType> GetItemList()
    {
        DBEntities entities = new DBEntities();
        return Mapper.Map <List<CustomerType>>(entities.GetAllCustomerTypes().ToList());
    }
}

コードのどこでも、次のように使用できます。

CustomerTypeDAL customerTypeDAL = new CustomerTypeDAL();
List<CustomerType> custTypes = customerTypeDAL.ItemList;

初めて呼び出すと、DB から取得されます。その後、キャッシュの後に移動します。

于 2013-02-15T21:41:34.877 に答える