2009-03-19 12 views
15

Estoy en un mundo de dolor con este, y agradecería que alguien pudiera ayudar.ChangeConflictException en la actualización de Linq a Sql

Tengo un DataContext adjunto a una sola tabla de prueba en una base de datos. La tabla de prueba es el siguiente:

CREATE TABLE [dbo].[LinqTests](
    [ID] [bigint] IDENTITY(1,1) NOT NULL, 
    [StringValue] [varchar](255) NOT NULL, 
    [DateTimeValue] [datetime] NOT NULL, 
    [BooleanValue] [bit] NOT NULL, 
    CONSTRAINT [PK_LinqTests] PRIMARY KEY CLUSTERED ([ID] ASC)) 
ON [PRIMARY] 

El uso de LINQ, puedo añadir, recuperar y borrar registros de la tabla de prueba, pero no puedo actualizar una fila - para una actualización, siempre me dan una ChangeConflictException con un vacío Colección ObjectChangeConflict.MemberConflicts. Aquí está el código usado:

var dataContext = new UniversityDataContext(); 
dataContext.Log = Console.Out; 

for (int i = 1; i <= 1; i++) { 
    var linqTest = dataContext.LinqTests.Where(l => (l.ID == i)).FirstOrDefault(); 

    if (null != linqTest) { 
     linqTest.StringValue += " I've been updated."; 
    } 
    else { 
     linqTest = new LinqTest { 
      BooleanValue = false, 
      DateTimeValue = DateTime.UtcNow, 
      StringValue = "I am in loop " + i + "." 
     }; 
     dataContext.LinqTests.InsertOnSubmit(linqTest); 
    } 
} 

try { 
    dataContext.SubmitChanges(ConflictMode.ContinueOnConflict); 
} 
catch (ChangeConflictException exception) { 
    Console.WriteLine("Optimistic concurrency error."); 
    Console.WriteLine(exception.Message); 
    Console.ReadLine(); 
} 

Console.ReadLine(); 

Aquí está la salida de registro para una actualización realizada a través del DataContext.

UPDATE [dbo].[LinqTests] 
SET [StringValue] = @p3 
WHERE ([ID] = @p0) AND ([StringValue] = @p1) AND ([DateTimeValue] = @p2) AND (NOT ([BooleanValue] = 1)) 
-- @p0: Input BigInt (Size = 0; Prec = 0; Scale = 0) [1] 
-- @p1: Input VarChar (Size = 15; Prec = 0; Scale = 0) [I am in loop 1.] 
-- @p2: Input DateTime (Size = 0; Prec = 0; Scale = 0) [3/19/2009 7:54:26 PM] 
-- @p3: Input VarChar (Size = 34; Prec = 0; Scale = 0) [I am in loop 1. I've been updated.] 
-- Context: SqlProvider(Sql2000) Model: AttributedMetaModel Build: 3.5.30729.1 

Estoy ejecutando esta consulta en un SQL Server 2000 en clúster (8.0.2039). No puedo, por mi vida, descubrir qué está pasando aquí. Ejecutar una consulta de ACTUALIZACIÓN similar contra el DB parece funcionar bien.

Gracias de antemano por cualquier ayuda.

+0

favor enviar el código que está utilizando para la actualización – eglasius

Respuesta

28

Finalmente descubrí lo que estaba sucediendo con esto. Aparentemente, la opción "no contar" se activó para este servidor.

En Microsoft SQL Server Management Studio 2005:

  1. Haga clic derecho en el servidor y haga clic en Propiedades
  2. En la parte izquierda de la ventana Propiedades del servidor, seleccione los Conexiones página
  3. En Opciones de conexión predeterminadas, asegúrese de que "no count" no esté seleccionado.

Aparentemente, LINQ to SQL usa @@ ROWCOUNT después de las actualizaciones para emitir una comprobación automatizada de simultaneidad optimista. Por supuesto, si "no count" está activado para todo el servidor, @@ ROWCOUNT siempre devuelve cero, y LINQ to SQL arroja una ConcurrencyException después de emitir actualizaciones a la base de datos.

Este no es el único comportamiento de actualización que utiliza LINQ to SQL. LINQ to SQL no realiza una comprobación de concurrencia optimista automatizada con @@ ROWCOUNT si tiene una columna TIMESTAMP en su tabla.

+6

Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. Gracias. thx.ty –

+0

Voy a tener que ir de nuevo por GRACIAS GRACIAS GRACIAS! – SqlSandwiches

+2

Una buena investigación, solo para corregir un poco, Linq to SQL podría hacer uso del valor 'conteo' devuelto por el servidor, pero no está usando @@ ROWCOUNT porque "la función @@ ROWCOUNT se actualiza incluso cuando SET NOCOUNT está activado." [ver aquí] (http://msdn.microsoft.com/en-us/library/aa259204 (v = sql.80) .aspx) – Tomek

1

¿Es posible que alguno de los datos para la fila haya cambiado entre cuando se recuperó y se intentó la actualización? Porque LINQ-> SQL tiene una comprobación de concurrencia automática que validará el contenido del objeto contra los valores almacenados actualmente (como se ve en la consulta generada). Si es posible que alguno de los campos haya cambiado para la fila en el DB frente al objeto que LINQ está rastreando, la actualización fallará. Si esto está ocurriendo y por buenas razones y sabe qué campos, puede actualizar el objeto en el diseñador de DBML; seleccione el campo en la causa y cambie la propiedad "Actualizar verificación" a "Nunca".

+2

entiendo LINQ a la estrategia de concurrencia optimista de SQL al actualizar filas, pero es absolutamente imposible para cualquiera de estas filas en la tabla de prueba para haber sido modificado. Curiosamente, cuando agrego una columna TIMESTAMP a la tabla, no obtengo ninguna ConflictChangeExceptions. –

1

Tuve el mismo problema con SQL Server 2008 y la opción de conexión no countya se convirtió en.

En lugar de cambiar la propiedad Update Check a Nunca (como sugiere Quintin), me puse a whenChanged y el problema se solucionó.