2008-10-26 16 views
5

Sto tentando di utilizzare LINQ per inserire un record in una tabella figlio e io sono ricevere un errore "Cast specificato non valido" che ha qualcosa da fare con le chiavi interessate. La traccia dello stack è:LINQ to SQL -

Messaggio: Il cast specificato non è valido.

Tipo: System.InvalidCastException Fonte: System.Data.Linq TargetSite: booleani TryCreateKeyFromValues ​​(System.Object [], V ByRef) HelpLink: null Stack: a System.Data.Linq.IdentityManager.StandardIdentityManager .SingleKeyManager 2.TryCreateKeyFromValues(Object[] values, V& v) at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache 2.Find (Object [] valori chiave) a System.Data.Linq.IdentityManager.StandardIdentityManager.Find (metatipo tipo, dell'oggetto []) a valori- System.Data.Linq.CommonDataServices.GetCachedObject (metatipo type, Object [] keyValues) a System.Data.Linq.ChangeProcessor.GetOtherItem (MetaAsso ciazione assoc, Object esempio) in System.Data.Linq.ChangeProcessor.BuildEdgeMaps() a System.Data.Linq.ChangeProcessor.SubmitChanges (ConflictMode failureMode) a System.Data.Linq.DataContext.SubmitChanges (ConflictMode failureMode) a System.Data.Linq.DataContext.SubmitChanges()

(.....)

Questo errore viene gettata sul seguente codice:

ResponseDataContext db = new ResponseDataContext(m_ConnectionString); 
CodebookVersion codebookVersion = db.CodebookVersions.Single(cv => cv.VersionTag == m_CodebookVersionTag); 
ResponseCode rc = new ResponseCode() 
    { 
     SurveyQuestionName = "Q11", 
     Code = 3, 
     Description = "Yet another code" 
    }; 
codebookVersion.ResponseCodes.Add(rc); 
db.SubmitChanges(); //exception gets thrown here 

Le tabelle in questione hanno una relazione FK tra le due.
La colonna della tabella padre è chiamata 'id', è il PK ed è di tipo: INT NOT NULL IDENTITY
La colonna della tabella figlio è chiamata 'responseCodeTableId' ed è di tipo: INT NOT NULL.

codebookVersion (classe genitore) associa al tavolo tblResponseCodeTable
responseCode (ChildClass) mappe a tavola tblResponseCode

Se eseguo direttamente SQL, funziona. per esempio.

INSERT INTO tblResponseCode 
(responseCodeTableId, surveyQuestionName, code, description) 
VALUES (13683, 'Q11', 3, 'Yet another code') 

Gli aggiornamenti della stessa classe funzionano correttamente. per esempio.

codebookVersion.ResponseCodes[0].Description = "BlahBlahBlah"; 
db.SubmitChanges(); //no exception - change is committed to db 

Ho esaminato la variabile, rc, dopo l'operazione .Add() e lo fa, infatti, ricevo la corretta responseCodeTableId, proprio come ci si aspetta dal momento che sto aggiungendolo a quella raccolta.

tblResponseCodeTable's full definition: 
COLUMN_NAME TYPE_NAME 
id     int identity 
responseCodeTableId int 
surveyQuestionName nvarchar 
code    smallint 
description   nvarchar 
dtCreate   smalldatetime 

dtCreate ha un valore predefinito GetDate().

L'unico altro po 'di informazioni utili che mi viene in mente è che non SQL è mai provato a fronte del database, in modo da LINQ soffia fino prima ancora tentativi (da qui l'errore non essendo uno SqlException). Ho profilato e verificato che nessun tentativo è fatto per eseguire alcuna dichiarazione sul database.

Ho letto e ho visto il problema quando si ha una relazione con un campo non PK, ma questo non si adatta al mio caso.

Qualcuno può far luce su questa situazione per me? Che cosa incredibilmente ovvia mi manca qui?

Molte grazie.
Paul Prewett

+0

Il problema simile è discusso qui, risolto i miei problemi: http://stackoverflow.com/questions/4801364/specified-cast-is-not-valid-error-when-saving- linq-to-sql-entity –

risposta

0
ResponseCode rc = new ResponseCode() 
    { 
     SurveyQuestionName = "Q11", 
     Code = 3, 
     Description = "Yet another code" 
    }; 

e:

INSERT INTO tblResponseCode 
(responseCodeTableId, surveyQuestionName, code, description) 
VALUES (13683, 'Q11', 3, 'Yet another code') 

non sono gli stessi, non sta passando nel riferimento chiave esterna. Ora, io sono enorme n00b a LINQ2SQL, ma scommetterei che LINQ2SQL non è abbastanza intelligente per farlo per te, e si aspetta che sia il primo parametro del dizionario anonimo, e sta provando a lanciare una stringa su un numero intero .

Solo alcune idee.

+0

rc viene aggiunto tramite la proprietà FK di codebookVersion -> codebookVersion.ResponseCodes.Add (rc); – chakrit

0

Questo blocco:

codebookVersion.ResponseCodes.Add(rc); 
db.SubmitChanges(); //exception gets thrown here 

Puoi provare InsertOnSubmit invece di Add? vale a dire

codebookVersion.ResponseCodes.InsertOnSubmit(rc); 

Penso Add non è destinata ad essere utilizzata per inserire i record se la memoria non m'inganna. InsertOnSubmit è quello da usare.

0

Per cercare di restringere il colpevole.

Hai provato sostituendo il dizionario anonimo con qualcosa di simile:

ResponseCode rc = new ResponseCode(); 

rc.SurveyQuestName = "Q11"; 
rc.Code = 3; 
rc.Description = "Yet Another Code"; 

devo ancora lavorare molto con .NET 3.5 ancora (lavoro di giorno è ancora tutto 2.0), quindi mi chiedo se ci è un problema con il passaggio dei dati utilizzando il dizionario anonimo (i casi non corrispondono alle colonne SQL per uno).

0

Sì, ho letto questo e altri post, ma sembra sempre coinvolgere qualcuno che si collega a un campo che ha semplicemente un contrappunto unico. O nel caso di questo tizio (che suona esattamente come il mio), non ha trovato una soluzione.

Ecco la tabella padre:

tblResponseTable definition (which maps to CodebookVersion) 
COLUMN_NAME TYPE_NAME 
id int identity 
versionTag nvarchar 
responseVersionTag nvarchar 

versionTag ha un contraint unico su di esso, ma che non è rappresentato da nessuna parte che posso vedere nel roba LINQ to SQL - e dal momento che nulla va mai al database ... ancora bloccato.

1

Poiché il database non viene chiamato, penso che si debbano osservare le mappature che linq sta utilizzando sql. Com'è l'associazione? Ci dovrebbe essere un'associazione su entrambe le classi genitore e figlio. Dai un'occhiata all'associazione linq to sql tra le due classi. L'associazione dovrebbe avere una proprietà ThisKey. Il cast che sta fallendo sta cercando di trasmettere il valore della proprietà a cui punta ThisKey, penso. Per quanto posso dire, ci può essere un problema quando c'è più di una chiave e il tipo della prima chiave non corrisponde al tipo indicato da ThisKey. Non sono sicuro di come linq determinerebbe quale sia la prima chiave. A giudicare dall'aspetto, hai solo una chiave e una chiave esterna che non dovrebbe essere il problema, ma il designer, se lo stai utilizzando, è noto per essere creativo. Sto quasi indovinando, ma questo sembra qualcosa che ho visto prima.

0

Mike, ho sentito. Ma non importa dove guardo, tutto sembra corretto. Ho controllato e ricontrollato che ResponseTableId è un int e che Id è un int. Sono definiti come tali nel designer e quando guardo il codice generato, tutto sembra di nuovo in ordine.

Ho esaminato le associazioni. Eccoli:

[Table(Name="dbo.tblResponseCode")] 
public partial class ResponseCode : ... 
    ... 
    [Association(Name="CodebookVersion_tblResponseCode", Storage="_CodebookVersion", ThisKey="ResponseCodeTableId", OtherKey="Id", IsForeignKey=true)] 
    public CodebookVersion CodebookVersion 
    { 
     ... 
    } 

[Table(Name="dbo.tblResponseCodeTable")] 
    public partial class CodebookVersion : ... 
    ... 
    [Association(Name="CodebookVersion_tblResponseCode", Storage="_ResponseCodes", ThisKey="Id", OtherKey="ResponseCodeTableId")] 
    public EntitySet<ResponseCode> ResponseCodes 
    { 
     ... 
    } 

e uno screenshot dell'associazione nel caso che vi aiuterà:
designer

Eventuali ulteriori pensieri?

0
ResponseCode rc = new ResponseCode() 
{ 
    CodebookVersion = codebookVersion, 
    SurveyQuestionName = "Q11", 
    Code = 3, 
    Description = "Yet another code" 
}; 
db.ResponseCodes.InsertOnSubmit(rc); 
db.SubmitChanges(); 
0

Si consiglia di verificare che tutti i campi nelle tabelle del database che vengono impostate dal server db quando si inserisce un nuovo record hanno che riflette nel diagramma di LINQ to SQL. Se si seleziona un campo nel diagramma Linq a SQL e si visualizzano le sue proprietà, verrà visualizzato un campo denominato "Valore generato automaticamente" che, se impostato su true, garantirà che tutti i nuovi record assumano il valore predefinito specificato nel database.

0
+0

Grazie per il downvote. Noterai che questa risposta ha 3 anni e questo era il discorso in quel momento. –

+0

Ho downsotato per due motivi: 1) Non affronta affatto il problema descritto nell'OP (mi sono imbattuto recentemente in questo problema); e 2) il post sul blog specificamente collegato non ha alcun accenno alla deprecazione e al contrario dice "Stiamo ascoltando i clienti riguardo LINQ a SQL e continueremo ad evolvere il prodotto sulla base del feedback che riceviamo anche dalla comunità". – DuckMaestro

+1

Abbastanza giusto. Grazie per la spiegazione. –

0

Mi sono imbattuto in un problema molto simile. Io collego voi sopra al mio post prolisso: http://forums.asp.net/p/1223080/2763049.aspx

E sarò anche offrire una soluzione, solo una supposizione ...

ResponseDataContext db = new ResponseDataContext(m_ConnectionString); 
    CodebookVersion codebookVersion = db.CodebookVersions.Single(cv => cv.VersionTag == m_CodebookVersionTag); 
    ResponseCode rc = new ResponseCode() 
    { 
     ResponseCodeTableId = codebookVersion.Id, 
     SurveyQuestionName = "Q11", 
     Code = 3, 
     Description = "Yet another code" 
    }; 
    db.ResponseCodes.InsertOnSubmit(rc); 
    db.SubmitChanges(); 
0

qualche parte nel vostro oggetto grafico v'è un errore di conversione, il il modello di dati sottostante (o il modello Linq To SQL) è cambiato. Questo è in genere qualcosa come NVARCHAR (1) -> CHAR quando dovrebbe essere STRING o qualcosa di simile.

Questo errore non è divertente da cercare, si spera che il modello dell'oggetto sia piccolo.

1

È un esempio di questo bug? Se è così, prova a eseguire il tuo codice in .NET 4.0 ora che la beta è fuori.

Se, come me, non sei pronto per iniziare a utilizzare la versione beta, potresti riuscire a risolvere il problema. Il problema sembra essere che LINQ non supporta correttamente le relazioni definite su campi chiave non primari. Tuttavia, il termine "chiave primaria" non fa riferimento alla chiave primaria definita nella tabella SQL, ma alla chiave primaria definita nella finestra di progettazione LINQ.

Se si trascinano le tabelle nella finestra di progettazione, Visual Studio ispeziona automaticamente la chiave primaria definita nel database e contrassegna i campi di classe corrispondenti come "chiavi primarie". Tuttavia, questi non hanno bisogno di corrispondere tra loro. È possibile rimuovere la chiave che Visual Studio ha scelto per te e selezionare un altro campo (o un gruppo di campi).Naturalmente, è necessario assicurarsi che ciò sia logico (si dovrebbe avere un vincolo univoco nel database sul campo/campi che si sceglie).

Quindi avevo 2 tabelle/classi correlate tra loro utilizzando una chiave alternativa. La tabella padre aveva 2 chiavi: una chiave primaria surrogata definita come int e una chiave naturale alternativa definita come una stringa. Nella finestra di progettazione LINQ, avevo definito l'associazione utilizzando la chiave alternativa e ho sperimentato InvalidCastException ogni volta che tentavo di aggiornare quel campo di associazione sull'oggetto figlio. Per risolvere il problema, sono entrato nel designer LINQ, ho selezionato l'int e poi ho cambiato la proprietà della chiave primaria da True a False. Quindi ho scelto la stringa e ho impostato la proprietà Key primaria su True. Ricompilato, ritestato e InvalidCastException è sparito.

Guardando lo schermo colpo sembra che si può essere in grado di risolvere il problema modificando la chiave primaria LINQ su ResponseCode da ResponseCode.ID a ResponseCode.ResponseCodeTableID