LINQの - つのクエリで複数の平均値を計算します
-
21-08-2019 - |
質問
私は、データベースへの複数のトリップを回避するためのLINQにいくつかのSQLクエリを変換しようとしています。
私が変換しようとしている古い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は、BSの負荷にサブリストを持っています。私はこのリストを照会するLINQのツーオブジェクトを使用します。
だから私はAの開始とその子Bsの完了、及び各Bの開始と完了の間の平均時間との間の平均時間を取得するためのLINQを使用する必要があります。私はそれはそれは!になっているものませ全くわからないので、私は、元のSQLを記述しませんでした。
私が計算するためにこれらの平均のいくつか持っているので、私は1つの魔法のLINQクエリ内でそれらすべてを行うにしたいと思います。これは可能でしょうか?
解決
より興味深い質問は次のクエリは、SQLにLINQに変換するために、たとえば、サーバー上でそのようなことを行うにはどのようになります。
var q = from single in Enumerable.Range(1, 1)
let xs = sourceSequence
select new
{
Aggregate1 = xs.Sum(),
Aggregate2 = xs.Average(),
// etc
};
しかし、あなたがオブジェクトにLINQを使用している場合は、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);
私は、右理解していましたか?
編集:デヴィッド・Bも同様に答えました。私は普通の方法でサポートされている、単純な数値型にするTimeSpanを変換するのを忘れていました。 TotalMilliseconds /秒/分を使用するか、どんな規模が適切である。
他のヒント
SQLとLINQの特定の点で異なります。 SQLが持っているの暗黙のグループ化の - これらの全てを取得し、一つのグループを作ります。 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 )
};
は、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)正確に上記のようなこれらの時間differncesの平均値を取得します
//This will give you the average time it took to complete a task in minutes
Double averageTimeOfAandB = timeSpans_2.average(timeSpan => timeSpan.TotalMinutes);
そして、あなたは完了です。私はこのことができますことを願っています。このコードはテストされていないことに注意してください。
EDIT:LINQは、ラムダ式を使用していますが、シンタックスシュガーのよりであることを覚えておいてください(私はあなたが私に対してそれを保持しないことを望むような実装についてはあまり知りません)。あなたは、オブジェクトのリストのためにそれらを複数回呼び出すことができるようにし、また、あなたが、私は方法で提供implementaionsを包むことができます。