La conversión de un tipo de datos datetime2 a un tipo de datos datetime da como resultado un valor fuera de rango

379

Tengo una tabla de datos con 5 columnas, donde una fila se llena con datos y luego se guarda en la base de datos a través de una transacción.

Al guardar, se devuelve un error:

La conversión de un tipo de datos datetime2 a un tipo de datos datetime dio como resultado un valor fuera de rango

Implica, como se lee, que mi tabla de datos tiene un tipo de DateTime2y mi base de datos a DateTime; eso está mal.

La columna de fecha se establece de DateTimeesta manera:

new DataColumn("myDate", Type.GetType("System.DateTime"))

Pregunta

¿Se puede resolver esto en código o hay que cambiar algo a nivel de base de datos?

Gerbrand
fuente

Respuestas:

60

¿Qué tipo de fechas tienes en la columna?

¿Todos ellos se ajustan al rango del tipo?


Por otro lado, la forma correcta de obtener un Typeobjeto para el DataColumnconstructor es la typeofpalabra clave, que es un orden de magnitud más rápido.

Por lo tanto, para crear la columna, debe escribir

new DataColumn("myDate", typeof(DateTime))
SLaks
fuente
3
Cambié mis columnas de datos y usé typeof ahora ... Además encontré mi problema. hubo 1 DataRow que contenía una fecha equivocada, lo que provocó el error
Gerbrand
739

Esto puede suceder si no asigna un valor a un campo DateTime cuando el campo no acepta valores NULL .

¡Eso me lo arregló!

andyuk
fuente
43
En Entity Framework, si agrega una columna Creado que no es nula, actualice su EDMX, cuando no esté configurando el valor en el código, eso puede arrojar este error de esta manera
Brad Thomas
66
¿Qué lo arregló para ti? Este error aparece cuando tiene un campo de fecha y hora con una llamada getdate () como valor predeterminado.
user3046061
15
¿Por qué no puede ignorar Entity Framework si es NULL porque en mi lado SQL, tengo un valor predeterminado = getdate ()?
JoshYates1980
33
Lo que creo que sucede es que EntityFramework ve un DateTime.MinValue que es el año 0001 y en SQL datetime está fuera del rango de valor, por lo que envía este valor como un valor DateTime2 (que admite el año 0001) para que la inserción / actualización sea válida, sin embargo falla cuando SQL intenta convertir este DateTime2 a DateTime porque esto dará como resultado un valor diferente. Dos soluciones son: 1 Use una fecha y hora anulable en su modelo o 2. Inicialice todos sus valores de fecha y hora en el valor correcto antes de guardar los cambios de contexto. La elección que haga dependerá de lo que signifique la fecha y hora en su modelo.
Guillermo Ruffino
1
La solución de @ GuillermoRuffino funcionó para mí. Inspeccione todos sus campos y encuentre esas entradas de 0001 años.
Francesco B.
158

Tanto el DATETIMEy el DATETIME2mapa System.DateTimeen .NET - realmente no puede hacer una "conversión", ya que es realmente el mismo tipo .NET.

Consulte la página de documentos de MSDN: http://msdn.microsoft.com/en-us/library/bb675168.aspx

Hay dos valores diferentes para el " SqlDbType" para estos dos: ¿puede especificarlos en su DataColumndefinición?

PERO: en SQL Server, el intervalo de fechas admitido es bastante diferente.

DATETIMEadmite 1753/1/1 hasta "eternity" (9999/12/31), mientras que DATETIME2admite 0001/1/1 hasta la eternidad.

Entonces, lo que realmente necesita hacer es verificar el año de la fecha; si es antes de 1753, debe cambiarlo a algo DESPUÉS de 1753 para que el DATETIME columna en SQL Server lo maneje.

Bagazo

marc_s
fuente
77
Esto explica el problema que tuve. Aunque hay pocas situaciones en las que las fechas reales antes de 1753/1/1 necesitan ser manejadas, pero hay muchas situaciones en las que uno obtiene el valor predeterminado 0001/1/1 que puede provocar el error.
Hong
Confirmo que cuando estaba tratando de insertar un 'nuevo DateTime ()' en un tipo de datos 'datetime' recibí esta excepción.
George Onofrei
1
Estaba tratando de asignar un valor predeterminado de DateTime.MinValue en mi código C # que escribió en una base de datos. Esto explica el error que estaba recibiendo. +1
Mkalafut
Utilizo Entity Framework Code First y utilizo el modelo con la propiedad DateTime. DtInit = new System.DateTime(1492, 10, 12),falla
Kiquenet
Esta es una de esas situaciones donde la verdadera razón está oculta detrás del parche ... +1
Eugenio Miró
41

En mi base de datos SQL Server 2008, tenía una DateTimecolumna marcada como no anulable, pero con una GetDate()función como valor predeterminado. Al insertar un nuevo objeto usando EF4, recibí este error porque no estaba pasando explícitamente una propiedad DateTime en mi objeto. Esperaba que la función SQL manejara la fecha por mí, pero no lo hizo. Mi solución fue enviar el valor de la fecha desde el código en lugar de confiar en la base de datos para generarlo.

obj.DateProperty = DateTime.now; // C#
Graham
fuente
2
Encantado de ayudar. Es molesto porque pensarías que el contexto de datos de EF podría descubrir que el campo tiene un valor predeterminado cuando el objeto se crea a partir de la tabla.
Graham
Pensaría muchas cosas sobre EF. Estoy usando las entidades de seguimiento automático de POCO y es un clúster. Voy a revisar el primer modelo de código, y si eso también está lleno de tonterías, estoy pensando seriamente en volver a linq a sql y usar un mapeador de objetos para asignar accesorios a mis propias entidades ...
2
Vi una demostración de EF Code First en VS Live hace 2 semanas y parecía IMPRESIONANTE, por cierto.
Graham
Esas son buenas noticias. Pronto comenzaremos un nuevo proyecto en mi oficina, y estoy dividido en EF-CF y apuesto (usado / mantenido por SO). Probablemente se reducirá a cuál es mejor en una aplicación que se utiliza a través de un servicio WCF.
1
Hola, comentarios de un año! Yo mismo estoy comenzando con EF Code-First y descubrí que en mi POCO solo necesitaba definir mi miembro datetime como Nullable<DateTime>, y en el código puedo dejar esto realmente nulo (en lugar de 01/01/0000). Me sorprendió gratamente ver que EF to SQL sabía ignorar este valor nulo en INSERT y usar la fecha del servidor ( GetDate()) ... Para nosotros, esto era incluso preferible ya que necesitábamos una mayor coherencia en el servidor, sin preocuparnos por las diferencias de reloj entre el servidor web y el del servidor sql.
Funka
34

para mí fue porque la fecha y hora era ...

01/01/0001 00:00:00

en este caso, desea asignarle un objeto EF DateTime nulo ... utilizando mi código FirstYearRegistered como ejemplo

DateTime FirstYearRegistered = Convert.ToDateTime(Collection["FirstYearRegistered"]);
if (FirstYearRegistered != DateTime.MinValue)
{
    vehicleData.DateFirstReg = FirstYearRegistered;
}  
JGilmartin
fuente
Estoy analizando estos datos usando ExcelDataReader y está devolviendo el 01/01/0001 cuando se ingresó texto no válido (no arroja una excepción como se esperaba, usando el método .GetDateTime (columnIndex)). La comparación con el MinValue hizo el truco para evitar la excepción de fuera de rango en sql.
Tommy
22

Este me estaba volviendo loco. Quería evitar el uso de una fecha y hora anulables ( DateTime?). Tampoco tenía la opción de usar el datetime2tipo de SQL Server 2008

modelBuilder.Entity<MyEntity>().Property(e => e.MyDateColumn).HasColumnType("datetime2");

Finalmente opté por lo siguiente:

public class MyDb : DbContext
{
    public override int SaveChanges()
    {
        UpdateDates();
        return base.SaveChanges();
    }

    private void UpdateDates()
    {
        foreach (var change in ChangeTracker.Entries<MyEntityBaseClass>())
        {
            var values = change.CurrentValues;
            foreach (var name in values.PropertyNames)
            {
                var value = values[name];
                if (value is DateTime)
                {
                    var date = (DateTime)value;
                    if (date < SqlDateTime.MinValue.Value)
                    {
                        values[name] = SqlDateTime.MinValue.Value;
                    }
                    else if (date > SqlDateTime.MaxValue.Value)
                    {
                        values[name] = SqlDateTime.MaxValue.Value;
                    }
                }
            }
        }
    }
}
sky-dev
fuente
1
Utilizando [Column(TypeName = "datetime2")]?
Kiquenet
21

A veces, EF no sabe que se trata de una columna calculada o un disparador . Por diseño, esas operaciones establecerán un valor fuera de EF después de una inserción.

La solución es especificar Computeden EF edmxpara esa columna en la StoreGeneratedPatternpropiedad.

Para mí fue cuando la columna tenía un disparador que insertaba la fecha y hora actuales, ver más abajo en la tercera sección.


Pasos para resolver

En Visual Studio abra la Model Browserpágina, Modelluego Entity Types-> luego

  1. Seleccione la entidad y la propiedad de fecha y hora
  2. Seleccione StoreGeneratedPattern
  3. Ajustado a Computed

Cuadro de diálogo EF Model Browser Model Entity Type


Para esta situación, otras respuestas son soluciones alternativas, para el propósito de la columna es tener una hora / fecha especificada cuando se creó el registro, y ese es el trabajo de SQL para ejecutar un disparador para agregar la hora correcta. Como este disparador SQL:

DEFAULT (GETDATE()) FOR [DateCreated].

ΩmegaMan
fuente
Tenga en cuenta que había usado GETDATE()lo que literalmente hice en ese momento. Pero hubo un comentario reciente que uno debe usar SYSDATETIME()para cualquier operación DateTime2 que creo que es cierto.
ΩmegaMan
10

Me encontré con esto y agregué lo siguiente a mi propiedad datetime:

 [Column(TypeName = "datetime2")]
 public DateTime? NullableDateTimePropUtc { get; set; }
Rogala
fuente
1
using System.ComponentModel.DataAnnotations.Schema; se requiere
Kiquenet
9

Si no pasamos un campo de fecha hora a fecha, se pasará la fecha predeterminada {1/1/0001 12:00:00 AM}.

Pero esta fecha no es compatible con el marco de la entidad, por lo que arrojará la conversión de un tipo de datos datetime2 a un tipo de datos datetime que resultó en un valor fuera de rango

Solo default DateTime.nowal campo de fecha si no está pasando ninguna fecha.

movie.DateAdded = System.DateTime.Now
Lijo
fuente
Yo diría que pasar 'DateTime.Now' como valor predeterminado está lejos de ser correcto, y es bastante engañoso.
Bartosz
6

Lo más fácil sería cambiar su base de datos para usar datetime2 en lugar de datetime. La compatibilidad funciona bien y no obtendrá sus errores.

Todavía querrás hacer un montón de pruebas ...

El error probablemente se deba a que está tratando de establecer una fecha para el año 0 o algo así, pero todo depende de dónde tenga el control para cambiar las cosas.

Rob Farley
fuente
4

Encontré esta publicación tratando de averiguar por qué seguía recibiendo el siguiente error, que se explica en las otras respuestas.

La conversión de un tipo de datos datetime2 a un tipo de datos datetime dio como resultado un valor fuera de rango.

Use un objeto DateTime anulable.
fecha y hora pública? PurchaseDate {get; conjunto; }

Si está utilizando el marco de la entidad Establezca la propiedad anulable en el archivo edmx en True

Establezca la propiedad anulable en el archivo edmx en ** Verdadero **

hedor
fuente
3

Como ya ha señalado andyuk , esto puede suceder cuando se asigna un valor NULL a un campo DateTime no anulable . ¿Considera cambiar DateTime a DateTime? o Nullable < DateTime >. Tenga en cuenta que, en caso de que esté utilizando una propiedad de dependencia , también debe asegurarse de que el tipo de su propiedad de dependencia también sea un tipo DateTime anulable.

A continuación se muestra un ejemplo de la vida real de un DateTime a DateTime incompleto . ajuste de tipo que aumenta el comportamiento extraño

ingrese la descripción de la imagen aquí

Julio Nobre
fuente
2

Entity Framework 4 funciona con el tipo de datos datetime2, por lo que en db el campo correspondiente debe ser datetime2 para SQL Server 2008.

Para lograr la solución hay dos formas.

  1. Para usar el tipo de datos datetime en Entity Framwork 4, debe cambiar ProviderManifestToken en el archivo edmx a "2005".
  2. Si establece el campo correspondiente como Permitir nulo (lo convierte en NULABLE), entonces EF usa automáticamente los objetos de fecha como fecha y hora.
Mahmut C
fuente
1
Recogí tu segundo punto para mis modelos de base de datos (clases POCO) y me pregunté cómo establecer un campo como tipo anulable. En caso de que alguien se lo pregunte, puede hacerlo agregando un signo de interrogación (?) Después del tipo de fecha. por ejemplo, DateTime pública? StartTime {get; conjunto; } Esto resolvió el problema para mí. La única otra cosa que tuve que hacer fue colocar un molde de TimeSpan alrededor de una línea de código donde estaba restando dos valores de DateTime anulables entre sí. por ejemplo, var timeTaken = (TimeSpan) (endTime - startTime);
Ciaran Gallagher
1

Creó una clase base basada en la implementación @ sky-dev. Por lo tanto, esto se puede aplicar fácilmente a múltiples contextos y entidades.

public abstract class BaseDbContext<TEntity> : DbContext where TEntity : class
{
    public BaseDbContext(string connectionString)
        : base(connectionString)
    {
    }
    public override int SaveChanges()
    {

        UpdateDates();
        return base.SaveChanges();
    }

    private void UpdateDates()
    {
        foreach (var change in ChangeTracker.Entries<TEntity>())
        {
            var values = change.CurrentValues;
            foreach (var name in values.PropertyNames)
            {
                var value = values[name];
                if (value is DateTime)
                {
                    var date = (DateTime)value;
                    if (date < SqlDateTime.MinValue.Value)
                    {
                        values[name] = SqlDateTime.MinValue.Value;
                    }
                    else if (date > SqlDateTime.MaxValue.Value)
                    {
                        values[name] = SqlDateTime.MaxValue.Value;
                    }
                }
            }
        }
    }
}

Uso:

public class MyContext: BaseDbContext<MyEntities>
{

    /// <summary>
    /// Initializes a new instance of the <see cref="MyContext"/> class.
    /// </summary>
    public MyContext()
        : base("name=MyConnectionString")
    {
    }
    /// <summary>
    /// Initializes a new instance of the <see cref="MyContext"/> class.
    /// </summary>
    /// <param name="connectionString">The connection string.</param>
    public MyContext(string connectionString)
        : base(connectionString)
    {
    }

     //DBcontext class body here (methods, overrides, etc.)
 }
Dynamiclynk
fuente
1

Agregue el atributo mencionado a continuación en la propiedad en su clase de modelo.

Attribute = [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
Reference = System.ComponentModel.DataAnnotations.Schema

Inicialmente olvidé agregar este atributo. Entonces, en mi base de datos, la restricción se creó como

ALTER TABLE [dbo].[TableName] ADD DEFAULT (getdate()) FOR [ColumnName]

y agregué este atributo y actualicé mi base de datos, luego se cambió a

ALTER TABLE [dbo].[TableName] ADD CONSTRAINT [DF_dbo.TableName_ColumnName] DEFAULT (getdate()) FOR [ColumnName]
Ajith Chandran
fuente
[DatabaseGenerated (DatabaseGeneratedOption.Computed)]
Ajith Chandran
0

A veces funciona bien en máquinas de desarrollo y no en servidores. En mi caso tuve que poner:

<globalization uiCulture="es" culture="es-CO" />

En el archivo web.config.

La zona horaria en la máquina (Servidor) era correcta (a la configuración regional de CO) pero la aplicación web no. Esta configuración se realizó y funcionó bien nuevamente.

Por supuesto, todas las fechas tenían valor.

:RE

Jaime Enrique Espinosa Reyes
fuente
0

Agregar este código a una clase en ASP.NET funcionó para mí:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
}
Howie Krauth
fuente
0

Soy consciente de este problema y todos ustedes también deberían estarlo:

https://en.wikipedia.org/wiki/Year_2038_problem

En SQL, se creó un nuevo tipo de campo para evitar este problema (datetime2).

Este tipo de campo 'Fecha' tiene los mismos valores de rango que una clase DateTime .Net. Resolverá todos sus problemas, por lo que creo que la mejor manera de resolverlo es cambiar el tipo de columna de su base de datos (no afectará los datos de su tabla).

marcolomew
fuente
0

Consulte los dos siguientes: 1) Este campo no tiene valor NULL. Por ejemplo:

 public DateTime MyDate { get; set; }

Reemplazar a:

public DateTime MyDate { get; set; }=DateTime.Now;

2) Nueva la base de datos nuevamente. Por ejemplo:

db=new MyDb();
RainyTears
fuente
¿Qué sucede si no desea que el valor sea DateTime.Now de forma predeterminada?
Salvaje
Si no quieres: DateTime.Now. Puede usar: nuevo DateTime (..., ..., ...)
RainyTears
0

Problema con el atributo de fecha y hora heredado

Este mensaje de error a menudo se muestra cuando un campo de fecha no anulable tiene un valor nulo en el momento de inserción / actualización. Una causa puede ser la herencia.

Si su fecha se hereda de una clase base y no realiza una asignación, EF no leerá su valor.

Para más información: https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and- elección-pautas-estrategia

FrankyHollywood
fuente
0

Vi este error cuando quería editar una página usando ASP.Net MVC. ¡No tuve ningún problema al crear pero actualizar la base de datos hizo que mi propiedad DateCreated fuera de rango!

Cuando no desee que su DateTimepropiedad sea anulable y no desee verificar si su valor está en el rango de fecha y hora sql (¡y @Html.HiddenForno ayuda!), Simplemente agregue un static DateTimecampo dentro de la clase relacionada (Controlador) y dele el valor cuando GET está funcionando, luego úselo cuando POST esté haciendo su trabajo:

public class PagesController : Controller
{
    static DateTime dateTimeField;
    UnitOfWork db = new UnitOfWork();

    // GET:
    public ActionResult Edit(int? id)
    {
        Page page = db.pageRepository.GetById(id);
        dateTimeField = page.DateCreated;
        return View(page);
    }

    // POST: 
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(Page page)
    {
        page.DateCreated = dateTimeField;
        db.pageRepository.Update(page);
        db.Save();
        return RedirectToAction("Index");

    }
}
mp3846
fuente
0

Me encontré con este problema en un proyecto de aplicación de consola simple y mi solución rápida es convertir cualquier fecha datetime2 posible en una fecha y hora anulable ejecutando este método:

static DateTime? ParseDateTime2(DateTime? date)
    {
        if (date == null || date.ToString() == "1/1/0001 12:00:00 AM")
        {
            return null;
        }
        else
        {
            return date;
        }
    }

Este ciertamente no es un método completamente completo, ¡pero funcionó para mis necesidades y quizás ayude a otros!

David Alan Condit
fuente
0

Verifique el formato de solicitud en DB. por ejemplo, mi base de datos tiene valor predeterminado o enlace(((1)/(1))/(1900))

System.DateTime MyDate = new System.DateTime( 1900 ,1, 1);

ingrese la descripción de la imagen aquí

Arsalan Maqsood
fuente
-1

tendrá una columna de fecha que se configuró para lesathan el valor mínimo del tiempo de transmisión permitido como 1/1/1001.

Para superar este problema, puede establecer el valor de fecha y hora adecuado para su propiedad y también establecer otra propiedad mágica como IsSpecified = true.

Koteshwar
fuente