2011-06-21 12 views
11

Nota al principio, mi pregunta resulta ser similar a la pregunta 1668172 de SO.Cómo diseñar la fecha de nacimiento en DB y ORM para la combinación de partes con fecha desconocida y conocida


Ésta es una cuestión de diseño que seguramente debe haber surgido de otros antes, pero no pude encontrar una respuesta que se ajusta a mi situación. Quiero grabar la fecha de nacimiento en mi solicitud, con varios 'niveles' de información:

  • NULL valor, es decir DoB es desconocido
  • 1950-??-?? Sólo se conoce el valor del año fecha de nacimiento, la fecha/mes aren 't
  • ????-11-23 sólo un mes, el día, o una combinación de los dos, pero sin un año
  • 1950-11-23 completa DoB se conoce

las tecnologías estoy USI ng para mi aplicación son los siguientes:

  • Asp.NET 4 (C#), probablemente con MVC
  • alguna solución ORM, probablemente LINQ to SQL o NHibernate de
  • MSSQL Server 2008, al principio sólo Express Edition

posibilidades de bits de SQL que pasó por mi mente hasta el momento:

  • 1) Utilice una columna anulable por ejemplo varchar 1950-11-23, y reemplazar unkowns con 'X's, p. XXXX-11-23 o 1950-XX-XX
  • 2) Utilice tres columnas nullable int p. Ej. 1950, 11 y 23
  • 3) Utilizar una columna INT para el año, además de una columna de fecha y hora para la plena conocida dobs

Para el extremo C# de este problema Simplemente llegué a estas dos opciones:

  • A) Utilice una propiedad de cadena para representar DoB, convirtiendo solo para fines de visualización.
  • B) Utilice una costumbre (?) Estructura o clase de DoB con tres enteros con valores nulos
  • c) el uso de un DateTime anulable junto a un número entero anulable para el año

Las soluciones parecen formar pares emparejados en 1A, 2B o 3C. Por supuesto que 1A no es una buena solución, pero establece una línea de base.

Todos los consejos y enlaces son muy apreciados. Bueno, si están relacionados, de todos modos :)


Editar, acerca de las respuestas: he marcado una respuesta como aceptada, porque creo que me va a funcionar.Sin embargo, vale la pena mirar las otras respuestas, si ha tropezado aquí con la misma pregunta.

+1

+1. Interesante pregunta. – RichardOD

+0

He encontrado otra pregunta que me hizo una pregunta similar: http://stackoverflow.com/questions/1668172/handling-partial-incomplete-dates-in-net –

Respuesta

3

Side El SQL

Mi última idea sobre este tema es el uso de un rango de fechas que son inciertos o pueden tener diferente especificidad.Dados dos columnas:

DobFromDate (inclusive) 
DobToDate (exclusive) 

Así es como funcionaría con sus escenarios:

Specificity DobFromDate DobToDate 
----------- ----------- ---------- 
YMD   2006-05-05 2006-05-06 
YM    2006-05-01 2006-06-01 
Y    2006-01-01 2007-01-01 
Unknown  0000-01-01 9999-12-31 
-> MD, M, D not supported with this scheme 

Tenga en cuenta que no hay razón para que esto no se podría llevar hasta el final a hora, minuto, segundo, milisegundo, y así.

A continuación, cuando se consulta para las personas nacidas en un día específico:

DECLARE @BornOnDay date = '2006-05-16' 

-- Include lower specificity: 
SELECT * 
FROM TheTable 
WHERE 
    DobFromDate <= @BornOnDay 
    AND @BornOnDay < DobToDate; 

-- Exclude lower specificity: 
SELECT * 
FROM TheTable 
WHERE 
    DobFromDate = @BornOnDay 
    AND DobToDate = DateAdd(Day, 1, @BornOnDay); 

Esto me tiene la mejor combinación de capacidad de mantenimiento, facilidad de uso y potencia expresiva. No manejará la pérdida de precisión en los valores más significativos (por ejemplo, conoce el mes y el día, pero no el año), pero si se puede solucionar, entonces creo que es un ganador.

Si alguna vez va a consultar por fecha, entonces, en general, las mejores soluciones (en mi opinión) serán aquellas que conservan los elementos como fechas en el servidor de alguna manera.

Además, tenga en cuenta que si usted está buscando un intervalo de fechas en lugar de un solo día, con mi solución que todavía sólo necesita dos condiciones, no cuatro:

DECLARE 
    @FromBornOnDay date = '2006-05-16', 
    @ToBornOnDay date = '2006-05-23'; 

-- Include lower specificity: 
SELECT * 
FROM TheTable 
WHERE 
    DobFromDate < @ToBornOnDay 
    AND @FromBornOnDay < DobToDate; 

El C# lateral

Usaría una clase personalizada con todos los métodos necesarios para hacer las comparaciones de fechas y fechas apropiadas en él. Conoces los requisitos del negocio sobre cómo usarás las fechas que son desconocidas, y pueden codificar la lógica dentro de la clase. Si necesita algo antes de cierta fecha, ¿usará solo artículos conocidos o desconocidos? ¿Qué devolverá ToString()? Estas son cosas que, en mi opinión, se resuelven mejor con una clase.

+0

Solución interesante. Nunca pensé en esto antes. ¡Archivaré esto para un uso posterior en proyectos que necesitan establecer gradualmente la precisión de la fecha! –

+0

Guau, gran sugerencia. Con la (mencionada) excepción de las situaciones en las que solo se conocen MD, D, M, esto me permitiría representar las cosas bastante bien en el lado de DB, y como mencionas, el lado de C# puede agregarlo a su gusto. Voy a tener una noche de sueño sobre esto primero, pero muy bien puede ir con esta solución ya que la única excepción coincide con el único escenario que es simplemente "agradable" tener :) Tx @ErikE – Jeroen

+0

Pensé un poco más sobre esta solución. Se realizaron algunas consultas sobre mis datos, lo que demuestra que rara vez tengo un mes o un día, pero no el año. Así que me estoy salteando el requisito de "es bueno tener" y probaré esta solución. Thx nuevamente @ErikE, lo marcó como la respuesta. – Jeroen

2

Me gusta la idea de 3 columnas con nulos y una estructura de 3 nullable int en C#.

lo hace tomar un poco de esfuerzo en el manejo db pero se puede evitar que sea interpretado en torno a cadenas y también se puede consultar con SQL directamente por año o año y mes y así sucesivamente ...

+0

Mi primer intento fue precisamente este, es muy "honesto" sobre la información tienes o no tienes Sin embargo, la respuesta de @ ErikE es un gran competidor ya que es "honesto" sobre la información también :). Decisiones, decisiones ... De cualquier manera: ¡gracias por su respuesta! – Jeroen

1

Problema interesante ...

Me gusta la solución 2B sobre la solución 3C porque con 3C no se normalizaría ... cuando actualizas una de las entradas, también debes actualizar DateTime o no estarás sincronizado.

Sin embargo, cuando lea los datos en su C# end, tendría una propiedad que enrollaría todas las entradas en una cadena formateada como la que tiene en la solución 1 para que pueda mostrarse fácilmente.

Tengo curiosidad por saber qué tipo de informes necesitará hacer sobre estos datos ... o si simplemente los almacenará y los recuperará de la base de datos.

1

No me preocuparía mucho acerca de cómo almacenar la fecha, aún así almacenaría la fecha dentro de un campo de fecha y hora, PERO, si sé si alguna parte de la fecha no estaba completa, tendría banderas para cada sección de la fecha que no es válido, por lo que el esquema sería:

DBODate como fecha DayIsSet como Bit Bit MonthIsSet como YearIsSet como mapa de bits.

De esta manera todavía puede implementar todas las comparaciones de fechas válidas, y aún así saber la precisión de la fecha en que está trabajando. (En cuanto a la fecha, siempre elegiría la porción faltante como el mínimo de ese valor: el valor predeterminado de IE Month es enero, el día es el primero, el año es 1900 o algo así).

+0

La razón por la que trataría de mantenerme cerca del tipo de datos de fecha y hora es porque obtiene automáticamente todas las funciones correctas de verificación de fechas, como el 29 de febrero, cuántos días en el mes correspondiente, etc. –

+0

@ NB- Original tuve el mismo pensamiento que DB. La pregunta es cuando no sabes la parte del año: ¿cómo sabes que el 29 de febrero es válido? También necesitaría establecer un año bisiesto predeterminado para acomodar el 29 de febrero en el caso en que el año sea desconocido ... – RichardOD

+0

@RichardOD muy buen punto. Cualquiera de estas soluciones requerirá alguna lógica personalizada que gire en torno a la validación de la fecha. ¡No tengo envidia de tu problema! Sigo pensando que la mejor manera de hacerlo sería tener valores predeterminados para cada uno de los campos de fecha. Curiosamente, el año 0004 fue realmente un año bisiesto, que es manejado por el tipo de datos DateTime2 dentro de SQL. –

2

Hagas lo que hagas va a ser complicado DB sabio. Para los consumidores de este tipo de fechas, escribiría una clase/estructura especial que encapsula qué tipo de fecha es (probablemente lo llamaría algo así como PartialDate), para que sea más fácil de tratar para los consumidores, al igual que Martin Fowler aboga por un Money Class.

Si expone un DateTime directamente en C#, esto podría generar confusión si tuviera una "fecha" de ???? - 11-23 y deseara determinar si el cliente tenía más de 18 años, por ejemplo, ¿cómo lo haría? predeterminado la fecha, cómo sabría el consumidor que parte de la fecha no era válida, etc. ...

La ventaja añadida de tener un PartialDate es que permitirá que otras personas que lean el código se den cuenta rápidamente de que no son normales, ¡complete las fechas y no debe ser tratado como tal!

Editar

Pensando en el concepto de datos parcial un poco más, me decidieron a Google. Descubrí que existe el concepto de Partial on Joda time y interesting PDF on the topic, que puede o no serle útil.

+0

Gracias por la respuesta, y los enlaces @RichardOD, voy a echar un vistazo a los de mañana. – Jeroen

1

Obviamente, todas las soluciones mencionadas anteriormente representan algún tipo de compromiso.

Por lo tanto, recomendaría pensar cuidadosamente cuál de los 'niveles' es el más probable y optimizarlo para eso. Luego, busque el manejo de excepciones adecuado para los otros casos excepcionales.

No sé si los informes son un problema para usted en este momento o pueden ser posteriores, pero podría considerarlos como una tercera dimensión aparte de los problemas de DB/C#.

+0

Wups, ni siquiera había pensado en informar aún: ¡O, puede que tenga que considerar eso también cuando decida qué solución elegir! – Jeroen

Cuestiones relacionadas