277 messaggi dal 03 ottobre 2006
sto provando la seguente istruzione
var test = _db.ListEventiBarche
.Where(r => r.Evento.Event_date.Month == mese || r.Evento.Event_end_date.Month == mese)
.GroupBy(r => r.Barca.BarcaID)
.Select(r => new BarcaplanningDTO
{
BarcaID = r.Key,
Imbarco = r.Select(x => x.Imbarco.Nome).ToList(),
Imbarcostring = (r.Select(x => x.Imbarco.Nome).ToList()).Aggregate("",(current,next) => current +","+ next),
}).ToList();

dove la classe BarcaplanningDTO è
public class BarcaplanningDTO
{
public int BarcaID { get; set; }
public List<string> Imbarco { get; set; }
public string Imbarcostring { get; set; }
}

ma l'istruzione aggregate mi da il seguente errore:
LINQ to Entities does not recognize the method 'System.String Aggregate[String,String](System.Collections.Generic.IEnumerable`1[System.String], System.String, System.Func`3[System.String,System.String,System.String])' method, and this method cannot be translated into a store expression

Però se tolgo l'istruzione con aggregate e poi eseguo
foreach(BarcaplanningDTO c in test)
{
c.Imbarco.Aggregate("",(current,next) => current + next);
}

funziona perfettamente... non riesco ad evitare un secondo ciclo ?
Vorrei in pratica appiattire una lista di stringhe necessaria per colpa di un group in una stringa unica
333 messaggi dal 05 novembre 2012
Ciao,

Però se tolgo l'istruzione con aggregate e poi eseguo
foreach(BarcaplanningDTO c in test)
{
c.Imbarco.Aggregate("",(current,next) => current + next);
}


è normale che questa funzioni e la prima no...stai facendo due cose differenti

Nella prima soluzione hai un IQueryable che si traduce in sql. Aggregate è un metodo sconosciuto in sql ed è per questo che viene generata l'eccezione.

Una possibile soluzione (non l'unica, va valutato il contesto) è di chiamare prima AsEnumerable, questo farà in modo che la tua query sql venga eseguita ed il resto delle operazioni (compreso aggregate) verranno eseguite in memoria e non su sql.

var test = _db.ListEventiBarche
.Where(r => r.Evento.Event_date.Month == mese || r.Evento.Event_end_date.Month == mese)
.GroupBy(r => r.Barca.BarcaID)
.AsEnumerable()
.Select(r => new BarcaplanningDTO
{
BarcaID = r.Key,
Imbarco = r.Select(x => x.Imbarco.Nome).ToList(),
Imbarcostring = (r.Select(x => x.Imbarco.Nome).ToList()).Aggregate("",(current,next) => current +","+ next),
}).ToList();


/Ciao

Alessio
277 messaggi dal 03 ottobre 2006
Grazie mille della dritta
però ora mi da l'errore

There is already an open DataReader associated with this Command which must be closed first.
333 messaggi dal 05 novembre 2012
Ciao,

un paio di domande :)

nella classe del dominio (per intenderci, la classe utilizzata per ListEventiBarche) la proprietà Imbarco è dichiarata come virtual?

nella classe BarcaplanningDTO, ti servono sia Imbarco che Imbarcostring ?

Non è la causa dell'errore e quindi l'affrontiamo alla fine, al posto di aggregate meglio string.join

UPDATE:
E' probabile che l'errore sia generato a causa del lazy loading di ef.
Ci sono diverse soluzioni per la tua esigenza e per capire quale soluzione sia la migliore per il tuo contesto servirebbero altre info...allo stato attuale per es. potrebbe andare bene anche questo

public class BarcaplanningDTO
{
    public int BarcaID { get; set; }
    public List<string> Imbarco { get; set; }
    public string Imbarcostring => string.Join(",", Imbarco);
}

var test = _db.ListEventiBarche
    .Where(r => r.Evento.Event_date.Month == mese || r.Evento.Event_end_date.Month == mese)
    .GroupBy(r => r.Barca.BarcaID)
    .Select(r => new BarcaplanningDTO
    {
        BarcaID = r.Key,
        Imbarco = r.Select(x => x.Imbarco.Nome).ToList()
    }).ToList();

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()

/Ciao
Modificato da scioCoder il 18 marzo 2019 13:53 -

Alessio
11.886 messaggi dal 09 febbraio 2002
Contributi
Attenzione perché qui il ToList sta scatenando altre n query oltre alla prima, che potrebbe giustificare l'errore "There is already an open DataReader associated with this Command which must be closed first.".

Imbarco = r.Select(x => x.Imbarco.Nome).ToList()

Enjoy learning and just keep making
333 messaggi dal 05 novembre 2012
Ciao Moreno,

ok, il tuo ragionamento mi torna sul codice che ho postato ieri ma la stessa cosa vale anche sull'ultimo?

Grazie
/Ciao

Alessio
11.886 messaggi dal 09 febbraio 2002
Contributi
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.

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.

Per wmartin: qui trovi come loggare le query:
https://docs.microsoft.com/it-it/ef/ef6/fundamentals/logging-and-interception

ciao,
Moreno
Modificato da BrightSoul il 18 marzo 2019 20:58 -

Enjoy learning and just keep making
277 messaggi dal 03 ottobre 2006
Rispondo prima alle domande di Alessio:
nella classe del dominio (per intenderci, la classe utilizzata per ListEventiBarche) la proprietà Imbarco è dichiarata come virtual?
Si è dichiarata virtual come vedi:
public class EventoBarca
{
[Key, Column(Order = 0)]
public int EventoID { get; set; }
[Key, Column(Order = 1)]
public int BarcaID { get; set; }

public virtual Evento Evento { get; set; }
public virtual Barca Barca { get; set; }

public virtual Fornitore Skipper { get; set; }
public virtual ICollection<Tesserato> Tesserati { get; set; }
public virtual Imbarco Imbarco { get; set; }
}

nella classe BarcaplanningDTO, ti servono sia Imbarco che Imbarcostring ?
Mi servono entrambi perchè sto provando a fare la seguente cosa:
Una gridview con 31 colonne pari ai giorni del mese e le righe un elenco di barche.
Vorrei mostrare con delle caselle colorate i giorni in cui le barche sono impegnate e dato che una barca può essere impegnata in più intervalli di giorni nel mese scelto, raggruppo nella query BarcaID.
Poi tengo una proprietà List<string> Imbarco perchè ogni barca ha un imbarco e quindi se in una riga ci sono barche diverse devo collezionare gli imbarchi... mentre in string Imbarcostring mi tocca appiattire la lista in una singola stringa per poi poter filtrare la gridview per nome imbarco usando il "contains" (chissà quanti metodi migliori ci sono)
Ma per rispondere anche a Moreno, i ToList() sono anche di più di quelli che avevo riportato.
Ecco la query completa
query = _db.ListEventiBarche
.Where(r => r.Evento.Event_date.Month == mese || r.Evento.Event_end_date.Month == mese)
.GroupBy(r => r.Barca.BarcaID)
//.AsEnumerable()
.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(),
//Imbarcostring = (r.Select(x => x.Imbarco.Nome).ToList()).Aggregate("",(current,next) => current + next),
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()
}).ToList();


foreach (BarcaplanningDTO c in query)
{
c.Imbarcostring = c.Imbarco.Aggregate("", (current, next) => current + next);
}

Così come le vedete funziona tutto. Se tolgo i due commenti e naturalmente il foreach mi trovo l'errore che ho riportato

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.