2011-03-11 15 views
7

Digamos que tengo una tabla que rastrea el número de veces que se descargó un archivo, y expongo esa tabla a mi código a través de EF. Cuando el archivo se descargue, quiero actualizar el recuento por uno. En un primer momento, escribí algo como esto:Cómo incrementar de forma segura un contador en Entity Framework

var fileRecord = (from r in context.Files where r.FileId == 3 select r).Single(); 
fileRecord.Count++; 
context.SaveChanges(); 

Pero luego, cuando examiné el SQL real que se genera en estas declaraciones me di cuenta de que la incrementación no está sucediendo en el lado DB pero en cambio en mi memoria. Entonces mi programa lee el valor del contador en la base de datos (digamos 2003), realiza el cálculo (el nuevo valor es 2004) y luego actualiza explícitamente la fila con el nuevo valor de Conteo de 2004. Claramente esto no es seguro desde una perspectiva de concurrencia .

que estaba esperando la consulta podría terminar buscando su lugar como:

UPDATE Files SET Count = Count + 1 WHERE FileId=3 

¿Puede alguien sugerir cómo podría lograr esto? Preferiría no bloquear la fila antes de la lectura y luego desbloquearla después de la actualización porque tengo miedo de bloquear las lecturas de otros usuarios (a menos que haya alguna forma de bloquear una fila solo para escrituras pero no bloquee las lecturas).

También miré haciendo un comando Entity SQL pero parece que Entity SQL no admite actualizaciones.

Gracias

Respuesta

1

Usted es sin duda la bienvenida a llamar a un procedimiento almacenado con EF. Escriba un sproc con el SQL que muestra y luego cree una función de importación en su modelo EF mapeado a dicho sproc.

0

Tendrá que hacer algunos bloqueos para que esto funcione. Pero puedes minimizar la cantidad de bloqueo.

Cuando lee el recuento y desea actualizarlo, debe bloquearlo, esto se puede hacer colocando la lectura y la actualización dentro del alcance de una transacción. Esto lo protegerá de las condiciones de carrera.

Cuando lea el valor y solo quiera leerlo, puede hacerlo con un nivel de aislamiento de transacción de ReadUncommited, esta lectura no estará bloqueada por el bloqueo de lectura/escritura anterior.

Cuestiones relacionadas