2010-01-04 8 views
18

Pregunta: ¿Cuáles son algunas otras estrategias para evitar números mágicos o valores codificados en sus scripts SQL o procedimientos almacenados?SQL: evitando la codificación rígida o números mágicos

Considere un procedimiento almacenado cuyo trabajo es verificar/actualizar un valor de un registro basado en su StatusID o alguna otra tabla de búsqueda FK o rango de valores.

considere una tabla Status, donde la identificación es más importante, ya que es una FK a otra tabla:

alt text

Los scripts SQL que deben ser evitados son algo así como:

DECLARE @ACKNOWLEDGED tinyint 

SELECT @ACKNOWLEDGED = 3 --hardcoded BAD 

UPDATE SomeTable 
SET  CurrentStatusID = @ACKNOWLEDGED 
WHERE ID = @SomeID 

El problema aquí es que esto no es portátil y depende explícitamente del valor codificado. Existen defectos sutiles cuando se implementa esto en otro entorno con inserciones de identidad desactivadas.

también tratando de evitar una SELECT basado en la descripción de texto/nombre del estado:

UPDATE SomeTable 
SET  CurrentStatusID = (SELECT ID FROM [Status] WHERE [Name] = 'Acknowledged') 
WHERE ID = @SomeID 

Pregunta: ¿Cuáles son algunas otras estrategias sobre cómo evitar los números mágicos o valores codificados de forma rígida en sus secuencias de comandos SQL o procedimientos almacenados?

Algunas otras ideas sobre cómo lograr esto:

  • añadir una nueva columna bit (nombrado como 'IsAcknowledged') y conjuntos de reglas, donde no puede haber sólo una fila con un valor de 1. Esto ayudaría en la búsqueda de la fila única: SELECT ID FROM [Status] WHERE [IsAcknowledged] = 1)

Respuesta

7

En algún nivel, habrá una cierta "codificación dura" de valores. La idea de la eliminación de ellos proviene de dos partes:

  1. Hacer que el código sea más legible (es decir, diciendo 'Acknowledged' en lugar de 3 es probablemente va a hacer que sus intenciones más obvio para el lector
  2. Hacer el código. más dinámico, donde una función puede tomar un parámetro en lugar de varias funciones que no lo hacen (esto es una simplificación, obviamente, pero el significado debe ser bastante evidente por sí mismo de todos modos)

Haciendo bit columnas para varios stat es puede ser una buena o mala idea; realmente solo depende de los datos. Si los datos pasan por varias "etapas" (Recibido, Reconocido, En revisión, Rechazado, Aceptado, Respondido, etc.), entonces ese enfoque rápidamente se escapa de la viabilidad (por no mencionar el irritante proceso de tener que garantizar que solo uno) de las columnas se establece en 1 en cualquier momento dado). Si, por otro lado, el estado es tan simple como usted describe, hacerlo puede hacer que el código sea más legible y los índices funcionen mejor.

El mayor no-no en los valores de codificación difíciles es valores de codificación rígida que hacen referencia a otras entidades (en otras palabras, codificación dura de la clave primaria para un objeto correspondiente). La cadena 'Acknowledged 'sigue siendo un valor codificado, es más transparente en su significado y no es una referencia a otra cosa. Para mí, se reduce a esto: si puede (razonablemente) buscarlo, hágalo. Si no puede (o si algo lo convierte en una tarea irrazonable, ya sea desde el punto de vista del rendimiento o la mantenibilidad), codifíquelo. Al usar esto, puede buscar el valor de 3 usando Acknowledged; no puede buscar Acknowledged desde cualquier otra cosa.

0

Bueno, para empezar, la lógica de negocios probablemente se debe evitar en la capa de almacenamiento.

Como esto no se puede evitar cuando se utiliza una base de datos como SQL Server, donde existe una gran cantidad de la BL lata en el DB, creo que es posible que en vez volver a usar ID de cadena en lugar de automático ID.

Esto será mucho más fácil de gestionar que los auto identificadores, y se puede manejar de mejor manera, incluso cuando se utiliza la capa de aplicación real.

Por ejemplo usando un enfoque .Net, muchos de los los ID de cadena única se puede almacenar en cualquier lugar de los archivos de configuración , a las búsquedas adicionales utilizando el DB seleccionado, archivos XML.

1

Si su caso es tan simple como el anterior, donde un bit IsAcknowledged funcionaría, iría por esa ruta. Nunca he tenido ningún problema con eso. Si tiene escenarios más complicados, donde terminaría con una docena de campos de bits, no veo ningún problema al usar un "número mágico", siempre y cuando tenga el control total sobre él.Si le preocupa que la columna de identidad no se correlacione correctamente cuando transfiere la base de datos a la base de datos, podría crear otra columna única (que no sea de identidad) con sus valores de ID, entero o guid o cualquier otra cosa que sea útil.

1

Si la entidad 'Estado', que forma parte de su modelo de dominio, tiene valores predefinidos, algunos de los cuales deben ser manejados de manera específica por procedimientos almacenados, entonces está perfectamente bien codificar referencias a esos valores específicos en tu código El problema aquí es que está confundiendo lo que potencialmente es una clave abstracta (columna de identidad de ID) para un valor que tiene un significado en su modelo de dominio. Si bien es correcto mantener su columna de identidad de ID, debe usar un atributo significativo de la entidad de su dominio al referirse a ella en el código, este puede ser el nombre, o puede ser un alias numérico. Pero este alias numérico se debe definir en su modelo de dominio, p. 3 significa 'Reconocido', y no debe confundirse con el campo ID abstracto que, como dices, puede ser una columna de identidad en algunas de las instancias de tu base de datos.

3

Así es como yo lo haría. (Debido a que es mucho más rápido que tu ejemplo)

UPDATE SomeTable 
SET CurrentStatusID = [Status].[ID] 
FROM SomeTable 
RIGHT JOIN [Status] ON [Name] = 'Acknowledged' 
WHERE SomeTable.[ID] = @SomeID 

(no probado podría tener errores tipográficos)

+0

Lo hago, excepto que mis tablas de búsqueda tienen una columna StatusText que se usa para mostrar, y una columna UniqueName que se usa para valores codificados. Esto permite que las solicitudes de los usuarios para cambiar la etiqueta que se muestra se puedan realizar sin afectar al UniqueName al que hacen referencia los valores codificados. – AaronLS

+0

La única razón por la que tengo miedo de usar esta técnica es que no sé cuánto impacto tendrá a largo plazo en el rendimiento, hacer consultas en una columna de cadena en lugar de enteros. – AaronLS

+0

Ok esto fue hace 7 meses. Como recuerdo, mi punto fue utilizar una unión en lugar de una sub consulta, que será más rápida. No tengo idea de dónde sacas la idea de que estoy consultando una cadena en lugar de un número entero. Esto funcionará mejor que el ejemplo en la pregunta, ya que es una combinación y no una subconsulta. – Hogan

3

No confiar en la identidad para todas sus identificaciones. Cuando tiene una tabla de búsqueda que va a tener menos de 50 filas, por ejemplo, es perfectamente razonable definir esas búsquedas como identificadores específicos o usar un código validado para ellas. En cualquier caso, la "codificación difícil" ya no es un problema.

9

poco me di cuenta de que los números mágicos pueden ser implemented by views:

CREATE VIEW V_Execution_State AS 
SELECT 10 AS Pending, 20 AS Running, 30 AS Done 

DECLARE @state INT 
SELECT @state = Pending FROM V_Execution_State 
+0

Bastante buena idea. Como tener una enumeración en SQL. ¡Gracias! – Joey

+2

Sin embargo, un problema con este enfoque es que si decide agregar otro estado de ejecución, ahora no solo debe cambiar la vista, sino que también se verá afectado cualquier código que dependa de una estructura estática. –

+0

Me pregunto si hay alguna forma en que pueda usar un Pivot para implementar una vista que cambie automáticamente a medida que la tabla de búsqueda tenga adiciones. – AaronLS

12

Para situaciones como su tabla de estado, puedo crear lo que llamo conjuntos de datos "estáticos". Estas tablas contienen datos que

  • está ajustado y definido sobre la creación,
  • Nunca cambie alguna vez, y
  • es siempre la misma, de una instancia de base de datos a la instancia de base de datos, con no excepciones

Es decir, al mismo tiempo que crea la tabla, la rellena también, utilizando una secuencia de comandos para garantizar que los valores sean siempre los mismos. A partir de entonces, sin importar dónde ni cuándo esté la base de datos, conocerá cuáles son los valores, y puede codificar de manera adecuada y adecuada. (Nunca utilizaría claves sustitutivas ni la propiedad de la columna de identidad en estas situaciones)

No tiene que usar números, puede usar cadenas, o binarios o fechas, o lo que sea más simple, más fácil y más apropiado . (Cuando puedo, uso cadenas de char, y no varchars, como "RCVD", "DLVR", ACKN ", etc., son valores codificados más fáciles que, por ejemplo, 0, 2 y 3.)

Este sistema funciona para conjuntos de valores no extensibles.Si estos valores se pueden modificar (de modo que 0 ya no significa "acuse de recibo", entonces tiene un problema de acceso de seguridad. Si tiene un sistema donde pueden agregado por los usuarios, entonces usted tiene un problema de diseño diferente y difícil de resolver

+1

De acuerdo. En este tipo de casos, creo una columna StatusCd de algún tipo cuyo valor nunca cambia. De esta manera puede atravesar los sistemas, pero puede ser comprensible con sólo mirar el valor del código. – Yoav

+0

¿Hace que este valor único legible para humanos sea la clave principal de la tabla? ¿O todavía usa un número entero como la clave principal? – AaronLS

+0

Uso el valor único (esencialmente, la clave natrual); agregar una clave sustituta a dicha tabla es completamente inútil. –

3

una idea:.

CREATE FUNC dbo.CONST_ACKNOWLEDGED() 
RETURNS tinyint 
AS 
BEGIN 
    RETURN 3 
END 

sin embargo, sólo tiene sentido si no tiene autonumber, en mi humilde opinión

0

Imagínese

table dbo.Status 
(
    Id int PK 
    ,Description varchar 
) 
values 
1, Received 
2, Acknowledged 
3, Under Review 
etc 

lo tanto, sólo

declare @StatusReceived int = 1 
declare @StatusAcknowledged int = 2 
declare @StatusUnderReview = 3 
etc 

Como otros mencionar, esto supone que la identidad no se ha establecido.

Yo también solía unirme en las tablas de búsqueda, pero esto hace que el SELECTO sea más corto y fácil de leer.

Este enfoque se presta a la automatización, por lo que genero una tabla completa en una consulta separada, luego copio los elementos que requiero (no todos).

Cuestiones relacionadas