11.886 messaggi dal 09 febbraio 2002
Contributi
vailfox ha scritto:

Per il momento tutto funziona e le prestazioni con il Profiler di VS2010 mi da un tempo di 0.117/s nell'impiego della query (prima erano 0.350/s).


Benone, ottimo lavoro :)
A proposito del LazyLoading, hai provato a disabilitarlo e a riabiltarlo subito dopo aver letto gli elementi della customerList? Così potresti riutilizzare lo stesso contesto che hai già nella pagina, ma magari hai già scartato questa soluzione per qualche motivo di cui non sto tenendo conto (?)

ciao, buona serata

Enjoy learning and just keep making
170 messaggi dal 17 febbraio 2009
Ciao Bright, si ho riprovato ad abilitare il lazy ed ho avuto lo stesso problema. Nella prima esecuzione della pagina aspx ottengo dei risultati sbagliati .... ovvero conteggi dei customers diversi.

Mi sono documentato e ho visto che il problema potrebbe essere dato dalla funzionalità MARS (multipleactiveresultsets=True; nella stringa di connessione di EntityFramework).
Proprio in questo momento ho deciso di creare un'applicazione context prendendo spunto da quello di MVCasting dai ragazzi di aspitalia:
http://www.aspitalia.com/script/1037/Gestire-Ciclo-Vita-Object-Context-Entity-Framework-Applicazione-ASP.NET.aspx
questo per evitare di allocare vari context sparsi nell'applicazione.

Sono arrivato a scrivere questa classe:

http://pastebin.com/3Vg2WvA1

e ad accedere al context scrivendo:

 Dim query = From c In ApplicationContext.Current.Context.CustomerTable ... 


Sto provando a fare altri test per vedere se il LazyLoading mi da ancora problemi....
ma inizio ad avere molta confusione.
In oltre spero che l'ApplicationContext da me creato sia corrette... non ho instanziato il ModelContainer in un HttpModule come nell'esempio, ma lo fanno nella classe.
Pensi sia corretto??
170 messaggi dal 17 febbraio 2009
Dopo 3 giorni di sbattimento, ho trovato l'origine dei guai.
Dopo ave aggiunto un ApplicationContext e un WebContextModule per assicurare un Context per Request nella mia applicazione ho notato che il problema principale (quello dei dati sfalsati) si verificava sempre se pubblicavo l'applicazione in locale e la eseguivo con IIS 7. In pratica, dopo il prelievo di una lista di device, vedevo che l'applicazione SOLO nel primo record del datagrid non caricava l'ultimo eventLog del device.. ma ne prendeva uno specifico (non ho capito per quale motivo) che comunque non era l'ultimo.
in pratica avevo
________________
Device | EventLog a caso
Device | ultimo EventLog
Device | ultimo EventLog
...

sostituendo nella property Current della Entity Device (inserita tramite le partial class)
Dim cs as EventLog = Me.EventLog.LastOrDefault()

con
Dim cs As EventLog = Me.EventLog.OrderByDescending(Function(d) d.ID).FirstOrDefault

Il tutto ha funzionato ottenendo i dati previsti.

DOMANDA: Come mai questo comportamento solo con IIS7 (deploy locale) e non sul Web Service Integrato di VS2010 (sempre in locale con lo stesso DB SqlServer Express)????
Credo che, dato che Linq2Entities non supporta il .LastOrDefault(), questo creava problemi in fase di Load delle entity correlate nel Context (EF 4.3 per l'appunto)....

A me sembra una situazione strana.... e a voi??

@BrightSoul,
risolvendo il problema sopra citato posso riattivare il lazy loading senza complicazioni, ma effettuando il profiler dell'applicazione, eseguendo la tua query su un context separato e lazy loading disabilitato ottengo solo 5 query per request della stessa pagina e un tempo di molto inferiore rispetto alla query semplice con lazy abilitato (che genera più di 360query).
Modificato da vailfox il 19 aprile 2012 18.46 -
11.886 messaggi dal 09 febbraio 2002
Contributi
Ciao,
purtroppo non ti so aiutare più di tanto perché non ho il quadro completo della situazione. Mi sembra però di notare che c'è una differenza importante tra il codice VB.NET che hai pubblicato qui e il codice C# contenuto nell'articolo di Daniele. Potrebbe essere quella la causa dei problemi...

Nel codice del tuo ApplicationContext leggo questo frammento:
Private _ctx As ModelContainer
Public ReadOnly Property Context() As ModelContainer
        Get
            If _ctx Is Nothing Then
                _ctx = New ModelContainer
            End If
            Return _ctx
        End Get
End Property

Ammesso che io l'abbia interpretato bene, ApplicationContext è una singleton e l'istanza del contesto va a finire nel campo _ctx della classe stessa. Questo questo significa che anche il contesto sarà un Singleton.

Nel codice di Daniele il contesto viene memorizzato nella collezione Items dell'HttpContext corrente ed è da lì che verrà estratto.
public NorthwindEntities Context
  {
    get
    {
      if (HttpContext.Current.Items[ConfigurationKeys.ConnectionString] == null)
        throw new InvalidOperationException(
          "You must register the HttpModule to use per-Request impelementation.");

        return ((NorthinwEntities)HttpContext.Current.Items[
          ConfigurationKeys.ConnectionString]);
    }
  }


La differenza è che, ad ogni nuova richiesta web, nel tuo caso il contesto usato sarà sempre lo stesso. Nel caso di Daniele, invece, ne verrà sempre creato uno nuovo, come è opportuno che sia.

Prova a modificare il tuo ApplicationContext in modo che sia più simile a quello mostrato nell'articolo.

Poi, per prova, leggi il valore di _ctx.GetHashCode() ad ogni richiesta e stampalo nella pagina. Se ottieni un valore sempre diverso significa che viene correttamente ricreata una nuova istanza.

ciao,

Enjoy learning and just keep making
170 messaggi dal 17 febbraio 2009
@BrightSoul
E' esattamente come da te detto!
Infatti con la "mia" versione dell'application context (mai scritta prima d'ora :) ) quando effettuavo il load test avevo un sacco di errori relativi alla connessione con il db.

Ho creato un application context con un webContextModule (HttpModule) così come spiegato nell'articolo e tutto ha funzionato correttamente ;)

Io pensavo che l'implementazione di un Singleton (dell'application context nel nostro caso) fosse una sola istanza di Application Context Per-Request.
Ma evidentemente non era così... in questo modo se si connettono 200 utenti in contemporanea, ci sarà una sola istanza di Application Context in tutto il dominio dell'applicazione in esecuzione giusto? (fermo restando la creazione di un nuovo context per request nell'HttpModule).

Devo ancora acquistare il libro della GoF sui pattern  .

Il problema dei dati sfalsati relativo al Me.EventLog.LastOrDefault si presenta anche con l'applicazione del pattern sopra citato.... ma vabbè... ho risolto con Me.EventLog.OrderByDescending(....).FirstOrDefault
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

vailfox ha scritto:

se si connettono 200 utenti in contemporanea, ci sarà una sola istanza di Application Context in tutto il dominio dell'applicazione in esecuzione giusto?

esatto, e l'istanza durerà finché il worker process non viene riciclato da IIS, cosa che potrebbe avvenire ad intervalli regolari o dopo un periodo di inattività.

vailfox ha scritto:

Il problema dei dati sfalsati relativo al Me.EventLog.LastOrDefault

Se usi un extension method LINQ non supportato, come LastOrDefault, dovresti ottenere un'eccezione.
Stai eseguendo la query dentro un try...catch o forse hai scritto del codice che cattura le eccezioni non gestite? Questi potrebbero essere dei motivi che nascondono il problema.
Comunque sì, usare OrderByDescending(...).FirstOrDefault() risolve il problema.

vailfox ha scritto:

Devo ancora acquistare il libro della GoF sui pattern

Sì, dovrebbe essere una buona lettura, spesso vedo che viene citato qua e là. Non l'ho ancora comprato perché ho paura che manchi di esempi pratici ma se lo leggi poi dimmi com'è ;) Al momento sono più attirato da quello di Esposito e Saltarello.

ciao

Enjoy learning and just keep making
170 messaggi dal 17 febbraio 2009
BrightSoul ha scritto:

esatto, e l'istanza durerà finché il worker process non viene riciclato da IIS, cosa che potrebbe avvenire ad intervalli regolari o dopo un periodo di inattività.


Ora è più chiaro, Grazie ;)



Stai eseguendo la query dentro un try...catch o forse hai scritto del codice che cattura le eccezioni non gestite? Questi potrebbero essere dei motivi che nascondono il problema.
Comunque sì, usare OrderByDescending(...).FirstOrDefault() risolve il problema.


No, non utilizzo nessun Try ... Catch, con FirstOrDefault l'applicazione viene compilata ed eseguita, il problema è che nel primo record del datagrid della lista dei device con rispettiva colonna "ultimo EventLog" ho
| Device | EventLog a caso
| Device | ultimo EventLog
e questo solo su IIS 7. Sul Web Server integrato di VS2010 non ho il problema.

Ad ogni modo mi sarebbe piaciuto capire perché utilizzando LastOrDefault ottengo questo strano comportamento.... la cosa mi ha fatto "impazzire" per ben 2 giorni  .
Anche se il problema è ormai risolto, giusto per curiosità posto il mio Object Model e la classe parziale Device.... magari vi viene in mente qualcosa....

Object Model -> http://cl.ly/1P2j0H03182Q2Q0v3d39
Partial Device -> http://pastebin.com/Cb3AqmT1
Problema sito in CurrentStatus nella prima riga, dove "cs" sta per "current status".

Ripeto, il problema è già risolto. Eventuali pareri sarebbero solo a scopo "didattico", giusto per capire l'origine del problema


Sì, dovrebbe essere una buona lettura, spesso vedo che viene citato qua e là. Non l'ho ancora comprato perché ho paura che manchi di esempi pratici ma se lo leggi poi dimmi com'è ;)
Al momento sono più attirato da quello di Esposito e Saltarello.


Certamente, il problema è che troverò il tempo di affrontare una lettura del genere solo dopo alcuni "impegni universitari"
Modificato da vailfox il 23 aprile 2012 10.24 -
Modificato da vailfox il 23 aprile 2012 10.25 -
11.886 messaggi dal 09 febbraio 2002
Contributi
ciao,

vailfox ha scritto:

e questo solo su IIS 7. Sul Web Server integrato di VS2010 non ho il problema.

Non so... a me sembra molto strano. Sia IIS che l'Asp.Net development server usano entrambi lo stesso runtime di Asp.Net. La query SQL che viene generata dal provider LINQ è la medesima.
Ad ogni modo, prova a leggere questo articolo che illustra le differenze tra i due webserver, magari ti salta all'occhio qualcosa.
http://www.asp.net/web-forms/tutorials/deployment/core-differences-between-iis-and-the-asp-net-development-server-cs

vailfox ha scritto:

Ad ogni modo mi sarebbe piaciuto capire perché utilizzando LastOrDefault ottengo questo strano comportamento...

Ok, ci provo. Penso di aver capito qualcosa in più quando ho letto questa riga:
Dim cs As EventLog = Me.EventLog.OrderByDescending(Function(d) d.ID).FirstOrDefault

Se poggi il mouse sulla proprietà di navigazione EventLog, noterai che è una collezione di tipo EntityCollection<EventLog>.
Questo tipo di collezione NON implementa IQueryable quindi ogni extension method come LastOrDefault che tu possa usare su di essa non andrà a far parte dell'espressione LINQ. Non dovendo essere "tradotto" in SQL, non ottieni un'eccezione.

Quindi il LastOrDefault andrà in esecuzione solo dopo che il provider avrà effettuato una query per ottenere TUTTI gli EventLog, e solo dopo che le entità si saranno materializzate nel contesto.

vailfox ha scritto:

| Device | EventLog a caso
| Device | ultimo EventLog

Questo problema si verifica perché Sql Server, nel recuperare tutti gli eventlog, non ti garantisce che l'ultimo da te inserito sia effettivamente l'ultimo che ti risulta nella lista.
Cito da qui: http://msdn.microsoft.com/en-us/library/ms188385.aspx


The order in which rows are returned in a result set are not guaranteed unless an ORDER BY clause is specified.

Quindi, usare l'extension method .OrderBy è comunque indicato se vuoi assicurarti che i risultati ti siano forniti nell'ordine voluto.

Chiarito questo aspetto, resta un'altra cosa in sospeso: il fatto che l'accesso alla proprietà di navigazione .EventLog vada a materializzare tutte le entità, mentre a te ne serve una sola. Quello che puoi fare è usare il metodo .CreateSourceQuery per ottenere un IQueryable da .EventLog. E' molto semplice:
Dim cs As EventLog = Me.EventLog.CreateSourceQuery().OrderByDescending(Function(d) d.ID).FirstOrDefault
Così dovrebbe essere ok anche dal punto di vista delle prestazioni.

In chiusura, vorrei fare due considerazioni marginali sulla classe Device, ma si fa per parlare...
Select Case Me.CurrentStatus.StatusEnum
                Case EnumDeviceStatus.Successful
                    Return "~/Images/Ok-256.png"
                Case EnumDeviceStatus.Failed
                    Return "~/Images/Error-256.png"
Nelle classi di dominio, prova a non introdurre delle proprietà come StatusImage che riguardano strettamente la presentazione dei dati.
Potresti cavartela semplicemente con StatusEnum: stampala nell'html, come valore dell'attributo class. Esempio:
<div class="status Successful">Titolo del device</div>
Poi, dal CSS, definisci l'immagine come sfondo della div. Ad esempio protresti fare (ovviamente adattalo alle tue esigenze):
.status.Successful {background-image:url('Images/Ok-256.png'); background-position:left; background-repeat:no-repeat;}


L'altra cosa riguarda la proprietà CurrentStatus. Teoricamente, come ho appreso l'altro ieri al .Net Campus, nelle classi di dominio dovresti scrivere solo logica invariante. Cioè, data una stessa istanza di Device, il CurrentStatus restituito dovrebbe essere sempre lo stesso. Invece, in questo caso, il CurrentStatus cambia in base alla data/ora corrente, che è cablata all'interno della proprietà.
Potresti, ad esempio, convertire la proprietà CurrentStatus in un metodo GetCurrentStatus(DateTime dataora), così esponi la sua dipendenza da una data/ora. Oppure, ancor meglio, estrai tutta questa logica in un extension method o in un servizio. Lo scopo è quello di mantenere snelle le classi di dominio e relegare altrove la logica della loro interazione col "mondo esterno" o con altre classi di dominio.

ciao
Modificato da BrightSoul il 23 aprile 2012 22.19 -

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.