LINQ to Entity - Stranissimo Index Out Of Range su Query

mercoledì 25 giugno 2014 - 11.44
Tag Elenco Tags  VB.NET  |  .NET 4.0  |  Windows XP  |  Visual Studio Express  |  SQL Server Express

mpaolo Profilo | Newbie

Buongiorno a tutti, mi capita un assurdo di Index Out Of Range ciclando i risultati di una semplicissima query

Utilizzo VisuaBasic 2010 Express e SQL Express 2008 R2

La tabella in questione:

CREATE TABLE [dbo].[Movcont_D](
[CodAZ] [int] NOT NULL,
[Anno] [int] NOT NULL,
[ID] [int] NOT NULL,
[Riga] [int] NOT NULL,
[Conto] [nvarchar](10) NULL,
[Descrizione] [nvarchar](50) NULL,
[V_Dare] [float] NULL,
[V_Avere] [float] NULL,
[ID_Cliente] [int] NULL,
[ID_Fornitore] [int] NULL,
[Partita_Anno] [int] NULL,
[Partita_ID] [int] NULL,
[Scadenza_ID] [int] NULL,
CONSTRAINT [PK_Movcont_D] PRIMARY KEY CLUSTERED
(
[CodAZ] ASC,
[Anno] ASC,
[ID] ASC,
[Riga] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]


La parte di codice incriminata:
Dim querytest = From eleD In newcontext.Movcont_D
Where eleD.Anno <= ianno

Dim n As Integer = 0
For Each tt In querytest
'il ciclo si pianta quando il campo [Riga] contiene il valore 16
Next

L'assurdo è che ci sono valori dopo tale riga che vengono tranquillamente letti se modifico la condizione:
Where eleD.Anno <= ianno AND eleD.Riga<>16


Ancora più assurdo il fatto che se inserisco gli stessi dati nel DB ma con il valore Riga sommato a 1000 in modo che non sia mai presente il valore 16, tutto fila liscio!

Non ci capisco nulla!!! Aiutatemi per cortesia
Grazie
Paolo

0v3rCl0ck Profilo | Guru

Secondo me mancano delle parti che non hai evidenziato nel codice riportato, tipo la variabile n dove la usi? un eccezione di tipo index out of range viene scatenato quando si prova ad accedere ad un array con un indice fuori dai limiti dell'array, cerchi per caso di accedere ad un array con indice quella variabile 'n'?

Hai provato a forzare l'enumeratore in una lista:

Dim l = querytest.ToList()


Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

mpaolo Profilo | Newbie

Grazie intanto per il rapido interessamento

Utilizzo EF da più di due anni, non ho mai incontrato un problema simile

Questo è il codice:

Dim newcontext As New ModelGESTContainer
Dim querytest = From eleD In newcontext.Movcont_D
Where eleD.Anno <= 2014

Dim l = querytest.ToList


Questo è il dettaglio dell'errore:

System.IndexOutOfRangeException non è stata gestita
Message=Indice oltre i limiti della matrice.
Source=System.Data.Entity
StackTrace:
in System.Data.EntityKey.CompositeValuesEqual(EntityKey key1, EntityKey key2)
in System.Data.EntityKey.InternalEquals(EntityKey key1, EntityKey key2, Boolean compareEntitySets)
in System.Data.EntityKey.Equals(EntityKey other)
in System.Collections.Generic.GenericEqualityComparer`1.Equals(T x, T y)
in System.Collections.Generic.Dictionary`2.FindEntry(TKey key)
in System.Collections.Generic.Dictionary`2.TryGetValue(TKey key, TValue& value)
in System.Data.Objects.ObjectStateManager.TryGetEntityEntry(EntityKey key, EntityEntry& entry)
in System.Data.Objects.EntityEntry.FixupEntityReferenceToPrincipal(EntityReference relatedEnd, EntityKey foreignKey, Boolean setIsLoaded, Boolean replaceExistingRef)
in System.Data.Objects.EntityEntry.FixupReferencesByForeignKeys(Boolean replaceAddedRefs)
in System.Data.Objects.ObjectStateManager.FixupReferencesByForeignKeys(EntityEntry newEntry, Boolean replaceAddedRefs)
in System.Data.Objects.ObjectStateManager.AddEntry(IEntityWrapper wrappedObject, EntityKey passedKey, EntitySet entitySet, String argumentName, Boolean isAdded)
in System.Data.Common.Internal.Materialization.Shaper.HandleEntityAppendOnly[TEntity](Func`2 constructEntityDelegate, EntityKey entityKey, EntitySet entitySet)
in lambda_method(Closure , Shaper )
in System.Data.Common.Internal.Materialization.Coordinator`1.ReadNextElement(Shaper shaper)
in System.Data.Common.Internal.Materialization.Shaper`1.SimpleEnumerator.MoveNext()
in System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
in System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
in prjGEST.frmEstrattoConto.GeneraEstratto() in S:\prjGEST\Base\prjGEST\frmEstrattoConto.vb:riga 46
in prjGEST.frmEstrattoConto.btGenera_Click(Object sender, EventArgs e) in S:\prjGEST\Base\prjGEST\frmEstrattoConto.vb:riga 22
in System.Windows.Forms.Control.OnClick(EventArgs e)
in System.Windows.Forms.Button.OnClick(EventArgs e)
in System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
in System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
in System.Windows.Forms.Control.WndProc(Message& m)
in System.Windows.Forms.ButtonBase.WndProc(Message& m)
in System.Windows.Forms.Button.WndProc(Message& m)
in System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
in System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
in System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
in System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
in System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
in System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
in System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
in Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
in Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
in Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
in prjGEST.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:riga 81
in System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
in System.AppDomain.nExecuteAssembly(RuntimeAssembly assembly, String[] args)
in System.Runtime.Hosting.ManifestRunner.Run(Boolean checkAptModel)
in System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly()
in System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData)
in System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext)
in System.Activator.CreateInstance(ActivationContext activationContext)
in Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssemblyDebugInZone()
in System.Threading.ThreadHelper.ThreadStart_Context(Object state)
in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
in System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
in System.Threading.ThreadHelper.ThreadStart()
InnerException:

grazie

0v3rCl0ck Profilo | Guru

prova a postare anche la query che viene generata da linq abilitando l'IntelliTrace, con gli events ADO.NET selezionati:


893x617 30Kb


riesci a vedere così la query:


1193x919 128Kb



Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

0v3rCl0ck Profilo | Guru

posta anche la classe di modellazione dell'entità "Movcont_D", come è strutturato? contiene una chiave composta?


Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

mpaolo Profilo | Newbie

Questo è il modello


1284x778 159Kb


In visual basic express 2010 non trovo l'opzione IntelliTrace

mpaolo Profilo | Newbie

Nel modello la tabella Movcont_D è relazionata con la tabella padre Movcont_T con i campi comuni CodAZ, Anno, ID
Ho provato ad eliminare la relazione ed il problema sparisce

La tabella Movcont_D ha come chiave primaria CodAZ, Anno, ID, Riga
quest'ultimo campo è la causa del problema quando contiene solo e soltanto il valore 16

Non riesco a venirne a capo

mpaolo Profilo | Newbie

Ho fatto una prova ulteriore:

Eliminati tutti i record sia della tabella figlia Movcont_D

Creo senza problemi i primi 16 record con riga da 0 a 15

quando inserisco il diciassettesimo record (riga=16) l'istruzione newcontext.Movcont_D.Addobject(newmovcont_d) genera l'errore IndexOut Of Range !!!!!!

L'assurdo è che se inserisco 17 o più record saltando il valore Riga=16 (es. Riga da 1001 a 1017) non si verifica alcun problema

Ma perchè ???

mpaolo Profilo | Newbie

La cosa incredibile è che nel DB il record con Riga=16 è stato scritto.

Se provo a leggere dal Context tutti i record si pianta sul record con Riga=16 con Index Out Of Range
Se con Sql ManagementStudio modifico il valore Riga di quel record da 16 a 160 non ho problemi nel leggere il record dal context
Se provo a modificare dal context il record con Riga=160 variando il valore Riga=16 sul Savechanges ritorna l'eccezzione di incoerenza nel context

Ma perchè il valore 16 su un campo chiave Int32 deve creare questo problema?

0v3rCl0ck Profilo | Guru

ho dato un occhio al punto che va in errore:

--> in System.Data.EntityKey.CompositeValuesEqual(EntityKey key1, EntityKey key2)

decompilando il framework per vedere come è sviluppato il metodo CompositeValuesEqual e guarda un po' come è fatto:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

e l'errore index out of range può succedere se key1 ha più chiavi di key2 ed è evidente da quel codice, il fatto è che non spiega come mai succeda solo quando vai ad inserire un record che ha riga=16... e poi guardando nella stack ad un passo prima di trova questo:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

che ha sua volta chiama "CompositeValuesEqual", e dove si vede chiaramente il controllo:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

quindi o _keyNames è valorizzato con un numero differente di elementi da _compositeKeyValues, oppure ci stiamo riferendo ad un framework diverso, e magari è un problema che nella versione che sto guardando avevano già risolto con quel controllo... io sto guardando l'assembly:

System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
del .NET 4.5

ma controllando il 3.5, sembra non ci sia traccia del metodo "CompositeValuesEqual", e quindi ne deduco che tu stia utilizzando il 4.5:

Il codice sorgente non è stato renderizzato qui
perchè non c'è sufficiente spazio.
Clicca qui per visualizzarlo in una nuova finestra

a questo punto non ti rimane che provare a riprodurre il problema in un progetto console con una struttura simile con 2 tabelle e quel tipo di relazione, passarmi il progetto e vedere cos'altro riesco a scoprire


Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

mpaolo Profilo | Newbie

Ti ringrazio tantissimo per l'interessamento e la competenza

Utilizzo Framework 4.0

Allego applicazione console scritta con VB 2010 express

Trovi anche il bakcup del DB effettuato con SQL Server 2008 Express

comunque la tabella padre ha un solo record, la tabella figlia ha 17 records



ancora grazie

0v3rCl0ck Profilo | Guru

appena ho un attimo ci guardo


Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

0v3rCl0ck Profilo | Guru

buone e cattive notizie....

la buona notizia è che a me funziona correttamente.
la cattiva notizia è che a me funziona correttamente.

ho aggiunto un console write:
Sub Main() Dim newcontext As New prjGESTEntities Dim query = From ele In newcontext.Movcont_D Dim l = query.ToList For Each movcontD As Movcont_D In l Console.WriteLine("Riga {0}", movcontD.Riga) Next End Sub

restorato il tuo db e runnato l'app... il risultato:

Riga 0
Riga 1
Riga 2
Riga 3
Riga 4
Riga 5
Riga 6
Riga 7
Riga 8
Riga 9
Riga 10
Riga 11
Riga 12
Riga 13
Riga 14
Riga 15
Riga 16
Riga 17
Press any key to continue . . .


io ho runnato l'applicazione da visual studio 2013, ma non ho cambiato il target framework, quindi non dovrebbe cambiare assolutamente niente, se non che, l'unica vera differenza è che io sicuramente ho sulla mia macchina il framework 4.5.1, quindi ho su anche il 4.5, queste sono in-place update, e rimpiazzano completamente il framework 4.0, ma essendo in-place, praticamente anche tutte le applicazione compilate con target fx 4.0 possono trarre vantaggio dal 4.5 e dalle sue point releases 4.5.1 e 4.5.2. Detto questo presumo che nella versione 4.5 ci sia di fatto quel check sui boundaries dell'array che ti ho postato prima, e che sul 3.5 non ci sia (confermato dal post precedente), come anche sul 4.0 (non posso confermartelo perchè ormai ho su il 4.5 che rimpiazza le dll del 4.0).

a questo punto ti consiglio di provare ad installare il fx 4.5.2 (l'ultimissimo RTM), senza necessariamente dovere compilare il progetto in 4.5 (quindi puoi lasciarlo compilare in 4.0), e vedere se il problema sparisce.

qui le istruzioni per installare le varie versioni tra cui la 4.5.2: http://goo.gl/DM3baE

Facci sapere se con il 4.5 installato il problema sparisce.

Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

mpaolo Profilo | Newbie

Hai centrato il problema ... Grande!

In effetti la stessa applicazione lanciata su un ambiente in cui è presente Framework 4.5.1 o 4.5.2 non ha problemi

Lanciata invece su un ambiente con Framework 4.0 non appena rileva la presenza del valore 16 sul campo Riga si pianta

Ma come posso risolvere su macchine con Windows XP dove non è supportato l'aggiornamento del Framework?





0v3rCl0ck Profilo | Guru

>Hai centrato il problema ... Grande!
>

bene

>In effetti la stessa applicazione lanciata su un ambiente in
>cui è presente Framework 4.5.1 o 4.5.2 non ha problemi
>
>Lanciata invece su un ambiente con Framework 4.0 non appena rileva
>la presenza del valore 16 sul campo Riga si pianta
>

la riga con valore 16 mi lascia comunque sconcertato, ma sai tu hai tempo di debuggare il framework? io sincertamente no, mi piacerebbe, ma lo trovo un po' una perdita di tempo...

>Ma come posso risolvere su macchine con Windows XP dove non è
>supportato l'aggiornamento del Framework?
>

intanto saprai bene che windows xp non è più supportato, e le macchine con xp devono aggiornarsi ad una qualsiasi versione successiva, esistono anche versioni di windows leggere (windows thin pc), basato su windows 7, che possono girare su hardware relativo all'era xp: http://goo.gl/9buk3P

detto questo capisco benissimo la problematica di fare aggiornare i sistemi, e quindi io penserei di cercare se esiste una patch mirata a quel bug, innanzitutto facendo un full update con windows update della macchine (sempre che con win xp funzioni ancora l'updater, altrimenti devi cercare le KB a mano!), altrimenti cercando un bug-fix mirato al problema del system.data.entity sempre dal microsoft download center, infine aprire un ticket di supporto con microsoft, anche perchè qua si parla di framework 4, non tanto di windows xp, e quindi il supporto c'è ancora per la versione 4, e alla peggio devono darti una patch mirata per la tua esigenza che puoi installare sulle macchine con il problema e che non possono aggiornarsi al 4.5. Apri il ticket e gli passi esattamente lo zip che hai passato a me, dicendo di provarlo su una macchina con solo il framework 4.0 installato (prima anche tu assicurati con una virtual machine, se installando il fx 4.0 e tutte gli updates si ripresenta il problema o sparisce, perchè forse ti mancano update su quelle macchine xp). Prova ad installare l'update 4.0.3 sui win xp, che dovrebbe contenere tutti gli updates del fx 4.0: http://support.microsoft.com/kb/2600211

se invece vuoi modificare la tua struttura per schivare il problema, puoi introdurre le chiavi surrogate, invece che avere chiavi composte (perchè è da li che credo nasca il problema), ricreando una struttura di questo tipo:

(ho tralasciato le colonne dettaglio per semplicità e ho cercato di tenere la tua naming convention)


374x226 10Kb


poi inserire un rafforzativo per evitare di inserire righe doppie per lo stesso ID_Movecont_T, sfruttando lo unique constraint:

ALTER TABLE dbo.New_Movcont_DSet ADD CONSTRAINT UK_New_Movcont_DSet_ID_Movecont_T_Riga UNIQUE (ID_Movecont_T, Riga)

lo unique constraint lo devi creare tu manualmente, perchè EF 4 non lo supporta, ma immagino che tu abbia un approccio database first, e quindi non avrai problema.

Nulla ti vieta di avere anche le colonne CodAZ, Anno e ID, nella tabella New_Movecont_DSet, se hai bisogno della chiave naturale completa (CodAZ, Anno, ID, Riga), di conseguenza inserendo la unique per quelle 4 colonne, però spesso non si ripetono i dati, perchè puoi sempre fare la lookup all'occorrenza, ma tutto dipende dalle tue esigenze. Per retrocompatibilità con il tuo codice se porti tutte le informazioni è più veloce il refactor.

Ti ho allegato l'esempio completo rivisitato con le surrogate.

Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic

mpaolo Profilo | Newbie

Grazie infinite per la tua disponibilità ed i preziosi suggerimenti

Tutti gli aggiornamento del framework 4 erano già presenti sul PC, pertanto il bug è rimasto.
Non credo di fare interventi sulla struttura del DB, ho fatto invece un test applicando un offset di 100000 al valore Riga e non si sono presentati problemi, rimane un vero mistero di come il solo valore 16 generi tale problema.

A questo punto farò ancora un test su un altro PC con Windows XP per verificare il ripetersi del problema, in caso positivo proverò ad aprire una segnalazione alla Microsoft ma intanto manterrò la soluzione offset.



Grazie ancora
Paolo


0v3rCl0ck Profilo | Guru

si, io credo che sia una cosa da sottoporre a Microsoft con una segnalazione, anche perchè effettivamente è davvero strano, e nel tuo codice non vedo niente di particolare o che non si dovrebbe fare, semplicemente è una relazione con chiave multipla.

tienici aggiornati

Michael Denny | Visual C# MVP
http://blogs.dotnethell.it/Regulator/
http://dennymichael.wordpress.com
http://mvp.microsoft.com/mvp/Michael%20Denny-5000735
Twitter: @dennymic
Partecipa anche tu! Registrati!
Hai bisogno di aiuto ?
Perchè non ti registri subito?

Dopo esserti registrato potrai chiedere
aiuto sul nostro Forum oppure aiutare gli altri

Consulta le Stanze disponibili.

Registrati ora !
Copyright © dotNetHell.it 2002-2025
Running on Windows Server 2008 R2 Standard, SQL Server 2012 & ASP.NET 3.5