2009-02-16 32 views
39

Casi todos los programadores lo hicieron una vez en su vida: establecer un indicador si el valor de una variable cambiaba. Siempre hay un montón de propiedades y desea realizar un seguimiento si algo ha cambiadoDiferentes formas de implementar la funcionalidad 'dirty'-flag

  1. en cualquier propiedad
  2. en una propiedad específica
  3. o en algún conjunto de propiedades

me interesa de diferentes maneras para implementar la funcionalidad "indicador sucio" para las situaciones anteriores, además de la bandera sucia amplia de objeto estándar que se actualiza en cada cambio de propiedad. Debe haber algo mejor que poner "dirty = true" en cada setter: se ve feo y es un trabajo tedioso.

Respuesta

24

Para mi DAO Guardo una copia de los valores originales recuperados de la base de datos. Cuando lo envío para actualizarlo, simplemente comparo los valores originales con el actual. Cuesta un poco en el procesamiento, pero es mucho mejor que tener una bandera sucia por propiedad.

EDITAR para justificar aún más no tener una bandera sucia: si la propiedad vuelve a su valor original, no hay manera de reflejar eso, la bandera sucia continúa sucia porque se perdió el valor original.

+1

¿Por qué es mucho mejor que tener una bandera sucia por propiedad? Guarda más datos en la memoria. No digo que lo que estás haciendo no sea mejor, pero no lo has justificado. –

+4

Si realmente lo piensas, no necesariamente guardo muchos más datos en la memoria porque no necesito llevar un indicador de estado por propiedad. No necesito preocuparme por volver a configurar "sin cambios" si el valor vuelve al original. También una bandera sucia NO me permitiría regresar. –

+1

Estoy haciendo lo mismo con mis DAO. ¡Es bueno ser confirmado! – MicSim

4

Pondría changed() en cada setter, es decir, llamar a un método privado en lugar de simplemente cambiar un indicador. El método puede establecer una bandera o hacer el procesamiento que sea necesario, p. también podría notificar a cualquier observador.

6

Si está configurando una bandera "sucia", tenga en cuenta que mantiene el estado. En algún momento, debe realizar una acción basada en ese estado; de lo contrario, no necesitaría mantener la bandera. Entonces, la pregunta es: ¿hay otra forma de activar la acción necesaria? ¿Enviando mensajes de algún tipo? ¿Quién consume el estado "sucio" y toma medidas, y existe una interfaz más limpia para esa notificación?

10

Solía ​​tener una clase base de Entidad, proporcionando lógica sucia/eliminada.

Al escribir entidad de subclases, que podría hacer algo como:

public string Name 
{ 
    get { return name; } 
    set { setValue("Name", value); } 
} 

Esto funciona bien, pero tiene la enfermedad 'feo cadena' ...

Hoy en día se puede utilizar para excluir las expresiones Lambda las cadenas:

set {setValue(x => x.Name, value);} 

O, y yo creo que esta es la mejor solución, se puede usar AOP:

https://www.postsharp.net/

De esta manera, puede definir acciones por Atributos. Usted crea un atributo y especifica que cuando el usuario cambia la propiedad asociada, la entidad se ensucia.

Además, puede mantener una lista de propiedades en su clase (Entidad base) que recordará las propiedades modificadas y accederá a esa lista desde su Código AOP.

+0

Esto suena como el mejor método IMO –

+1

votando por la sugerencia de AOP, pero el método inicial "setValue" me hace temblar :) – msulis

8

He creado una clase llamada DirtyValue<T> que tiene un valor original y un valor actual.En su primer uso, establece tanto el valor original como el valor actual. Las llamadas sucesivas solo configuran el valor actual.

Puede ver si ha cambiado comparando los dos, con una propiedad de bool de solo lectura llamada IsDirty(). Usando esta técnica también puede obtener acceso al valor original también.

+0

¿Las propiedades del tipo DirtyValue o simplemente tiene campos de tipo DirtyValue y luego simplemente exponer Valor actual a través de la propiedad? Todavía parece un trabajo duro, aunque es bueno que no tengas que configurar es Sucio = verdadero; en todas partes –

+0

Sí, son valores, no propiedades. Los expongo a través de accesorios si es necesario. Quiero asegurarme de que, independientemente de cómo estén configurados (con una propiedad o directamente), lo sucio todavía funciona. –

+0

erm, campos quiero decir, no valores! :) –

5

En algunas situaciones con una tarea de escritor de datos y una tarea de lector independiente, he asignado a cada tarea una variable updateCount. El productor incrementa su cuenta cada vez que escribe. Cada vez que el lector se despierta y encuentra que su conteo es menor que el recuento del productor, realiza una actualización con los valores actuales. Necesita un poco de manejo especial para el desbordamiento de contador, pero esto es bastante simple de implementar.

He utilizado con éxito esta técnica en simulaciones, donde el productor es el bucle de física y el lector es la pantalla en 3D.

2

Una alternativa interesante al enfoque explícito dirty=true, aunque probablemente sea exagerado para la mayoría de las situaciones y a menudo no aplicable, sería usar páginas de guardia. Configure la página de memoria como de solo lectura (por ejemplo, con VirtualProtect() en Windows) y capte la señal/excepción cuando el programa intente escribir en la página. Haga un registro de que la página ha sido modificada, luego cambie los indicadores de protección de la página para que se pueda escribir y reanude la ejecución.

Esta es la técnica generalmente empleada por los sistemas operativos para determinar si una página debe escribirse en el archivo de intercambio antes de que se expulse de la RAM.

-1

Es posible que desee considerar anular el código gethashcode e igualar los métodos de los objetos de su dominio y almacenar los códigos hash originales en una tabla hash por clave de objeto. A continuación, cree un proceso que tome un objeto, encuentre su clave en la tabla hash y compare los valores hash.

  • If hash same, no change. (no enviar al repositorio o base de datos)
  • if hash diferente, el objeto tiene cambios. (actualización)
  • Si no se encuentra la clave, el objeto es nuevo. (insertar)
  • No estoy seguro de cómo determinar si se debe eliminar un objeto que no sea la eliminación del proceso a petición y no utilizar el seguimiento de hashcode para ellos.

No he intentado esto y una hashtable puede no ser la mejor manera de rastrear las claves de objeto/valores hash. Ahorraría mem al rastrear solo códigos y claves hash. No estoy 100% seguro, pero creo que algunos de los orm pueden usar este método en su contexto de datos/seguimiento de objetos.

+3

Existe un problema con este enfoque: "Hash same" no siempre significa "no change", podría significar "change", pero los valores de hash colisionaron. –

+0

-1 ver http://blogs.msdn.com/b/ericlippert/archive/2011/02/28/guidelines-and-rules-for-gethashcode.aspx – reggaeguitar

Cuestiones relacionadas