2008-10-26 30 views
5

Estoy tratando de usar LINQ para insertar un registro en una tabla secundaria y estoy recibiendo un error "Cast especificado no es válido" que tiene algo que ver con las claves involucradas w/ . El seguimiento de la pila es:LINQ to SQL -

Mensaje: La conversión especificada no es válida.

Tipo: System.InvalidCastException Fuente: System.Data.Linq TargetSite: booleanas TryCreateKeyFromValues ​​(System.Object [], V ByRef) HelpLink: null Stack: en System.Data.Linq.IdentityManager.StandardIdentityManager .SingleKeyManager 2.TryCreateKeyFromValues(Object[] values, V& v) at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache 2.Find (Object [] keyValues) en System.Data.Linq.IdentityManager.StandardIdentityManager.Find (MetaType tipo, objeto [] keyValues) en System.Data.Linq.CommonDataServices.GetCachedObject (MetaType tipo, Object [] keyValues) en System.Data.Linq.ChangeProcessor.GetOtherItem (MetaAsso ciación Assoc, objeto de instancia) en System.Data.Linq.ChangeProcessor.BuildEdgeMaps() en System.Data.Linq.ChangeProcessor.SubmitChanges (ConflictMode failureMode) en System.Data.Linq.DataContext.SubmitChanges (ConflictMode failureMode) en System.Data.Linq.DataContext.SubmitChanges()

(.....)

Este error se está lanzando en el siguiente código:

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 

Las tablas en cuestión tienen una relación FK entre las dos.
La columna de la tabla principal se llama 'id', es PK, y es del tipo: INT NOT NULL IDENTITY
La columna de la tabla hija se llama 'responseCodeTableId' y es del tipo: INT NOT NULL.

codebookVersion (clase padre) se asigna a la mesa tblResponseCodeTable
ResponseCode (ChildClass) se asigna a tblResponseCode mesa

Si ejecuto SQL directamente, funciona. p.ej.

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

Las actualizaciones de la misma clase funcionan correctamente. p.ej.

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

He examinado la variable, RC, después de la operación .Add() y lo hace, de hecho, recibo el responseCodeTableId adecuado, tal como me esperaba, ya que estoy añadiendo a la colección.

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

dtCreate tiene un valor predeterminado de GetDate().

El único otro poco de información útil que se me ocurre es que ningún SQL se haya tratado contra la base de datos, por lo que LINQ es volar antes de que alguna vez intentos (de ahí el error de no ser un SqlException). He perfilado y verificado que no se intenta ejecutar ninguna declaración en la base de datos.

He leído y visto el problema cuando tienes una relación con un campo PK no, pero eso no se ajusta a mi caso.

¿Alguien puede arrojar algo de luz sobre esta situación para mí? ¿Qué cosa increíblemente obvia me estoy perdiendo aquí?

Muchas gracias.
Paul Prewett

+0

Problema similar se discute aquí, resolvió mis problemas: http://stackoverflow.com/questions/4801364/specified-cast-is-not-valid-error-when-saving- linq-to-sql-entity –

Respuesta

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

y:

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

no son lo mismo, no está de paso en la referencia de clave externa. Ahora, soy enorme n00b en LINQ2SQL, pero apostaría que LINQ2SQL no es lo suficientemente inteligente como para hacer eso por usted, y lo espera como el primer parámetro del diccionario anónimo, y está tratando de convertir una cadena en un entero .

Solo algunas ideas.

+0

rc se está agregando a través de la propiedad FK de codebookVersion -> codebookVersion.ResponseCodes.Add (rc); – chakrit

0

Este bloque:

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

Se puede tratar InsertOnSubmit en lugar de Add? es decir,

codebookVersion.ResponseCodes.InsertOnSubmit(rc); 

Creo Add no está destinado a ser utilizado para insertar registros si la memoria no me falla. InsertOnSubmit es el que se debe usar.

0

Para tratar de reducir al culpable.

Ha intentado sustituir el diccionario anónima con algo como:

ResponseCode rc = new ResponseCode(); 

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

todavía tengo que trabajar realmente con .NET 3.5 todavía (trabajo del día sigue siendo todo 2.0), por lo que me pregunto si hay es un problema al pasar los datos usando el diccionario anónimo (los casos no coinciden con las columnas de SQL para uno).

0

Sí, he leído eso y otras publicaciones, pero siempre parece involucrar a alguien que se vincula a un campo que simplemente tiene un contraint único. O en el caso de este tipo (que suena exactamente como el mío), no obtuvo una solución.

Aquí está la tabla primaria:

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

versionTag tiene un contraint único en él, pero eso no está representado en cualquier lugar que pueda ver en la materia LINQ a SQL - y puesto que nada nunca va a la base de datos ... todavía atorada.

1

Dado que no se está llamando a la base de datos, creo que hay que mirar las asignaciones que está utilizando linq para sql. ¿Cómo se ve la Asociación? Debería haber una Asociación en las clases de padres e hijos. Eche un vistazo a la asociación de linq a sql entre las dos clases. La Asociación debe tener una propiedad ThisKey. El reparto que está fallando trata de arrojar el valor de la propiedad a la que apunta ThisKey, creo. Por lo que puedo decir, puede haber un problema cuando hay más de una clave y el tipo de la primera clave no coincide con el tipo que ThisKey señala también. No estoy seguro de cómo linq determinaría cuál es la primera clave. Por lo que se ve, solo tiene una clave y una clave externa, así que ese no debería ser el problema, pero se sabe que el diseñador, si lo está utilizando, se vuelve creativo. Estoy adivinando, pero esto parece algo que he visto antes.

0

Mike, te escucho. Pero no importa dónde miro, todo parece correcto. Revisé y volví a comprobar que ResponseTableId es un int y que Id es un int. Se definen como tales en el diseñador y cuando voy a ver el código generado, parece que todo vuelve a estar en orden.

He examinado las asociaciones. Aquí están:

[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 
    { 
     ... 
    } 

Y una captura de pantalla de la asociación en caso de que ayudará a:
designer

Cualquier otra idea?

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

Es posible que desee comprobar para ver que todos los campos de las tablas de bases de datos que son fijados por el servidor db cuando se inserta un nuevo registro tienen que refleja en el diagrama de LINQ to SQL. Si selecciona un campo en el diagrama de Linq a SQL y visualiza sus propiedades, verá un campo llamado "Valor generado automáticamente" que, si se establece en verdadero, garantizará que todos los registros nuevos adopten el valor predeterminado especificado en la base de datos.

0
+0

Gracias por el voto a favor. Notarás que esta respuesta tiene 3 años y esa fue la conversación en ese momento. –

+0

Bajé la votación por dos razones: 1) No aborda en absoluto el problema que se describe en el PO (Me encontré con este tema recientemente); y 2) la publicación de blog específicamente vinculada no menciona la desaprobación y, por el contrario, dice: "Escuchamos a los clientes sobre LINQ to SQL y seguiremos evolucionando el producto según los comentarios que recibimos de la comunidad también". – DuckMaestro

+1

Bastante justo. Gracias por la explicación. –

0

Me encontré con un problema muy similar. Voy enlace que a mi post prolijo: http://forums.asp.net/p/1223080/2763049.aspx

Y también a ofrecer una solución, sólo una suposición ...

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

En algún lugar de su gráfico de objetos hay un error de conversión, el modelo de datos subyacente (o el modelo de Linq a SQL) ha cambiado. Esto es típicamente algo así como NVARCHAR (1) -> CHAR cuando debería ser STRING, o algo similar.

Este error no es divertido de cazar, con suerte su modelo de objetos es pequeño.

1

¿Es este un ejemplo de este bug? Si es así, intente ejecutar su código en .NET 4.0 ahora que la versión beta está desactivada.

Si, como yo, no está listo para comenzar a utilizar la versión beta, es posible que pueda evitar el problema. El problema parece ser que LINQ no admite correctamente las relaciones definidas en campos clave no primarios. Sin embargo, el término "clave principal" no se refiere a la clave primaria definida en la tabla SQL, sino a la clave primaria definida en el diseñador LINQ.

Si arrastró sus tablas al diseñador, entonces Visual Studio inspecciona automáticamente la clave principal definida en la base de datos y marca los campos de clase correspondientes como "claves principales". Sin embargo, estos no necesitan corresponderse entre sí. Puede eliminar la clave que Visual Studio eligió para usted y elegir otro campo (o grupo de campos).Por supuesto, debe asegurarse de que esto sea lógico (debe tener una restricción única en la base de datos en el campo/campos que elija).

Así que tuve 2 tablas/clases relacionadas entre sí utilizando una clave alternativa. La tabla padre tenía 2 claves: una clave primaria sustituta definida como int, y una clave natural alternativa definida como una cadena. En el diseñador de LINQ, había definido la asociación usando la clave alternativa, y experimenté InvalidCastException cada vez que intentaba actualizar ese campo de asociación en el objeto hijo. Para evitar esto, entré en el diseñador de LINQ, seleccioné el int y luego cambié la propiedad de la clave principal de verdadero a falso. Luego elegí la cadena y establecí su propiedad de clave primaria en True. Se volvió a compilar, se volvió a probar y la InvalidCastException desapareció.

En cuanto a su imagen de las cámaras parece que puede ser capaz de solucionar el problema cambiando la clave principal LINQ en ResponseCode de ResponseCode.ID a ResponseCode.ResponseCodeTableID