3

私は現在のプロジェクトのいくつかの場所で同じタイプの困難に遭遇し続けています。

最も単純なインスタンスは次のとおりです。

RequestとRequestActionの2つの関連エンティティがあります。各RequestActionにはステータスとタイムスタンプがあり、リクエストを指し示します。

最新の関連するRequestActionのステータスに基づいて、リクエストのコレクションをクエリする必要があります。

例:最新のRequestActionのステータスが「Open」であるすべてのリクエストを取得します。

データベースを非正規化して最新のステータスをRequestエンティティのプロパティにすることはできません。

アプリケーションの他の多くの場所で同じタイプのフィルタリングが必要です。私は履歴と監査のためにアイテムの多くのバージョンを追跡していますが、通常は各アイテムの最新バージョンのみを確認したいと思います。

私は2つの解決策を考えることができますが、どちらも特に魅力的ではありません。

1)SQLを手動で記述できます。この問題に対する生のSQLの答えは、テーブルの1つのインスタンスのタイムスタンプが他のインスタンスよりも大きい場合に外部結合を使用してテーブルをそれ自体に結合し、次に2番目のテーブルがnullであるレコードを探して、それ以上のタイムスタンプがないことを示します。見つけられた。これは私が過去にシナリオを扱った方法です。maxを含むサブクエリとは異なり、インデックスを使用するため、データベースで効率的です。ただし、私の開発チームは、データベースとの通信にエンティティを使用するよう強く求められているため、このソリューションは強く推奨されていません。

2)エンティティを使用してすべての値をメモリにロードし、コード内で手動でループして、探している値を見つけることができます。コードは次のようになります。

var openRequests = new List<Request>();
var allRequests = context.Requests;
foreach (var request in allRequests)
{
    var recentAction = request.RequestActions
        .OrderByDescending(c => c.ActionTimestamp)
        .First();
    if (recentAction.Status == "Open")
    {
        openRequests.Add(request);
    }
}

これは私が望む結果を提供しますが、それはひどく非効率的であり、リソースと実行時間の膨大な浪費です。私がクエリしているデータベースは非常に大きく、各レコードを反復処理することは実際には実行可能ではありません。

エンティティを使用してこれを行う効率的な方法はありますか?この種の機能を必要としたのは私だけだとは想像しがたいです。

4

2 に答える 2

2

オープンリクエストアクションの最新のタイムスタンプを識別するSQL側は、次のようになりませんか。

;WITH MostRecentActions AS 
(
  SELECT RequestID, ActionTimestamp,
    /* other relevant RequestAction columns, */
    rn = ROW_NUMBER() OVER (PARTITION BY RequestID ORDER BY ActionTimestamp DESC)
  FROM dbo.RequestActions
  WHERE Status = 'Open'
)
SELECT RequestID, ActionTimestamp /* , other columns */ 
  FROM MostRecentActions
  WHERE rn = 1;      
于 2012-06-15T21:24:20.557 に答える
1

単一のDBクエリでLINQtoEntitiesを使用してこれをクエリできます。

var openRequests = context.Requests
    .Where(r => r.RequestActions
        .OrderByDescending(ra => ra.ActionTimestamp)
        .Select(ra => ra.Status)
        .FirstOrDefault() == "Open")
    .ToList();

生成されたSQLは次のようになります。

SELECT 
[Extent1].[Id] AS [Id], 
[Extent1].[SomeProp1] AS [SomeProp1], 
[Extent1].[SomeProp2] AS [SomeProp2], -- ...etc.
FROM  [dbo].[Requests] AS [Extent1]
CROSS APPLY  (SELECT TOP (1) [Project1].[Status] AS [Status]
    FROM ( SELECT 
           [Extent2].[Status] AS [Status], 
           [Extent2].[ActionTimestamp] AS [ActionTimestamp]
           FROM [dbo].[RequestActions] AS [Extent2]
           WHERE [Extent1].[Id] = [Extent2].[RequestId]
    ) AS [Project1]
    ORDER BY [Project1].[ActionTimestamp] DESC ) AS [Limit1]
WHERE N'Open' = [Limit1].[Status]

これが「優れた」パフォーマンスの高いSQLであるかどうかはわかりません。

于 2012-06-16T00:28:05.467 に答える