Utilizzando Linq per ObjectDataSource: come trasformare il datetime usando ToShortTimeString?
-
19-08-2019 - |
Domanda
Sto accedendo a una business class usando un ObjectDataSource e sto provando a produrre un output sensato per l'utente. I valori di ritorno descrivono una classe (come in Classroom e insegnamento, non software). Vorrei mostrare l'orario della lezione in un intervallo come questo: " 9: 00-10: 00 " ;.
Questa è la query Linq che sto usando per estrarre i dati:
return classQuery.Select(p => new SelectClassData
{
ClassID = p.ClassID,
Title = p.Title,
StartDate = p.StartDate.ToShortDateString(),
EndDate = p.EndDate.ToShortDateString(),
TimeOfClass =
p.StartDate.ToShortTimeString() + " - " +
p.EndDate.ToShortTimeString()
}).ToList();
Come puoi vedere, codifico l'ora di inizio e di fine nelle date di inizio e di fine anche se queste potrebbero essere potenzialmente in date diverse.
Quando eseguo questo codice ottengo:
" Impossibile tradurre l'espressione 'p.EndDate.ToShortTimeString ()' in SQL e non può trattarla come un'espressione locale. "
So che sto proiettando i risultati ma, essendo nuovo a Linq, avevo supposto che la chiamata C # a ToShortTimeString fosse avvenuta dopo la proiezione. Qualcuno può aiutarmi a capire come ottenere la stringa che sto cercando?
Soluzione
Il motivo è che la query viene utilizzata in LINQ to SQL. LINQ to SQL considera le query come alberi delle espressioni. Ha dei mapping definiti per alcuni metodi (ad esempio, Contains
) ma poiché non li esegue realmente, non può funzionare con metodi arbitrari. Analizza la query e la invia al server SQL. L'equivalente della query verrà eseguito come un'istruzione SQL sul server di database e il risultato tornerà. Il problema è ToShortTimeString ()
non ha una traduzione SQL equivalente in LINQ to SQL. Il trucco usato qui è quello di recuperare i dati dal server SQL e chiamare il metodo sul lato client ( AsEnumerable
farà questo).
return classQuery.Select(p => new { p.ClassID, p.Title, p.StartDate, p.EndDate })
.AsEnumerable()
.Select(p => new SelectClassData {
ClassID = p.ClassID,
Title = p.Title,
StartDate = p.StartDate.ToShortDateString(),
EndDate = p.EndDate.ToShortDateString(),
TimeOfClass = p.StartDate.ToShortTimeString() + " - " + p.EndDate.ToShortTimeString() })
.ToList();
Altri suggerimenti
Mi piace molto la risposta di Mehrdad. Non solo risolve il problema, mi insegna anche qualcosa su Linq. Grazie!
Tuttavia, ho continuato a risolvere il problema e ho escogitato un approccio diverso che descriverò qui nel caso in cui qualcun altro inciampare su questa domanda voglia prendere in considerazione. Il mio codice Linq to SQL ora recita:
return classQuery.Select(p => new SelectClassData
{
ClassID = p.ClassID,
Title = p.Title,
sDate = p.StartDate,
eDate = p.EndDate
}).ToList();
Nota che sDate ed eDate sono ora oggetti DateTime invece che stringhe. In " SelectClassData " oggetto, ho semplicemente cambiato la dichiarazione in modo che l'accesso alle variabili StartDate, EndDate e TimeOfClass passi attraverso un getter di proprietà:
public class SelectClassData
{
public int ClassID { get; set; }
public string Title { get; set; }
public DateTime sDate { get; set; }
public DateTime eDate { get; set; }
public string StartDate { get { return GetSDate(); } }
public string EndDate { get { return GetEDate(); } }
public string TimeOfClass { get { return GetTimeOfClass(); } }
protected string GetSDate()
{
return sDate.ToShortDateString();
}
protected string GetEDate()
{
return eDate.ToShortDateString();
}
protected string GetTimeOfClass()
{
return sDate.ToShortTimeString() + " - " + eDate.ToShortTimeString();
}
}
Cioè, ho impostato sDate ed eDate tramite LinqToSql ma eseguo " ToShortTimeString " e " ToShortDateString " trasformazioni dopo il recupero di Linq implementandolo nella classe di dati di destinazione.