framework - Depuración de LINQ to SQL SubmitChanges()
entity framework get sql (18)
Me está costando mucho trabajo intentar depurar LINQ to SQL y enviar cambios.
He estado usando http://weblogs.asp.net/scottgu/archive/2007/07/31/linq-to-sql-debug-visualizer.aspx , que funciona muy bien para la depuración de consultas simples.
Estoy trabajando en la clase DataContext para mi proyecto con el siguiente fragmento de mi aplicación:
JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.UpdateJobMaster(newJobToCreate);
this.SubmitChanges();
Encontraré algunas excepciones muy raras cuando ejecuto esto. SubenCambios;
Index was outside the bounds of the array.
El rastro de la pila va a lugares en los que no puedo entrar:
at System.Data.Linq.IdentityManager.StandardIdentityManager.MultiKeyManager`3.TryCreateKeyFromValues(Object[] values, MultiKey`2& k)
at System.Data.Linq.IdentityManager.StandardIdentityManager.IdentityCache`2.Find(Object[] keyValues)
at System.Data.Linq.IdentityManager.StandardIdentityManager.Find(MetaType type, Object[] keyValues)
at System.Data.Linq.CommonDataServices.GetCachedObject(MetaType type, Object[] keyValues)
at System.Data.Linq.ChangeProcessor.GetOtherItem(MetaAssociation assoc, Object instance)
at System.Data.Linq.ChangeProcessor.BuildEdgeMaps()
at System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode)
at System.Data.Linq.DataContext.SubmitChanges()
at JobTrakDataContext.CreateNewJob(NewJob job, String userName) in D:/JobTrakDataContext.cs:line 1119
¿Alguien tiene alguna herramienta o técnica que usan? ¿Me estoy perdiendo algo simple?
EDITAR : He configurado la depuración de .NET mediante la sugerencia de Slace, sin embargo, el código .net 3.5 aún no está disponible: http://referencesource.microsoft.com/netframework.aspx
EDIT2 : He cambiado a InsertOnSubmit según la sugerencia de sirrocco, todavía obteniendo el mismo error.
EDIT3: Implementé las sugerencias de Sam tratando de registrar el SQL generado y atrapar la excepción ChangeExceptoinception. Estas sugerencias no arrojan más luz, nunca voy a generar SQL cuando se lanza mi excepción.
EDIT4: Encontré una respuesta que funciona para mí a continuación. Es solo una teoría pero ha solucionado mi problema actual.
De hecho, hemos dejado de utilizar el diseñador de Linq to SQL para nuestros grandes proyectos y este es uno de los principales motivos. También cambiamos muchos de los valores predeterminados para nombres, tipos de datos y relaciones y de vez en cuando el diseñador perdería esos cambios. Nunca encontré una razón exacta, y no puedo reproducirla de manera confiable.
Eso, junto con las otras limitaciones, nos hizo abandonar al diseñador y diseñar las clases a mano. Después de que nos acostumbramos a los patrones, en realidad es más fácil que usar el diseñador.
Hrm.
Tomando un WAG (Wild Ass Guess), me parece que LINQ - SQL está tratando de encontrar un objeto con una identificación que no existe, basada de alguna manera en la creación de la clase JobMaster. ¿Hay claves externas relacionadas con esa tabla, de modo que LINQ to SQL intente obtener una instancia de una clase, que puede no existir? Parece que está estableciendo el ProjectID del nuevo objeto en una cadena: ¿realmente tiene una identificación que es una cadena? Si intenta establecerlo en un nuevo proyecto, deberá crear un nuevo proyecto y obtener su identificación.
Por último, ¿qué hace UpdateJobMaster? ¿Podría estar haciendo algo tal que se aplicaría lo anterior?
Una solución simple podría ser rastrear su base de datos e inspeccionar las consultas que se ejecutan en su contra, filtrada, por supuesto, para clasificar otras aplicaciones, etc., accediendo a la base de datos.
Por supuesto, eso solo ayuda una vez que superas las excepciones ...
VS 2008 tiene la capacidad de depurar el framework .NET ( http://blogs.msdn.com/sburke/archive/2008/01/16/configuring-visual-studio-to-debug-net-framework-source-code .aspx )
Esta es probablemente su mejor apuesta, puede ver lo que está sucediendo y cuáles son todas las propiedades en el punto exacto en el tiempo
¿Por qué haces UpdateJobMaster en una nueva instancia? ¿No debería ser InsertOnSubmit?
JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.InsertOnSubmit(newJobToCreate);
this.SubmitChanges();
Mi primera acción de depuración sería mirar el SQL generado:
JobMaster newJobToCreate = new JobMaster();
newJobToCreate.JobID = 9999
newJobToCreate.ProjectID = "New Project";
this.UpdateJobMaster(newJobToCreate);
this.Log = Console.Out; // prints the SQL to the debug console
this.SubmitChanges();
El segundo sería capturar la ChangeConflictException y echar un vistazo a los detalles de la falla.
catch (ChangeConflictException e)
{
Console.WriteLine("Optimistic concurrency error.");
Console.WriteLine(e.Message);
Console.ReadLine();
foreach (ObjectChangeConflict occ in db.ChangeConflicts)
{
MetaTable metatable = db.Mapping.GetTable(occ.Object.GetType());
Customer entityInConflict = (Customer)occ.Object;
Console.WriteLine("Table name: {0}", metatable.TableName);
Console.Write("Customer ID: ");
Console.WriteLine(entityInConflict.CustomerID);
foreach (MemberChangeConflict mcc in occ.MemberConflicts)
{
object currVal = mcc.CurrentValue;
object origVal = mcc.OriginalValue;
object databaseVal = mcc.DatabaseValue;
MemberInfo mi = mcc.Member;
Console.WriteLine("Member: {0}", mi.Name);
Console.WriteLine("current value: {0}", currVal);
Console.WriteLine("original value: {0}", origVal);
Console.WriteLine("database value: {0}", databaseVal);
}
}
}
Puede crear una clase parcial para su DataContext y usar el método Creado o qué método tiene para configurar el registro en la consola.out envuelto en un #de DEPURACIÓN ... esto le ayudará a ver las consultas ejecutadas al depurar cualquier instancia de el contexto de datos que estás usando.
Lo encontré útil al depurar excepciones de LINQ to SQL.
partial void OnCreated()
{
#if DEBUG
this.Log = Console.Out;
#endif
}
El error al que se refiere arriba generalmente es causado por asociaciones que apuntan en la dirección incorrecta . Esto ocurre muy fácilmente cuando se agregan asociaciones de forma manual al diseñador, ya que las flechas de asociación en el diseñador de L2S apuntan hacia atrás en comparación con las herramientas de modelado de datos.
Sería bueno si arrojaran una excepción más descriptiva, y tal vez lo harán en una versión futura. (Damien / Matt ...?)
Primero, gracias a todos por la ayuda, finalmente lo encontré.
La solución fue eliminar el archivo .dbml del proyecto, agregar un archivo .dbml en blanco y volver a llenarlo con las tablas necesarias para mi proyecto desde ''Server Explorer''.
Noté un par de cosas mientras hacía esto:
- Hay unas pocas tablas en el sistema nombradas con dos palabras y un espacio entre las palabras, es decir, "Job Master". Cuando estaba volviendo a poner esa tabla en el archivo .dbml crearía una tabla llamada ''Job_Master'', que reemplazaría el espacio con un guión bajo.
- En el archivo .dbml original, uno de mis desarrolladores había revisado el archivo .dbml y eliminado todos los caracteres de subrayado, por lo que ''Job_Master'' se convertiría en ''JobMaster'' en el archivo .dbml. En el código, podríamos consultar la tabla en una convención de nomenclatura más, para nosotros.
- Mi teoría es que en algún lugar, la traducción de ''JobMaster'' a ''Job Master'' se perdió mientras hacía la proyección, y seguí con el error de matriz fuera de límites.
Es solo una teoría Si alguien puede explicarlo mejor, me encantaría tener una respuesta concreta aquí.
Compruebe que todas las columnas de "clave principal" en su dbml realmente se relacionan con las claves principales en las tablas de la base de datos. Acabo de tener una situación en la que el diseñador decidió poner una columna PK adicional en el archivo dbml, lo que significaba que LINQ to SQL no podía encontrar las dos caras de una clave externa al guardar.
Recientemente encontré el mismo problema: lo que hice fue
Proce proces = unit.Proces.Single(u => u.ProcesTypeId == (from pt in context.ProcesTypes
where pt.Name == "Fix-O"
select pt).Single().ProcesTypeId &&
u.UnitId == UnitId);
En lugar de:
Proce proces = context.Proces.Single(u => u.ProcesTypeId == (from pt in context.ProcesTypes
where pt.Name == "Fix-O"
select pt).Single().ProcesTypeId &&
u.UnitId == UnitId);
Donde el contexto era obviamente el objeto DataContext y "unidad" una instancia del objeto Unit, una clase de datos de un archivo dbml.
A continuación, utilicé el objeto "proce" para establecer una propiedad en una instancia de otro objeto de clase de datos. Probablemente, el motor LINQ no pudo verificar si la propiedad que estaba configurando desde el objeto "proce" estaba permitida en el comando INSERT que iba a tener que ser creado por LINQ para agregar el otro objeto Data Class a la base de datos.
Siempre me ha parecido útil saber exactamente qué cambios se envían a DataContext en el método SubmitChanges ().
Utilizo el método DataContext.GetChangeSet () , devuelve una instancia de objeto ChangeSet que contiene 3 IList de solo lectura de objetos que se han agregado, modificado o eliminado.
Puede colocar un punto de interrupción justo antes de la llamada al método SubmitChanges y agregar un reloj (o reloj rápido) que contenga:
ctx.GetChangeSet();
Donde ctx es la instancia actual de su DataContext, y luego podrá rastrear todos los cambios que serán efectivos en la llamada SubmitChanges.
Tuve el mismo error de no hablar.
Tenía una relación de clave externa con una columna de una tabla que no era la clave principal de la tabla, sino una columna única. Cuando cambié la columna única para que fuera la clave principal de la tabla, el problema desapareció.
Espero que esto ayude a cualquiera!
Es casi seguro que esta no será la causa raíz de todos, pero encontré esta misma excepción en mi proyecto y encontré que la causa raíz era que se estaba lanzando una excepción durante la construcción de una clase de entidad. Curiosamente, la verdadera excepción es "perdida" y en su lugar se manifiesta como una excepción ArgumentOutOfRange que se origina en el iterador de la instrucción Linq que recupera el / los objeto / s.
Si recibe este error y ha introducido los métodos OnCreated o OnLoaded en sus POCO, intente recorrer esos métodos.
Esto es lo que hice
...
var builder = new StringBuilder();
try
{
context.Log = new StringWriter(builder);
context.MY_TABLE.InsertAllOnSubmit(someData);
context.SubmitChanges();
}
finally
{
Log.InfoFormat("Some meaningful message here... ={0}", builder);
}
Terminé con esta pregunta cuando intentaba depurar mi LINQ ChangeConflictException. Al final me di cuenta de que el problema era que agregué manualmente una propiedad a una tabla en mi archivo DBML, pero olvidé establecer las propiedades como Nullable (debería haber sido cierto en mi caso) y el tipo de datos del servidor.
Espero que esto ayude a alguien.
Publiqué mis experiencias con esta excepción en una respuesta a SO # 237415
Publiqué una pregunta similar el día de hoy aquí: Excepción de LINQ extraño (Índice fuera de límites) .
Es un caso de uso diferente: donde ocurre este error durante un SubmitChanges (), el mío ocurre durante una consulta simple, pero también es un error de índice fuera de rango.
Publicación cruzada en esta pregunta en caso de que la combinación de datos en las preguntas ayude a una buena respuesta samaritana, ya sea :)