5

データベースへの複数のトリップを回避するために、いくつかのSQLクエリをLinqに変換しようとしています。

私が変換しようとしている古いSQLは次のようになります。

SELECT
    AVG(CAST(DATEDIFF(ms, A.CreatedDate, B.CompletedDate) AS decimal(15,4))),
    AVG(CAST(DATEDIFF(ms, B.CreatedDate, B.CompletedDate) AS decimal(15,4)))
FROM
    dbo.A
INNER JOIN
    dbo.B ON B.ParentId = A.Id

そこで、2つのC#クラスを作成しました。

class B
{
    public Guid Id { get; set; }
    public DateTime CreatedDate { get; set; }
    public DateTime CompletedDate { get; set; }
}

class A
{
    public Guid Id { get; set; }
    public DateTime CreatedDate { get; set; }
    public List<B> BList { get; set; }
}

そしてList<A>、クエリしたいオブジェクトがあります。これはデータベースから入力されるため、リスト内の各Aには、Bの負荷を持つサブリストがあります。Linq-to-objectsを使用してこのリストをクエリしたいと思います。

したがって、Linqを使用して、Aの開始から子Bの完了までの平均時間、および各Bの開始から完了までの平均時間を取得する必要があります。私は元のSQLを作成しなかったので、それが想定どおりに機能するかどうかは完全にはわかりません。

計算するこれらの平均のいくつかを持っているので、1つの魔法のLinqクエリ内でそれらすべてを実行したいと思います。これは可能ですか?

4

3 に答える 3

5

より興味深い質問は、サーバーでそのようなことを行う方法です。たとえば、次のクエリを LINQ to SQL に変換するなどです。

        var q = from single in Enumerable.Range(1, 1)
                let xs = sourceSequence
                select new
                {
                    Aggregate1 = xs.Sum(),
                    Aggregate2 = xs.Average(),
                    // etc
                };

しかし、LINQ to Objects を使用している場合、1 つのクエリに詰め込もうとしても意味がありません。集計を個別に書くだけです:

var aggregate1 = xs.Sum();
var aggregate2 = xs.Average();
// etc

言い換えると:

var xs = from a in listOfAs
         from b in a.Bs
         select new { A=a, B=b };

var average1 = xs.Average(x => (x.B.Completed - x.A.Created).TotalSeconds);
var average2 = xs.Average(x => (x.B.Completed - x.B.Created).TotalSeconds);

私は正しく理解しましたか?

編集:David Bも同様に答えました。TimeSpan を Average メソッドでサポートされている単純な数値型に変換するのを忘れていました。TotalMilliseconds/Seconds/Minutes または適切なスケールを使用します。

于 2009-06-29T13:56:18.593 に答える
4

Sql と Linq は特定の点で異なります。Sql には暗黙的なグループ化があります。これらすべてを取得して 1 つのグループを作成します。linq では、グループ化する定数を導入することで、暗黙的なグループ化を偽造することができます。

var query = 
  from i in Enumerable.Repeat(0, 1)
  from a in AList
  from b in a.BList
  select new {i, a, b} into x
  group x by x.i into g
  select new
  {
    Avg1 = g.Average(x => (x.b.CompletedDate - x.a.CreatedDate)
       .TotalMilliseconds ),
    Avg2 = g.Average(x => (x.b.CompletedDate - x.b.CreatedDate)
       .TotalMilliseconds )
  };
于 2009-06-29T13:53:34.650 に答える
1

B の開始から終了までの平均時間を取得することから始めましょう。

1) まず、各 B オブジェクトの開始と終了の間の時間差が必要なので、次のようにします。

List<TimeSpan> timeSpans = new List<TimeSpan>();
foreach (B myB in BList)
{
  TimeSpan myTimeSpan = myB.CompletedDate.Subtract(myB.CreatedDate);
  timeSpans.Add(myTimeSpan);
}

2) 次に、これの平均を取得する必要があります。ラムダ式を使用してこれを行うことができます。

//This will give you the average time it took to complete a task in minutes
Double averageTimeOfB = timeSpans.average(timeSpan => timeSpan.TotalMinutes);

次のように、同じことを実行して、A の開始と B の終了の間の平均時間を取得できます。

1) A の開始日と B の完了日のそれぞれの時差を取得します。

 List<TimeSpan> timeSpans_2 = new List<TimeSpan>();
 foreach (B myB in BList)
 {
    TimeSpan myTimeSpan = myB.CompletedDate.Subtract(objectA.CreatedDate);
    timeSpans_2.Add(myTimeSpan);
 }

2) 上記とまったく同じように、これらの時間差の平均を取得します。

//This will give you the average time it took to complete a task in minutes
Double averageTimeOfAandB = timeSpans_2.average(timeSpan => timeSpan.TotalMinutes);

これで完了です。これが役立つことを願っています。このコードはテストされていないことに注意してください。

編集: LINQ はラムダ式を使用しますが、シンタックス シュガーのようなものであることを思い出してください (実装についてはよくわからないので、私に反対しないでください)。また、メソッドで提供する実装をラップして、A オブジェクトのリストに対して複数回呼び出すこともできます。

于 2009-06-29T12:38:39.733 に答える