333 messaggi dal 05 novembre 2012
Ciao Moreno,

Sì, perché la riga col ToList() era anche nel post di oggi.
Bisognerebbe andare a loggare le query inviate da Entity Framework perché ho l'impressione che il ToList() stia forzando EF a inviare varie query.

Mi hai fatto venire il dubbio ed ho provato a fare un progettino simile di test...confermo...è differente dal codice postato ieri e viene inviata una sola query

Il problema "There is already an open DataReader" si può "silenziare" abilitando MARS (cioè aggiungendo MultipleActiveResultSets=True alla connection string) ma secondo me è meglio andare a verificare quante query SQL partono, giusto per essere sicuri di quali siano le reali prestazioni di quella query LINQ.

Concordo pienamente...
Penso che il problema sia legato al lazy loading e sto aspettando info a riguardo da wmartin...eventualmente per risolvere pensavo di suggerirgli a priori Include della risorsa

Grazie
/Ciao

Alessio
333 messaggi dal 05 novembre 2012
Ciao,

ti ho chiesto del virtual per avere conferma del Lazy loading di entity framework...confermato il virtual è confermato che l'errore di questa mattina dipende dal lazy loading e dal fatto che veniva eseguita contemporaneamente più di una query al database (dubbio sollevato anche da Moreno)

Per risolvere il problema utilizziamo Eager Loading (metodo Include)...se vuoi approfondire le modalità di caricamento delle entità correlate in ef guarda Loading Related Entities (oppure cerca qui sul sito, ci sono diversi contenuti scritti da Stefano Mostarda)

Adesso...per risponderti in tempi brevi...puoi fare questo

public class BarcaplanningDTO
{
    // ... altre proprietà
    public string Imbarcostring => string.Join(",", Imbarco);
}

var query = await _db.ListEventiBarche
    .Where(r => r.Evento.Event_date.Month == mese || r.Evento.Event_end_date.Month == mese)
    .Include(x => x.Barca)
    .Include(x => x.Imbarco)
    .Include(x => x.Evento)
    .GroupBy(r => r.Barca.BarcaID)
    .Select(r => new BarcaplanningDTO
    {
        BarcaID = r.Key,
        Titolo = r.Select(x => x.Evento.Title).ToList(),
        Modello = r.Select(x => x.Barca.Modello).FirstOrDefault(),
        Nome = r.Select(x => x.Barca.Nome).FirstOrDefault(),
        Regione = r.Select(x => x.Barca.Regione).FirstOrDefault(),
        Letti = r.Select(x => x.Barca.Letti).FirstOrDefault(),
        Imbarco = r.Select(x => x.Imbarco.Nome).ToList(),
        Occupata = r.Select(x => 3).ToList(),
        Ordine = 3,
        Dateint = r.Select(x => new Intervallodate { EventoID = x.EventoID, Event_date = x.Evento.Event_date, Event_end_date = x.Evento.Event_end_date }).ToList()
    }).ToListAsync();


Ti riporto i consigli di questa mattina
A livello generale due consigli a livello di performance
- verificare sempre (e capire realmente) come una query linq si traduce nella richiesta/e (non sempre è vero il rapporto 1:1) al database e per fare questo puoi guardare qui
- in questo caso quando disponibile meglio utilizzare la variante asincrona, await _db.ListEventiBarche....ToListAsync()

sono ancora validi, ma per il primo punto utilizza il link che ti ha segnalato Moreno...il codice da scrivere e davvero poco ma la pagina che ti ha segnalato è più esaustiva

Verifica il numero di query che vengono eseguite sul database (per la prova che ho fatto prima presumo una)
Anche se viene inviata una sola query non è detto che sia una buona soluzione, verifica il piano di esecuzione...a volte è meglio scomporre l'esigenza ed inviare più query o cambiare completamente metodo ed al posto di gestire il tutto lato codice si può risolvere con una store procedure per es

/Ciao

Alessio
276 messaggi dal 03 ottobre 2006
Grazie
Mentre cerco di valutare come vengono create fisicamente le query ho provato a sostituire il codice con quello suggerito da Alessio ma mi ha subito bloccato dicendo che avrebbe dovuto convertire la definizione del metodo per accettare "await" e così me l'ha trasformato in questo modo:

public async System.Threading.Tasks.Task<await> IQueryableAsync<BarcaplanningDTO> GetBarchePlanningDTO(DropDownList ddl, int mese,string regio,int anno, string tipofiltro)

Però ora mi sottolinea in rosso await dicendo che non trova il nome o manca un riferimento all'assembly
333 messaggi dal 05 novembre 2012
Ciao,

public async Task<IEnumerable<BarcaplanningDTO>> GetBarchePlanningDTO(DropDownList ddl, int mese,string regio,int anno, string tipofiltro)


quando hai dei metodi che eseguono operazioni di I/O (es. read/write su disco o database, interrogare un ws) conviene utilizzare la variante asincrona

/Ciao
Modificato da scioCoder il 19 marzo 2019 11:30 -

Alessio
276 messaggi dal 03 ottobre 2006
mi pare molto interessante l'uso di async e vorrei proprio trovare il modo di usarlo in combinazione con la struttura che ho già in piedi... ora il problema si è spostato sulla paginazione perchè mi da il seguente errore

When the DataBoundControl has paging enabled, either the SelectMethod should return an IQueryable<ItemType> or should have all these mandatory parameters : int startRowIndex, int maximumRows, out int totalRowCount

Ricapitolando, nel code behind uso la seguente:

public Task<IQueryable<BarcaplanningDTO>> GetBarchePlanning()
{
BarcheActions ba = new BarcheActions();
return ba.GetBarchePlanningDTO(filtroexp,currdata.Month, curregione.ToString(), currdata.Year, "Contains");
}

e in BarcheActions ho
public async Task<IQueryable<BarcaplanningDTO>> GetBarchePlanningDTO(DropDownList ddl, int mese,string regio,int anno, string tipofiltro)
{
...
return query.AsQueryable();
}
333 messaggi dal 05 novembre 2012
Ciao,

aspetta...mi era sfuggito che stai lavorando con una applicazine asp.net webforms ed il posizionamento del codice con la query :(

Riporta il metodo allo stato precedente senza l'utilizzo di async/await ed elimina il tolist alla fine della query
public IQueryable<BarcaplanningDTO> GetBarchePlanningDTO(DropDownList ddl, int mese, string regio, int anno, string tipofiltro)
{
    // ....
    var query = _db.ListEventiBarche
        // ....
        .Select(r => new BarcaplanningDTO
        {
            // ...
        });
    return query;
}


Allo stato attuale...in pratica...stai eseguendo la query due volte, la prima è superflua e recupera tutti i record mentre a te ne serve solo un subset, quello dell'attuale pagina di visualizzazione della griglia

Nel momento che invochi il ToList l'applicazione esegue la query a db...alla griglia è giusto passare IQueryable ed è quest'ultima che deve far eseguire la query aggiungendo le informazioni di paginazione.

Per il discorso asincrono, per il problema che stiamo discutendo nel thread lascia stare...
Se sei interessato e vuoi approfondire puoi iniziare a guardare qui
https://www.winfxitalia.com/articoli/netfx45/programmazione-asincrona-async-await.aspx
https://www.aspitalia.com/script/1108/Sfruttare-Keyword-Async-Await-Pagine-ASP.NET-Web-Forms-4.5.aspx
https://docs.microsoft.com/it-it/aspnet/web-forms/overview/performance-and-caching/using-asynchronous-methods-in-aspnet-45

Se poi hai dubbi a riguardo è meglio aprire altre discussioni sul forum, più mirate sul singolo problema

UPDATE: ho notato un altro particolare curioso, al metodo GetBarchePlanningDTO passi un oggetto DropDownList...nel contesto del metodo, ti serve realmente tutta la dropdown?

/Ciao
Modificato da scioCoder il 19 marzo 2019 15:01 -

Alessio
276 messaggi dal 03 ottobre 2006
Detto che ho intenzione di approfondire il discorso dell'async dato che spero proprio esista la possibilità di usarlo anche con webforms, la query che ho scritto qui termina con ToList() perchè in realtà a quella fa seguito una query2 simile che pesca dati da un altra entità e crea un altro BarcaplanningDTO che poi unisco al primo tramite
query.AddRange(query2);

quindi se mi confermi devo lasciare anche il ToList() vero ?

Poi un ultima cosa... il suggerimento interessante qui sotto che mi hai dato, come si "trasforma" se devo usarlo al posto del mio classico
public string Imbarcostring { get; set;}

mi pare di leggere che il tuo valga solo come "get" infatto mi da errore di valore nullo

public class BarcaplanningDTO
{
// ... altre proprietà
public string Imbarcostring => string.Join(",", Imbarco);
}
333 messaggi dal 05 novembre 2012
Detto che ho intenzione di approfondire il discorso dell'async dato che spero proprio esista la possibilità di usarlo anche con webforms

Assolutamente si...guarda i link che ti ho segnalato prima

la query che ho scritto qui termina con ToList() perchè in realtà a quella fa seguito una query2 simile che pesca dati da un altra entità e crea un altro BarcaplanningDTO che poi unisco al primo tramite
query.AddRange(query2);

Eh però stai facendo un minestrone :):):)
Anche se apparentemente tutto (in qualche modo) funziona non è il modo corretto di operare

Sulle due query non devi fare ToList e dai rispettivi metodi tornare un IQueryable, poi per unirle utilizzi i metodi Union (Fa la Distict) o Concat (Non Fa La Distinct) a seconda della tua esigenza...l'oggetto query che ottieni come risultato è ancora IQueryable ed è quello che devi passare alla gridview

Cmq...dalle domande che fai sembra che non hai ben chiaro il discorso query linq, dai un occhio a questa pagina perchè è fondamentale
https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/query-execution

quindi se mi confermi devo lasciare anche il ToList() vero ?

No...vedi sopra

Poi un ultima cosa... il suggerimento interessante qui sotto che mi hai dato, come si "trasforma" se devo usarlo al posto del mio classico
public string Imbarcostring { get; set;}

mi pare di leggere che il tuo valga solo come "get" infatto mi da errore di valore nullo

public class BarcaplanningDTO
{
// ... altre proprietà
public string Imbarcostring => string.Join(",", Imbarco);
}


Si è una proprietà in sola lettura, la sintassi è differente dal classico get { return ...; } perchè è stata dichiarata utilizzando la sintassi Expression-bodied introdotta con C# 7

Per l'errore dichiara il costruttore della classe ed inizializza la proprietà (lista) Imbarco...non è una cattiva idea se fai lo stesso anche per le altre liste

/Ciao
Modificato da scioCoder il 19 marzo 2019 18:00 -

Alessio

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.