2009-04-30 32 views
51

Estoy intentando eliminar una fila de gridview seleccionada utilizando LINQ (No LINQDataSource).System.Data.Linq.ChangeConflictException: Fila no encontrada o modificada

Cuando se cambia la selección, el enlace de vista detallada también se cambia . Puedo añadir una nueva entrada a la base de datos, pero cuando he añadido el código a un botón de eliminar en el interior del UpdatePanel, tengo una excepción:

try 
{   
    var query = from i in db.QuestionModules 
       where i.QuestionModuleID == QuestionModuleID 
       select i; 

    QuestionModule o = query.First(); 
    db.QuestionModules.DeleteOnSubmit(o); 
    db.SubmitChanges(); 
} 

Ésta es la excepción consigo:

System.Data.Linq.ChangeConflictException: Row not found or changed. at 
System.Data.Linq.ChangeProcessor.SubmitChanges(ConflictMode 
failureMode) at 
System.Data.Linq.DataContext.SubmitChanges(ConflictMode failureMode) 
at System.Data.Linq.DataContext.SubmitChanges() 

He tenido este problema durante aproximadamente una semana, y no importa lo que haga, es todavía allí, y el registro no se elimina.

¿Alguna idea sobre qué hacer?

Respuesta

15

estoy teniendo el mismo problema, y ​​me encontré con this blog, que, básicamente, establece que LINQ to SQL tiene un problema en su simultaneidad optimista donde: se utilizan

  1. campos de fecha y hora de alta precisión. La solución es establecer UpdateCheck para que nunca para esa columna su archivo DBML
  2. Las columnas GridView que están configuradas como invisibles están accediendo a una propiedad en el objeto de datos (esta segunda razón no tiene sentido, pero parece estar de moda en eso Blog).

No he probado estas soluciones aún, pero volveré a publicar aquí una vez que lo haya hecho.

+0

OK - Acabo de intentar configurar todos los UpdateCheck de la columna Fecha a Nunca ... no me alegra, sigo obteniendo el mismo resultado. – Mark

+0

Tuve el mismo problema con alguna actualización de campo datetime: el cambio del valor de UpdateCheck resolvió el problema. –

+2

+1 Tuve este problema, con un campo 'float' en SQL DB, que había mapeado a un tipo' float' (simple) en C#. Cuando cambié el tipo a 'doble', el problema desapareció. Pero fue esta respuesta tuya la que me avisó, ¡así que MUCHAS GRACIAS! –

66

OK - parece que (en mi caso al menos) la respuesta fue establecer la propiedad UpdateCheck todo de la columna de clave primaria no a Nunca en el archivo DBML. Al hacerlo, se solucionó el problema de "Fila no encontrada o cambiada".

Teniendo en cuenta el rumor de que Microsoft está peleando Linq-To-Sql a favor de Entity Framework, uno se pregunta si este tipo de errores se solucionarán.

+1

Esto puede funcionar, pero ¡caramba, ¿es deseable? ¡No para mí! –

+0

+1 como funcionó. puede alguien arrojar algo de luz sobre las implicaciones de esto. Publicación de blog o de lo contrario sería genial. Gracias. – Kieran

+1

Y si tengo un montón de columnas ... – keni

0

Bajo:

QuestionModule o = query.First(); 

hay que añadir el siguiente comando:

db.QuestionModule.Attach(o); 
1

Asegúrese de que no hay columnas contienen null los valores de la tabla relacionada (es decir, la tabla que actualizarse).

+0

¿Cómo alguien usaría L2S sin ninguna posibilidad de anulación en ningún campo de base de datos? –

+0

Esta solución funcionó para mí. Simplemente cambié todos los valores NULL a algo que debería ser el predeterminado, aunque el db debería soportar NULL en esa columna. –

0

Pude resolver este problema ejecutando databind() en gridview y datasource durante la actualización del panel de actualización.

protected void UpdatePanel1_Load(object sender, EventArgs e) 
    { 
     GridView1.DataBind(); 
     LinqDataSource1.DataBind(); 
    } 

Me actualizo updatepanel cada vez que cambia mi índice de selección y fue capaz de resolver los conflictos.

Espero que esto ayude.

6

Parecía funcionar para mi situación también. Estaba construyendo una fila en memoria, nunca antes presentada, que tenía varias relaciones de clave externa con filas en otras tablas.El InsertOnSubmit parecía funcionar pero un DeleteOnSubmit posterior me estaba dando el error de la fila no encontrada. No estaba completando todos los campos de la fila que envié, así que no sé si eso tuvo algo que ver con eso, pero marcar todas las columnas de clave principal no principal eliminó el mensaje de error.

Un pensamiento más: considero que marcar la política UpdateCheck de una columna como 'Nunca' significa que no se usa como base para la comprobación de concurencia optimista. Esto implicaría que dos usuarios podrían escribir sobre una fila determinada con datos diferentes en cualquier columna y los conflictos no se detectarían ... lo que significa que el último usuario que envíe la fila sobrescribirá los valores del envío de los usuarios anteriores. De varias lecturas en línea, deduje que una solución parcial para esto es usar el método Refresh inmediatamente antes del envío para sincronizar cualquier cambio. Por supuesto, sin bloqueo pesimista en la fila, no hay garantía de que la fila no cambie aún entre el Refresh y el Submit, pero en la mayoría de los escenarios que involucran grandes bases de datos esto sería raro.

Actualización: En otra revisión, creo que he descubierto un escenario que puede estar afectando a los demás, así que pensé que podría compartirlo por si acaso. Resulta que al menos parte del problema que he tenido con SQL LINQ está relacionado con los desencadenantes. Parece que si envía una fila usando SQL LINQ y su DBA tiene desencadenantes diseñados para escribir información en algunas columnas de esa fila, el modelo SQL LINQ determinará "Siempre" de manera predeterminada que la fila ha sido modificada desde la última vez que la escribió . Estaba enviando filas parcialmente pobladas y los activadores de nuestro DBA están rellenando algunas columnas, de modo que cuando intenté modificar más la fila en nuestro código detecté un conflicto de cambio en función de las columnas pobladas por el desencadenante. Estoy investigando ahora la mejor manera de manejar esto, pero cambiar estos campos activados por activadores para usar una política UpdateCheck de 'When Changed' o 'Never' funcionó para mí. Espero eso ayude.

+0

gracias por señalarme en la dirección de la propiedad 'UpdateCheck' ... – ctrlShiftBryan

2

Tenía changeconflictexception similar/"Fila no encontrada o cambiada" al actualizar una fila. Lo resolvió volviendo a agregar las tabbles en el dbml.

12

El problema también podría ser simplemente que la definición DBML de la tabla no es coherente con el estado de la definición de la base de datos. Acabo de eliminar el modelo DBML y lo inserté nuevamente desde la base de datos, y funcionó.

Espero que esto ayude a alguien.

+0

esta es la mejor respuesta –

46

Está obteniendo este error posiblemente porque uno de sus campos tiene algo diferente en el diseñador de Linq To SQL y en la base de datos real.

En mi caso, era porque uno de los campos era anulable en la base de datos y no se podía anular en el diseñador, lo que permitía anular el nombre en el diseñador y resolvía el problema de inmediato.

+3

Missmatch en DBML y la base de datos era mi problema. – Andreas

+0

Correcto, eso creía. Imagine una recomendación para establecer "todas" las columnas a algún valor tiene más votos :( – keni

0

Además, si llama al método de selección para el linqdatasource y establece e.result manualmente, asegúrese de incluir también cualquier valor de clave externa.

Nada más funcionó para mí, pero esto.

0

La forma i fijo que era: En primer lugar puedo actualizar la base de datos, entonces me puse los nuevos valores para la red como

e.Keys["ColumnOne"] ="new value" 
e.Keys["ColumnTwo"] ="new value" 

Todo esto se hizo en el marco del evento GridView_RowUpdating.

0

Solo quería agregar mi escenario para cualquiera que pueda tener este problema.

Utilizamos un T4 personalizado contra nuestro dbml de Linq a SQL. Básicamente, modificamos el get/set original de las propiedades de la cadena para recortar y establecer null de forma automática.

 get { return _OfficiantNameMiddle.GetValueOrNull(); } 
     set 
     { 
      value = value.GetValueOrNull(); 
      if (_OfficiantNameMiddle != value) 
      { 
       _IsDirty = true; 
       OnOfficiantNameMiddleChanging(value); 
       SendPropertyChanging("OfficiantNameMiddle"); 
       _OfficiantNameMiddle = value; 
       SendPropertyChanged("OfficiantNameMiddle"); 
       OnOfficiantNameMiddleChanged(); 
      } 
     } 

datos heredados en nuestra base de datos tuvieron algunos espacios iniciales/arrastran por lo que cualquier comprobación de concurrencia de estas columnas no lograron como resultado una coincidencia (que estaba comparando el valor recortado contra el valor no pertenece al forjado base de datos). Fue realmente fácil hacer un perfil de SQL, tomar el SQL y comenzar a comentar los elementos en la cláusula WHERE hasta que comenzó a devolver una fila durante la comprobación de concurrencia.

Afortunadamente, tenemos un campo LastUpdatedOn en nuestras tablas que se establece automáticamente a través de OnValidate (System.Data.Linq.ChangeAction).

partial void OnValidate(System.Data.Linq.ChangeAction action) 
    { 
     if (action == System.Data.Linq.ChangeAction.Insert) 
     { 
      CreatedBy = CurrentUserID; 
      CreatedOn = DateTime.Now; 
      LastUpdatedBy = CreatedBy; 
      LastUpdatedOn = CreatedOn; 
     } 
     else if (action == System.Data.Linq.ChangeAction.Update) 
     { 
      LastUpdatedBy = CurrentUserID; 
      LastUpdatedOn = DateTime.Now; 
     } 
    } 

Con el fin de evitar el problema, que acaba de establecer la comprobación de concurrencia en Nunca en todas las columnas excepto las columnas de clave principal y la columna LastUpdatedOn. Esto funcionó para nosotros.

0

Tuve un problema similar y aunque eliminar y volver a agregar la tabla/clase DBML ayudó a algunos usuarios, para mí fue un poco diferente ya que estoy usando WCF con entidad separada y un ListView en el cliente.

Si usara el .Attach (entidad) que fallaron - "Fila no se encuentra o se cambia" Pero cuando se utiliza .Attach (entidad, original) funciona cada vez que

public void DeleteTask(Task task) 
    { 
     TwoDooDataContext db = new TwoDooDataContext(); 
     db.Tasks.Attach(task,GetTaskByID(task.ID)); 
     db.Tasks.DeleteOnSubmit(task); 
     db.SubmitChanges(); 
    } 
0

Para mí fue una columna enum (asignada a un varchar) que causó el problema, así que tuve que pasar la verificación de actualización a never.

8

He solucionado este problema, asegurándome de actualizar mi objeto inmediatamente antes de actualizarlo. Lo hago con la opción KeepChanges.

db.Refresh(System.Data.Linq.RefreshMode.KeepChanges, employee); 
+0

Esto parece haber resuelto mis problemas gracias! Otro servicio puede actualizar simultáneamente este registro y tuve que actualizarlo antes de enviarlo. – Smeiff

+0

Esto funcionó como un encanto para yo ... después de horas de luchar! – jharr100

2

El problema que tenía era que tenía un tipo DateTime en el marco .NET, pero nuestra base de datos de campo fue de tipo DateTime2, que es más alto tipo de datos de precisión. Entonces, cuando enviamos cambios, los campos de fecha del objeto frente a la base de datos estaban a solo unos nanosegundos, lo que causaría el error de concurrencia. Esto sucedió cuando migramos a una versión MSSQL más nueva y convirtió nuestros campos DateTime a DateTime2.

Así que en nuestro código donde tuvimos:

Obj.DateUpdated = DateTime.Now() 

lo cambiamos a:

Obj.DateUpdated = DateTime.Parse(DateTime.Now.ToString()) 

A fin de comprobar sus tipos de datos, en especial sus campos de fecha, si se obtiene este error después de realizar una actualización y o migración.

3

Esto es solo un caso de definiciones de columna no coincidentes. Simplemente elimine la tabla del .dbml y vuelva a agregarla. Asegúrese de cambiar auto generate value property = true para las columnas que tienen datos generados automáticamente, como las claves primarias o las columnas de fecha y hora.

0

Como se indica en @dherrin79, esto puede deberse a una variación de precisión entre la base de datos y el código. Para mí, el problema era que la columna de la base de datos se suponía que era decimal (10,2), pero se había creado como decimal (18,0). Esto fue para un campo de dinero, entonces quizás debería haber usado el tipo de columna de dinero.

Así que, guardé una cantidad en dólares, como $ 3.14, pero se eliminó el decimal. Esto dio como resultado el cambio del valor de la base de datos y la no coincidencia del valor en C#.

Espero que esto ayude.