51 messaggi dal 02 settembre 2002
Ciao
premetto che utilizzo EF da poco e sto affrontando questo problema:

Ho bisogno che una query sql mi restituisca un risultato che non sia un'entità, quindi:

"SELECT COUNT(ID) as Tot, YEAR(InsertDate) as Year FROM <table>
WHERE Removed = 0 AND Confirmed = 1
GROUP BY YEAR(InsertDate)
ORDER BY YEAR(InsertDate)"

Tramite il comando db.Database.SqlQuery<TEnt>(qry).. non riesco (o non sono riuscito ancora a trovare) il modo per fargli restituisce e leggere il risultato che in pratica sono n record formati da due interi, se non tramite la creazione una classe dedicata da passare al db.Database.SqlQuery<Classe>..

E' possibile che ogni volta che ho bisogno di recuperare dal db dei dati che non siano un entità o un tipo primitivo (string, int, etc..) debba creare una classe
ad-hoc??

Grazie in anticipo per le risposte
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao e buona domenica,


Ho bisogno che una query sql mi restituisca un risultato che non sia un'entità,

In questo momento ho il dubbio se ti serva effettivamente inviare una query SQL con il metodo SqlQuery. Per favore chiarisci se la tua <table> è mappata ad un DbSet in EF oppure se devi interrogare tabelle al di fuori del mapping.

Per il momento darò per scontato che devi interrogare un DbSet, e quindi ti propongo una soluzione che sfrutta query LINQ anziché query SQL.

Quando non devi restituire un'entità o un tipo primitivo da una query LINQ, allora puoi proiettere un tipo anonimo. E' un modo per restituire al volo nuovi tipi di oggetto, senza che ci sia il bisogno di creare una classe ad-hoc (il compilatore svolgerà questo compito per te). Ecco un esempio in cui vedi una query LINQ che proietta un tipo anonimo composto da due proprietà Year e Count definite "al volo".
https://dotnetfiddle.net/MKLz78

In realtà potresti anche evitare i tipi anonimi e ricorrere al tipo Tuple del .NET Framework.
https://dotnetfiddle.net/4YQmUJ
Con le Tuple hai il vantaggio di conoscere il nome del tipo restituito dalla query, e quindi è facile menzionarlo come tipo di ritorno dell'eventuale metodo che usi per estrarre i dati.
Lo svantaggio è che puoi accedere ai valori delle Tuple solo attraverso le loro proprietà Item1, Item2, ..., ItemN, che non sono nomi descrittivi dei dati che contengono. Questa cosa verrà risolta nella prossima versione di C#, con i nuovi tipi di Tuple.
https://msdn.microsoft.com/it-it/magazine/mt595758.aspx

ciao,
Moreno

Enjoy learning and just keep making
51 messaggi dal 02 settembre 2002
Ciao e grazie della risposta

ho provato ad implementare la soluzione del Tuple ma senza riuscirci.
Il mio metodo è:

public static IEnumerable<Tuple<int, int>> GetTotForYear()
        {
            IEnumerable<Tuple<int, int>> result; 

            using(var db = new DbContext101Sport())
            {
                //var sql = "SELECT COUNT(ID) as Tot, YEAR(InsertDate) as Year FROM Profiles " +
                //    "WHERE Removed = 0 AND Confirmed = 1 " +
                //    "GROUP BY YEAR(InsertDate) " +
                //    "ORDER BY YEAR(InsertDate)";

               result = db.Profiles
                    .Where(x => x.Removed == false && x.Confirmed == true)
                    .OrderBy(x => x.InsertDate.Value.Year)
                    .GroupBy(x => x.InsertDate.Value.Year)
                    .Select (x => new Tuple<int, int>(x.Count(), x.Key));

                //result = db.Database.SqlQuery<TotForYear>(sql).ToList();
            }

            return result;
        }


Ma quando il debug leggo result, è vuoto.
Inoltre nella view viene generata un'eccezzione in fase di lettura dei campi:
@foreach(var item in GetTotForYear()){
            <text>
             {
                 "year": @item.Item1,
                 "income": @item.Item2
             },
            </text>
        }


Dove non viene in pratica riconosciuto il .Item1 e/o .Item2

Sto sbagliando il modo di utilizzarlo??
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
serve un .ToList() qui per forzare l'esecuzione della query ed estrarre i risultati:

result = db.Profiles
.Where(x => x.Removed == false && x.Confirmed == true)
.OrderBy(x => x.InsertDate.Value.Year)
.GroupBy(x => x.InsertDate.Value.Year)
.Select (x => new Tuple<int, int>(x.Count(), x.Key))
.ToList();


Quando lavori con query LINQ, ricorda che non vengono eseguite subito. Entity Framework non invia la query al database se non all'ultimo momento, cioè quando manifesti la tua intenzione di voler leggere i risultati, e questo lo fai con il foreach, che però arriva troppo tardi, perché ormai hai distrutto il tuo DbContext101Sport.

Invocare il ToList() causa internamente un foreach e quindi anche l'invio della query al database. Siccome però lo invochi all'interno dello using, ovvero quando il DbContext101Sport è ancora presente, allora la query avrà successo e tu otterrai i tuoi risultati.

Leggi a proposito della deferred execution delle query LINQ, è un concetto molto importante da conoscere.
https://blogs.msdn.microsoft.com/charlie/2007/12/10/linq-and-deferred-execution/

ciao,
Moreno

Enjoy learning and just keep making

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.