2012-11-24 21 views
8

Używam .NET i Entity Framework. Chcę pogrupować tabelę według daty bez części czasu.Zespół obiektów grupy według daty i powrotu nowej klasy

Mam klasę:

public sealed class QueryItem { 
    public int Year { get; set; } 
    public int Month { get; set; } 
    public int Day { get; set; } 
} 

i metoda (używam BLToolkit, jeśli chcesz wiedzieć, co jest DbManager):

protected override IQueryable<QueryItem> InitiateQuery() { 
    return 
     from query in DbManager.GetTable<SomeTableModel>() 
     group query by new { Year = query.CreationDate.Year, Month = query.CreationDate.Month, Day = query.CreationDate.Day } 
     into list1 
     select new QueryItem {Year = list1.Key.Year, Month = list1.Key.Month, Day = list1.Key.Day}; 
} 

w tej metodzie LINQ w języku tego zapytania SQL:

SELECT 
    [query].[CreationDate] 
FROM 
    [SomeDatabase.SomeTable] [query] 
GROUP BY 
    DatePart(Year, [query].[CreationDate]), 
    DatePart(Month, [query].[CreationDate]), 
    DatePart(Day, [query].[CreationDate]), 
    [query].[CreationDate] 

I to jest złe zapytania, ponieważ nie tylko przez grupę randkę.

Ale jeśli mogę użyć tego kodu (nie jest użyteczny, muszę wrócić do obiektu klasy):

var result = 
    from query in DbManager.GetTable<SomeTableModel>() 
    group query by new { Year = query.CreationDate.Year, Month = query.CreationDate.Month, Day = query.CreationDate.Day } 
    into list1 
    select list1; 

To będą tłumaczone na to:

SELECT 
    [t1].[c1] as [c11], 
    [t1].[c2] as [c21], 
    [t1].[c3] as [c31] 
FROM 
    (
     SELECT 
      DatePart(Year, [selectParam].[CreationDate]) as [c1], 
      DatePart(Month, [selectParam].[CreationDate]) as [c2], 
      DatePart(Day, [selectParam].[CreationDate]) as [c3] 
     FROM 
      [SomeDatabase.SomeTable] [selectParam] 
    ) [t1] 
GROUP BY 
    [t1].[c1], 
    [t1].[c2], 
    [t1].[c3] 

I to jest w porządku pytanie.

Przypuszczam, że Entity Framework próbuje zoptymalizować moje zapytanie, czy coś takiego i dlatego mam złą zapytania.

Mam rację? Czy robię to we właściwy sposób? Co powinienem zrobić (może użyć bezpośredniego zapytania SQL lub czegoś innego)?

Odpowiedz

8

Jest o wiele prostsze w użyciu EntityFunctions * tutaj:

var result = 
    from query in DbManager.GetTable<SomeTableModel>() 
    group query by EntityFunctions.TruncateTime(query.CreationDate) 
    into list1 
    select list1; 

* DbFunctions jak z Entity Framework 6.

+0

Przypuszczam, że powinien działać. Ale nie udało się z BLToolkit. Komunikat wyjątek: _'TruncateTime (konwersja (selectParam.CreationDate))”nie może być przekształcony w SQL._ A z StackTrace: _ w BLToolkit.Data.Linq.Builder.ExpressionBuilder.ConvertToSql (IBuildContext kontekście, wyrażenie Ekspresja , Boolean unwrap) _ Powinienem pomyśleć, jak zrealizować interfejs użytkownika filtra w inny sposób. – colotiline

+0

W EF przekłada się na 'convert (datetime, convert (varchar (255), [DateField], 102), 102))'. Czy możesz użyć tego do stworzenia jakiejś funkcji w BLT? Nie jest dla mnie jasne, jak współpracują BLT i EF. Dokumentacja BLT jest naprawdę uboga, niestety. –

+0

Próbowałem zaimplementować mojego własnego porównywalnika. To też się nie udało.Zawsze staram się zoptymalizować zapytanie i nie udało się. Ale użyłem innego interfejsu użytkownika i sposobu filtrowania danych, a teraz wszystko działa. – colotiline

2

aktualizacji odpowiedź:EntityFunctions ale przestarzałe.

Ostrzeżenie 1 'System.Data.Entity.Core.Objects.EntityFunctions' jest przestarzały: "Ta klasa została zastąpiona przez System.Data.Entity.DbFunctions. C: \ Users \ liufa \ Documents \ Visual Studio 2013 \ Projects \ MatasMrLenderTest \ Mvc5MobileApplication1 \ Sterowniki \ CreditScoreController.cs 32 103 Mvc5MobileApplication1

Teraz DbFunctions.

using System.Data.Entity; 

var result = DbManager.GetTable<SomeTableModel>() 
.GroupBy(o => DbFunctions.TruncateTime(o.CreationDate)) 
Powiązane problemy