variable uso type mssql formato fecha cast web-services datetime time transactions

web-services - type - uso de datetime en sql



Uso constante del valor de "ahora" en toda la transacción (4)

El código parece razonable.

Desventaja: la vida útil más probable del objeto será controlada por el contenedor DI y, por lo tanto, el usuario del proveedor no puede estar seguro de que siempre esté configurado correctamente (por invocación y no más tiempo de vida como app / singleton).

Si tiene un tipo que representa "transacción", puede ser mejor poner el tiempo de "Inicio" allí.

Estoy buscando pautas para usar un valor consistente de la fecha y hora actual a lo largo de una transacción.

Por transacción me refiero a un método de servicio de aplicación; estos métodos generalmente ejecutan una sola transacción SQL, al menos en mis aplicaciones.

Contexto ambiental

Un enfoque descrito en las respuestas a esta pregunta es poner la fecha actual en un contexto ambiental, por ejemplo, DateTimeProvider , y usar eso en lugar de DateTime.UtcNow todas partes.

Sin embargo, el propósito de este enfoque es solo hacer que el diseño sea verificable por unidades, mientras que también quiero evitar errores causados ​​por consultas múltiples innecesarias en DateTime.UtcNow , un ejemplo de esto es:

// In an entity constructor: this.CreatedAt = DateTime.UtcNow; this.ModifiedAt = DateTime.UtcNow;

Este código crea una entidad con fechas creadas y modificadas ligeramente diferentes, mientras que uno espera que estas propiedades sean iguales justo después de la creación de la entidad.

Además, un contexto ambiental es difícil de implementar correctamente en una aplicación web, por lo que se me ocurre un enfoque alternativo:

Método de inyección + DeterministicTimeProvider

  • La clase DeterministicTimeProvider se registra como una instancia "instancia por alcance de por vida" AKA "por solicitud HTTP en una dependencia de aplicación web".
  • Es un constructor inyectado a un servicio de aplicación y se pasa a los constructores y métodos de las entidades.
  • El método IDateTimeProvider.UtcNow se usa en lugar del habitual DateTime.UtcNow / DateTimeOffset.UtcNow todas partes para obtener la fecha y hora actuales.

Aquí está la implementación:

/// <summary> /// Provides the current date and time. /// The provided value is fixed when it is requested for the first time. /// </summary> public class DeterministicTimeProvider: IDateTimeProvider { private readonly Lazy<DateTimeOffset> _lazyUtcNow = new Lazy<DateTimeOffset>(() => DateTimeOffset.UtcNow); /// <summary> /// Gets the current date and time in the UTC time zone. /// </summary> public DateTimeOffset UtcNow => _lazyUtcNow.Value; }

¿Es este un buen enfoque? ¿Cuales son las desventajas? ¿Hay mejores alternativas?


Esto no es algo que se pueda responder con un reloj en tiempo real y una consulta, o mediante pruebas. El desarrollador puede haber descubierto alguna forma oscura de llegar a la llamada de la biblioteca subyacente ...

Así que no hagas eso. La inyección de dependencia tampoco te salvará aquí; el problema es que desea un patrón estándar de tiempo al inicio de la ''sesión''.

En mi opinión, el problema fundamental es que estás expresando una idea y buscando un mecanismo para eso. El mecanismo correcto es nombrarlo y decir lo que quiere decir en el nombre, y luego configurarlo solo una vez. readonly es una buena manera de manejar la configuración solo una vez en el constructor, y permite que el compilador y el tiempo de ejecución apliquen lo que quiere decir, lo que significa que está configurado solo una vez.

// In an entity constructor: this.CreatedAt = DateTime.UtcNow;


Hmmm ... esto parece una pregunta mejor para CodeReview.SE que para , pero seguro, lo CodeReview.SE .

¿Es este un buen enfoque?

Si se usa correctamente, en el escenario que describió, este enfoque es razonable. Logra los dos objetivos declarados:

  1. Haciendo su código más comprobable. Este es un patrón común al que llamo "Simulacro del reloj" y se encuentra en muchas aplicaciones bien diseñadas.

  2. Bloqueando el tiempo a un solo valor. Esto es menos común, pero su código logra ese objetivo.

¿Cuales son las desventajas?

  1. Ya que está creando otro objeto nuevo para cada solicitud, creará una cantidad moderada de uso de memoria adicional y trabajo adicional para el recolector de basura. Esto es algo así como un punto discutible ya que generalmente es así como se aplica a todos los objetos con vida útil por solicitud, incluidos los controladores.

  2. Hay una pequeña fracción de tiempo que se agrega antes de tomar la lectura del reloj, causada por el trabajo adicional que se realiza al cargar el objeto y por realizar una carga perezosa. Sin embargo, es despreciable, probablemente del orden de unos pocos milisegundos.

  3. Dado que el valor está bloqueado, siempre existe el riesgo de que usted (u otro desarrollador que use su código) pueda presentar un error sutil al olvidar que el valor no cambiará hasta la próxima solicitud. Podría considerar una convención de nomenclatura diferente. Por ejemplo, en lugar de "ahora", llámelo "requestRecievedTime" o algo así.

  4. Al igual que en el artículo anterior, también existe el riesgo de que su proveedor tenga un ciclo de vida incorrecto. Puede usarlo en un nuevo proyecto y olvidarse de configurar la creación de instancias, cargándolo como un singleton. A continuación, los valores se bloquean para todas las solicitudes. No hay mucho que puedas hacer para hacer cumplir esto, así que asegúrate de comentarlo bien. La etiqueta <summary> es un buen lugar.

  5. Es posible que necesite la hora actual en un escenario en el que la inyección del constructor no sea posible, como un método estático. Tendrá que refactorizar para usar métodos de instancia, o tendrá que pasar el tiempo o el proveedor de tiempo como un parámetro en el método estático.

¿Hay mejores alternativas?

Sí, mira la respuesta de Mike .

También puede considerar Noda Time , que tiene un concepto similar incorporado, a través de la interfaz IClock , y las implementaciones SystemClock y FakeClock . Sin embargo, ambas implementaciones están diseñadas para ser singletons. Ayudan con las pruebas, pero no logran su segundo objetivo de bloquear el tiempo a un solo valor por solicitud. Sin embargo, siempre se puede escribir una implementación que haga eso.


Lo siento por la falacia lógica de apelar a la autoridad aquí, pero esto es bastante interesante:

John Carmack dijo una vez:

Hay cuatro entradas principales para un juego: pulsaciones de teclas, movimientos del mouse, paquetes de red y tiempo. (Si no considera el tiempo como un valor de entrada, piénselo hasta que lo haga, es un concepto importante) "

Fuente: .plan publicaciones de John Carmack desde 1998 (scribd)

(Siempre he encontrado esta cita muy divertida, porque la sugerencia de que si algo no te parece bien, deberías considerarlo realmente difícil hasta que parezca correcto, es algo que solo un geek importante diría).

Entonces, aquí hay una idea: considere el tiempo como una entrada. Probablemente no esté incluido en el xml que conforma la solicitud de servicio web (no querría que lo hiciera de todos modos), pero en el controlador donde convierte el xml en un objeto de solicitud real, obtiene la hora actual y la hace parte. de su objeto de solicitud.

Por lo tanto, como el objeto de solicitud se pasa alrededor de su sistema durante el proceso de procesamiento de la transacción, el tiempo que debe considerarse como "el tiempo actual" siempre se puede encontrar dentro de la solicitud . Entonces, ya no es "la hora actual", es el tiempo de solicitud . (El hecho de que sea uno y el mismo, o muy cercano a uno y el mismo, es completamente irrelevante).

De esta manera, las pruebas también se vuelven aún más fáciles: no tiene que burlarse de la interfaz del proveedor de tiempo, el tiempo está siempre en los parámetros de entrada.

Además, de esta manera, otras cosas divertidas se vuelven posibles, por ejemplo, las solicitudes de servicio se aplican de forma retroactiva, en un momento en el tiempo que no tiene ninguna relación con el momento actual actual. Piensa en las posibilidades. (La imagen de bob squarepants-with-a-rainbow va aquí.)