2009-06-29 18 views
5

Tôi đang cố gắng chuyển đổi một số truy vấn SQL vào LINQ để tránh nhiều chuyến đi đến cơ sở dữ liệu.LINQ - tính nhiều điểm trung bình trong một truy vấn

SQL cũ Tôi đang cố gắng để chuyển đổi thực hiện:

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 

Vì vậy, tôi đã tạo ra hai lớp 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; } 
} 

Và tôi đã có một đối tượng List<A> mà tôi muốn truy vấn. Nó được điền từ cơ sở dữ liệu, do đó, mỗi A trong danh sách có một danh sách con với một tải của Bs. Tôi muốn sử dụng LINQ-to-objects để truy vấn danh sách này.

Vì vậy, tôi cần sử dụng LINQ để có được thời gian trung bình giữa điểm bắt đầu của A và hoàn thành các con của nó, và thời gian trung bình giữa mỗi lần bắt đầu và hoàn thành của mỗi B. Tôi đã không viết bản gốc SQL vì vậy tôi không hoàn toàn chắc chắn nó làm những gì nó nghĩa vụ phải!

Tôi có một số mức trung bình này để tính toán, vì vậy tôi muốn thực hiện tất cả chúng bên trong một truy vấn LINQ huyền diệu. Điều này có thể không?

Trả lời

5

Câu hỏi thú vị hơn sẽ là làm thế nào để làm một điều như vậy trên máy chủ, ví dụ để làm cho truy vấn sau đây dịch để LINQ to SQL.

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

Nhưng không có điểm cố gắng nhồi nhét nó vào một truy vấn nếu bạn đang sử dụng LINQ to Objects.Chỉ cần viết những uẩn riêng:

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

Nói cách khác:

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); 

đã tôi hiểu phải không?

Chỉnh sửa: David B đã trả lời tương tự. Tôi quên chuyển đổi TimeSpan thành kiểu số đơn giản được hỗ trợ bởi phương thức Trung bình. Sử dụng TotalMilliseconds/Seconds/Minutes hoặc bất kỳ tỷ lệ nào là thích hợp.

+0

Cảm ơn, công việc này hoàn hảo! Tôi đã đi với tùy chọn tổng hợp riêng biệt - điều này làm cho mọi thứ rõ ràng hơn một chút. –

1

Hãy bắt đầu bằng cách nhận được thời gian trung bình giữa bắt đầu và kết thúc của B:

1) Trước tiên, bạn cần sự khác biệt về thời gian giữa bắt đầu và kết thúc của từng đối tượng B, do đó bạn sẽ làm điều này:

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

2) Bây giờ bạn cần có mức trung bình của điều này. Bạn có thể làm điều này bằng cách sử dụng các biểu thức lambda:

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

Bạn bây giờ có thể làm điều tương tự để có được thời gian trung bình giữa đầu A và B dứt điểm như sau:

1) Lấy chênh lệch thời gian cho sự khởi đầu của một ngày và mỗi ngày hoàn thành 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) Lấy trung bình của các differnces thời gian chính xác như trên:

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

Và bạn đã hoàn tất. Tôi hy vọng rằng điều này sẽ giúp. Xin lưu ý rằng mã này chưa được kiểm tra.

EDIT: Hãy nhớ rằng LINQ sử dụng biểu thức Lamda nhưng có nhiều cú pháp đường (không biết nhiều về việc triển khai vì vậy tôi hy vọng bạn không giữ nó chống lại tôi). Và bạn cũng có thể bọc các cài đặt mà tôi cung cấp trong các phương thức để bạn có thể gọi chúng nhiều lần cho một Danh sách các đối tượng.

+0

Cảm ơn, điều này thực sự sẽ thực hiện công việc. Tuy nhiên như tôi đã có 9 trung bình/phút/max vv loại điều để tính toán từ dữ liệu này, tôi đã tự hỏi nếu nó có thể tất cả được thực hiện bên trong một truy vấn LINQ, tương tự như SQL gốc. –

+0

oops, vừa xem bản chỉnh sửa của bạn. Có vẻ như đây sẽ là cách dễ nhất. Tôi đã thấy các phương pháp trung bình trong LINQ và nghĩ rằng chúng có thể là con đường phía trước. Nhưng có lẽ không. –

+0

Xin lỗi vì đã nhầm lẫn một chút, bạn có nghĩa là đưa ra một đối tượng thuộc loại A bạn muốn tính toán không chỉ mức trung bình mà còn là min/max..etc? – Draco

4

Sql và Linq khác nhau ở một số điểm nhất định. Sql có nhóm tiềm ẩn - lấy tất cả các nhóm này và tạo một nhóm. Trong LINQ, người ta có thể giả mạo nhóm ngầm bằng cách giới thiệu một hằng số để nhóm vào.

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) 
    }; 
+0

Điều này cũng tuyệt vời và cuối cùng tôi có thể sử dụng triển khai này. Nếu tôi chỉ có thể có hai câu trả lời! –