2013-03-22 45 views
10

Tôi có Measurement Đối tượng có Thuộc tính liên quan CreationTime (Ngày giờ) và Reference (Chuỗi) và một số giá trị khác.Thực thể khung - Truy vấn LINQ theo thứ tự và nhóm theo

Tôi muốn viết một truy vấn LINQ đạt hiệu suất tới DbContext rằng

  • nhóm Measurement đối tượng của tôi bằng một trao Reference
  • lệnh của nhóm bằng cách hoặc là CreationTime tài sản của Measurement đầu tiên khỏi nhóm hoặc trung bình của các thuộc tính CreationTime
  • giới hạn truy vấn gần đây nhất numOfEntries

(Trong bước sau để tính toán giá trị so với các nhóm này quay trở lại trung bình, nhưng tôi đoán đó là không thích hợp cho vấn đề của tôi.)

Các DbContext chính nó có một DbSet<Measurement> gọi Measurements giữ tất cả Measurement đối tượng.

Tôi đã đưa ra truy vấn sau, kết quả trong Danh sách các nhóm được sắp xếp chính xác nhưng thiếu một số nhóm ở giữa.

var groupByReference = (from m in context.Measurements 
          orderby m.CreationTime 
          group m by new { m.Reference } into g 
          select g).Take(numOfEntries).ToList(); 

Làm cách nào để chọn các nhóm "gần đây nhất" là Measurement?

Tôi đang sử dụng Khung thực thể 4.4 với Cơ sở dữ liệu MySQL (MySql Connector/Net 6.6.4). Ví dụ này được đơn giản hóa, tôi có thể đi vào chi tiết hơn và/hoặc đưa ra một ví dụ nếu cần thiết.

Cảm ơn!

+1

Thay vì tính "trung bình của CreationTime ", bạn đã xem xét tính toán khoảng thời gian từ một điểm nhất định và sau đó xác định mức trung bình của những khoảng thời gian đó sau đó tính toán ngày kết quả dựa trên điểm đã cho và thời gian trung bình? –

Trả lời

0

Cố gắng di chuyển order by sau group by:

var groupByReference = (from m in context.Measurements 
         group m by new { m.Reference } into g 
         order by g.Avg(i => i.CreationTime) 
         select g).Take(numOfEntries).ToList(); 
+0

Tôi đã thử rằng, nhưng có một lỗi 'DateTime'cannot được chuyển đổi thành' int'. Tôi cũng đã thử với một thuộc tính 'int' cho mục đích thử nghiệm và có một MySqlException nói một cái gì đó như" cột không xác định "GroupBy1.K2 'trong' danh sách trường '" – zufallsfund

9

Đó là phương pháp cú pháp (mà tôi tìm thấy dễ dàng hơn để đọc) nhưng điều này có thể làm điều đó

bài Cập nhật bình luận

Sử dụng .FirstOrDefault() thay của .First()

Liên quan đến các ngày trung bình, bạn có thể phải bỏ lệnh đó vào lúc này vì tôi không thể nhận được một IDE vào lúc này

var groupByReference = context.Measurements 
           .GroupBy(m => m.Reference) 
           .Select(g => new {Creation = g.FirstOrDefault().CreationTime, 
//            Avg = g.Average(m => m.CreationTime.Ticks), 
               Items = g }) 
           .OrderBy(x => x.Creation) 
//       .ThenBy(x => x.Avg) 
           .Take(numOfEntries) 
           .ToList(); 
+1

Cảm ơn bạn đã gợi ý, nhưng tôi nhận được một 'NotSupportedException' cố gắng xác định g.First() vì 'g' không phải là thao tác truy vấn cuối cùng. Cố gắng trung bình trên thuộc tính 'CreationTime' không thành công vì nó không phải là' int'. – zufallsfund

+0

Tôi đã cập nhật câu trả lời của mình nhưng tôi sẽ không thể khắc phục vấn đề ngày trung bình cho đến khi tôi nhận được một IDE – NinjaNye

+0

Cảm ơn vì nỗ lực của bạn. Tôi đã thử điều này trong thời gian chờ đợi và cũng đã thêm một thuộc tính 'Ticks' lưu trữ CreationTime như một thời gian dài để '.Average()' hoạt động. Bây giờ tôi nhận được ngoại lệ MySQL nói rằng "cột không xác định" Distinct1.Reference 'trong' where khoản '"(FirstOrDefault) hoặc" Unknown cột' GroupBy1.K2 'trong' danh sách trường '"(Trung bình). Là một kết nối MySql Bug nguyên nhân có thể cho điều này? (Tôi nên đề cập rằng truy vấn thực sự phức tạp hơn một chút, tôi không truy vấn trực tiếp DbSet nhưng sử dụng truy vấn khác dưới dạng nguồn.) – zufallsfund

0

Yêu cầu của bạn là tất cả, nhưng đây là giải pháp sự hiểu biết của tôi về họ:

để nhóm bằng hữu tham khảo:

var refGroupQuery = (from m in context.Measurements 
      group m by m.Reference into refGroup 
      select refGroup); 

Bây giờ bạn nói rằng bạn muốn giới hạn kết quả bởi "nhất numOfEntries gần đây" - tôi thực hiện việc này để có nghĩa là bạn muốn giới hạn đo trở ...trong trường hợp đó:

var limitedQuery = from g in refGroupQuery 
        select new 
        { 
         Reference = g.Key, 
         RecentMeasurements = g.OrderByDescending(p => p.CreationTime).Take(numOfEntries) 
        } 

Để đặt hàng nhóm theo thời gian tạo Đo lường đầu tiên (lưu ý bạn nên đặt các phép đo, nếu bạn muốn giá trị CreationTime sớm, substitue "g.SomeProperty" với "g.CreationTime"):

var refGroupsOrderedByFirstCreationTimeQuery = limitedQuery.OrderBy(lq => lq.RecentMeasurements.OrderBy(g => g.SomeProperty).First().CreationTime); 

để đặt hàng nhóm theo CreationTime trung bình, sử dụng tài sản Bọ ve của struct DateTime:

var refGroupsOrderedByAvgCreationTimeQuery = limitedQuery.OrderBy(lq => lq.RecentMeasurements.Average(g => g.CreationTime.Ticks)); 
1

Bạn có thể cố gắng đúc kết quả của groupby và Take thành một n Enumerable đầu tiên sau đó xử lý phần còn lại (xây dựng trên giải pháp được cung cấp bởi NinjaNye

var groupByReference = (from m in context.Measurements 
           .GroupBy(m => m.Reference) 
           .Take(numOfEntries).AsEnumerable() 
           .Select(g => new {Creation = g.FirstOrDefault().CreationTime, 
              Avg = g.Average(m => m.CreationTime.Ticks), 
               Items = g }) 
           .OrderBy(x => x.Creation) 
           .ThenBy(x => x.Avg) 
           .ToList() select m); 

truy vấn sql của bạn sẽ trông tương tự (tùy thuộc vào đầu vào của bạn) này

SELECT TOP (3) [t1].[Reference] AS [Key] 
FROM (
    SELECT [t0].[Reference] 
    FROM [Measurements] AS [t0] 
    GROUP BY [t0].[Reference] 
    ) AS [t1] 
GO 

-- Region Parameters 
DECLARE @x1 NVarChar(1000) = 'Ref1' 
-- EndRegion 
SELECT [t0].[CreationTime], [t0].[Id], [t0].[Reference] 
FROM [Measurements] AS [t0] 
WHERE @x1 = [t0].[Reference] 
GO 

-- Region Parameters 
DECLARE @x1 NVarChar(1000) = 'Ref2' 
-- EndRegion 
SELECT [t0].[CreationTime], [t0].[Id], [t0].[Reference] 
FROM [Measurements] AS [t0] 
WHERE @x1 = [t0].[Reference] 
Các vấn đề liên quan