La conversion d'un type de données datetime2 en un type de données datetime entraîne une valeur hors plage

379

J'ai une table de données avec 5 colonnes, où une ligne est remplie de données puis enregistrée dans la base de données via une transaction.

Lors de l'enregistrement, une erreur est renvoyée:

La conversion d'un type de données datetime2 en un type de données datetime a donné lieu à une valeur hors plage

Cela implique, comme lu, que mon datatable a un type de DateTime2et ma base de données a DateTime; C'est faux.

La colonne de date est définie DateTimecomme ceci:

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

Question

Cela peut-il être résolu dans le code ou faut-il changer quelque chose au niveau de la base de données?

Gerbrand
la source

Réponses:

60

Quel genre de dates avez-vous dans la colonne?

Tous s'inscrivent-ils dans la gamme du type?


En passant, la bonne façon d'obtenir un Typeobjet pour le DataColumnconstructeur est le typeofmot - clé, qui est plus rapide de plusieurs ordres de grandeur.

Par conséquent, pour créer la colonne, vous devez écrire

new DataColumn("myDate", typeof(DateTime))
SLaks
la source
3
J'ai changé mes colonnes de données et utilisé typeof maintenant ... De plus, j'ai trouvé mon problème. il y avait 1 datarow qui contenait une date incorrecte, ce qui a déclenché l'erreur
Gerbrand
739

Cela peut se produire si vous n'affectez pas de valeur à un champ DateTime lorsque le champ n'accepte pas les valeurs NULL .

Cela m'a arrangé!

andyuk
la source
43
Dans Entity Framework, si vous ajoutez une colonne créée qui n'est pas nulle, puis mettez à jour votre EDMX, lorsque vous ne définissez pas la valeur dans le code, cela peut générer cette erreur de cette façon
Brad Thomas
6
Qu'est-ce qui l'a réparé pour vous? Cette erreur apparaît lorsque vous avez un champ datetime avec un appel getdate () comme valeur par défaut.
user3046061
15
Pourquoi l'Entity Framework ne peut-il pas ignorer si NULL parce que de mon côté SQL, j'ai une valeur par défaut = getdate ()?
JoshYates1980
33
Ce que je pense que cela se produit, c'est que EntityFramework voit un DateTime.MinValue qui est l'année 0001 et dans SQL datetime est hors de la valeur de la plage, donc il envoie cette valeur en tant que valeur DateTime2 (qui prend en charge l'année 0001) afin que l'insertion / mise à jour soit valide, cependant il échoue lorsque SQL essaie de convertir ce DateTime2 en DateTime car cela entraînera une valeur différente. Deux solutions sont: 1 Utilisez un datetime nullable dans votre modèle ou 2. initialisez toutes vos valeurs datetime, à la valeur correcte avant d'enregistrer les changements de contexte. Le choix que vous faites dépend de la signification de la date / heure dans votre modèle.
Guillermo Ruffino
1
La solution de @ GuillermoRuffino a fonctionné pour moi. Inspectez tous vos champs et trouvez ces entrées 0001 années.
Francesco B.
158

Le DATETIMEet le DATETIME2mappage System.DateTimedans .NET - vous ne pouvez pas vraiment faire une "conversion", car c'est vraiment le même type .NET.

Consultez la page de documentation MSDN: http://msdn.microsoft.com/en-us/library/bb675168.aspx

Il existe deux valeurs différentes pour le " SqlDbType" pour ces deux - pouvez-vous les spécifier dans votre DataColumndéfinition?

MAIS: sur SQL Server, la plage de dates prise en charge est assez différente.

DATETIMEprend en charge 1753/1/1 à "éternité" (9999/12/31), tandis que DATETIME2prend en charge 0001/1/1 à travers éternité.

Donc, ce que vous devez vraiment faire est de vérifier l'année de la date - si c'est avant 1753, vous devez le changer en quelque chose APRÈS 1753 pour que la DATETIMEcolonne dans SQL Server le gère.

Marc

marc_s
la source
7
Cela explique le problème que j'ai eu. Bien qu'il existe peu de situations où les dates réelles avant 1753/1/1 doivent être traitées, mais il existe de nombreuses situations où l'on obtient la valeur par défaut 0001/1/1 qui peut entraîner l'erreur.
Hong
Je confirme que lorsque j'essayais d'insérer un «nouveau DateTime ()» dans un type de données «datetime», j'ai reçu cette exception.
George Onofrei
1
J'essayais d'attribuer une valeur par défaut de DateTime.MinValue dans mon code C # qui a écrit dans une base de données. Cela explique l'erreur que j'obtenais. +1
Mkalafut
J'utilise Entity Framework Code First et j'utilise un modèle avec la propriété DateTime. DtInit = new System.DateTime(1492, 10, 12),échoue.
Kiquenet
C'est une de ces situations où la vraie raison est cachée derrière le patch ... +1
Eugenio Miró
41

Dans ma base de données SQL Server 2008, j'avais une DateTimecolonne marquée comme non nullable, mais avec une GetDate()fonction comme valeur par défaut. Lors de l'insertion d'un nouvel objet à l'aide d'EF4, j'ai eu cette erreur car je ne transmettais pas explicitement une propriété DateTime sur mon objet. Je m'attendais à ce que la fonction SQL gère la date pour moi, mais ce n'est pas le cas. Ma solution était d'envoyer la valeur de date à partir du code au lieu de compter sur la base de données pour la générer.

obj.DateProperty = DateTime.now; // C#
Graham
la source
2
Heureux de vous aider. C'est ennuyeux car on pourrait penser que le contexte de données EF pourrait découvrir que le champ a une valeur par défaut lorsque l'objet est créé à partir de la table.
Graham
Je pense que beaucoup de choses sur EF. J'utilise les entités d'auto-suivi POCO et c'est un tel cluster. Je vais vérifier le premier modèle de code, et si cela est aussi plein de bêtises, je pense sérieusement à revenir à linq en sql et à utiliser un mappeur d'objets pour mapper les accessoires à mes propres entités ...
2
J'ai vu une démo d'EF Code First sur VS Live il y a 2 semaines et elle avait l'air géniale, btw.
Graham
C'est une bonne nouvelle. Nous démarrons bientôt un nouveau projet dans mon bureau, et je suis divisé sur EF-CF et dapper (utilisé / maintenu par SO). Cela se résumera probablement à ce qui est mieux dans une application utilisée via un service WCF.
1
Bonjour, commentaires vieux d'un an! Je commence moi-même avec EF Code-First et j'ai découvert que sur mon POCO j'avais juste besoin de définir mon membre datetime comme Nullable<DateTime>, et dans le code, je peux laisser cela vraiment nul (au lieu du 01/01/0000). J'ai été agréablement surpris de voir qu'EF to SQL savait ignorer ce null sur INSERT et utiliser la date du serveur ( GetDate()) ... Pour nous, c'était encore préférable car nous avions besoin d'une meilleure cohérence sur le serveur, sans nous soucier des différences d'horloge entre le serveur web et celui du serveur sql.
Funka
34

pour moi c'était parce que le datetime était ..

01/01/0001 00:00:00

dans ce cas, vous voulez vous attribuer null EF DateTime Object ... en utilisant mon code FirstYearRegistered comme exemple

DateTime FirstYearRegistered = Convert.ToDateTime(Collection["FirstYearRegistered"]);
if (FirstYearRegistered != DateTime.MinValue)
{
    vehicleData.DateFirstReg = FirstYearRegistered;
}  
JGilmartin
la source
J'analyse ces données à l'aide d'ExcelDataReader et il renvoie le 01/01/0001 lorsque du texte non valide a été entré (ne génère pas d'exception comme prévu - en utilisant la méthode .GetDateTime (columnIndex)). La comparaison avec MinValue a fait l'affaire pour empêcher l'exception hors de portée dans sql.
Tommy
22

Celui-ci me rendait fou. Je voulais éviter d'utiliser une date / heure nullable ( DateTime?). Je n'avais pas non plus la possibilité d'utiliser le datetime2type de SQL Server 2008

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

J'ai finalement opté pour ce qui suit:

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
la source
1
En utilisant [Column(TypeName = "datetime2")]?
Kiquenet
21

Parfois, EF ne sait pas qu'il s'agit d'une colonne calculée ou d'un déclencheur . De par leur conception, ces opérations définiront une valeur en dehors de EF après une insertion.

Le correctif consiste à spécifier Computeddans les EF de edmxcette colonne dans la StoreGeneratedPatternpropriété.

Pour moi, c'était lorsque la colonne avait un déclencheur qui insérait la date et l'heure actuelles, voir ci-dessous dans la troisième section.


Étapes pour résoudre

Dans Visual Studio, ouvrez la Model Browserpage Modelpuis Entity Types-> puis

  1. Sélectionnez l'entité et la propriété date-heure
  2. Sélectionner StoreGeneratedPattern
  3. Mis à Computed

Boîte de dialogue EF Model Browser Model Entity Type


Pour cette situation, d'autres réponses sont des solutions de contournement, dans le but de la colonne est d'avoir une heure / date spécifiée lorsque l'enregistrement a été créé, et c'est le travail de SQL pour exécuter un déclencheur pour ajouter l'heure correcte. Tels que ce déclencheur SQL:

DEFAULT (GETDATE()) FOR [DateCreated].

ΩmegaMan
la source
Notez que j'avais utilisé GETDATE()ce que je faisais littéralement à l'époque. Mais il y a eu un commentaire récent que l'on devrait utiliser SYSDATETIME()pour toutes les opérations DateTime2 qui je pense être vrai.
ΩmegaMan
10

J'ai rencontré cela et j'ai ajouté ce qui suit à ma propriété datetime:

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

Si nous ne transmettons pas de champ date à date, la date par défaut {1/1/0001 12:00:00 AM} sera transmise.

Mais cette date n'est pas compatible avec le travail de trame d'entité, elle lancera donc la conversion d'un type de données datetime2 en un type de données datetime, ce qui a entraîné une valeur hors plage

Juste default DateTime.nowau champ de date si vous ne passez aucune date.

movie.DateAdded = System.DateTime.Now
Lijo
la source
Je dirais que passer "DateTime.Now" comme valeur par défaut est loin d'être correct et est plutôt trompeur.
Bartosz
6

Le plus simple serait de changer votre base de données pour utiliser datetime2 au lieu de datetime. La compatibilité fonctionne bien et vous n'obtiendrez pas vos erreurs.

Vous aurez toujours envie de faire un tas de tests ...

L'erreur est probablement parce que vous essayez de définir une date sur l'année 0 ou quelque chose - mais tout dépend de l'endroit où vous avez le contrôle pour changer les choses.

Rob Farley
la source
4

J'ai trouvé ce post essayant de comprendre pourquoi j'ai continué à obtenir l'erreur suivante qui est expliquée par les autres réponses.

La conversion d'un type de données datetime2 en un type de données datetime a entraîné une valeur hors plage.

Utilisez un objet DateTime nullable.
DateTime publique? PurchaseDate {get; ensemble; }

Si vous utilisez le framework d'entité Définissez la propriété nullable dans le fichier edmx sur True

Définissez la propriété nullable dans le fichier edmx sur ** True **

puanteur
la source
3

Comme andyuk l' a déjà souligné, cela peut se produire lorsqu'une valeur NULL est affectée à un champ DateTime non nullable . Vous envisagez de remplacer DateTime par DateTime? ou Nullable < DateTime >. Gardez à l'esprit que, si vous utilisez une propriété de dépendance , vous devez également vous assurer que le type de votre propriété de dépendance est également un type DateTime nullable.

Voici un exemple réel d'un DateTime à DateTime incomplet ? ajustement de type qui augmente le comportement étrange

entrez la description de l'image ici

Julio Nobre
la source
2

Entity Framework 4 fonctionne avec le type de données datetime2, donc dans db, le champ correspondant doit être datetime2 pour SQL Server 2008.

Pour parvenir à la solution, il existe deux façons.

  1. Pour utiliser le type de données datetime dans Entity Framwork 4, vous devez basculer le ProviderManifestToken dans le fichier edmx sur "2005".
  2. Si vous définissez le champ correspondant sur Allow Null (il le convertit en NULLABLE), EF utilise automatiquement les objets de date comme datetime.
Mahmut C
la source
1
J'ai repris votre deuxième point pour mes modèles de base de données (classes POCO) et je me suis demandé comment définir un champ comme type nullable. Si quelqu'un se pose la question, vous pouvez le faire en ajoutant un point d'interrogation (?) Après le type de date. par exemple DateTime publique? StartTime {get; ensemble; } Cela a résolu le problème pour moi. La seule autre chose que je devais faire était de placer un cast TimeSpan autour d'une ligne de code où je soustrayais deux valeurs DateTime nullables l'une de l'autre. par exemple var timeTaken = (TimeSpan) (endTime - startTime);
Ciaran Gallagher
1

Création d'une classe de base basée sur l'implémentation de @ sky-dev. Cela peut donc être facilement appliqué à plusieurs contextes et entités.

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;
                    }
                }
            }
        }
    }
}

Usage:

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
la source
1

Ajoutez l'attribut mentionné ci-dessous sur la propriété dans votre classe de modèle.

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

Au départ, j'ai oublié d'ajouter cet attribut. Donc, dans ma base de données, la contrainte a été créée comme

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

et j'ai ajouté cet attribut et mis à jour mon db puis il a été changé en

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

Parfois, cela fonctionne bien sur les machines de développement et non sur les serveurs. Dans mon cas, j'ai dû mettre:

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

Dans le fichier web.config.

Le fuseau horaire de la machine (serveur) était correct (pour les paramètres régionaux CO), mais pas l'application Web. Ce réglage est fait et cela a bien fonctionné à nouveau.

Bien sûr, toutes les dates avaient de la valeur.

:RÉ

Jaime Enrique Espinosa Reyes
la source
0

L'ajout de ce code à une classe dans ASP.NET a fonctionné pour moi:

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

Je suis conscient de ce problème et vous devriez tous l'être aussi:

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

En SQL, un nouveau type de champ a été créé pour éviter ce problème (datetime2).

Ce type de champ 'Date' a les mêmes valeurs de plage qu'une classe DateTime .Net. Cela résoudra tous vos problèmes, donc je pense que la meilleure façon de le résoudre est de changer le type de colonne de votre base de données (cela n'affectera pas vos données de table).

marcolomew
la source
0

Découvrez les deux suivants: 1) Ce champ n'a pas de valeur NULL. Par exemple:

 public DateTime MyDate { get; set; }

Remplacer par:

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

2) Nouvelle nouvelle base de données. Par exemple:

db=new MyDb();
RainyTears
la source
Que faire si vous ne souhaitez pas que la valeur soit DateTime.Now par défaut?
Savage
Si vous ne voulez pas: DateTime.Now. Vous pouvez utiliser: nouveau DateTime (..., ..., ...)
RainyTears
0

Problème avec l'attribut datetime hérité

Ce message d'erreur s'affiche souvent lorsqu'un champ de date non nullable a la valeur null au moment de l'insertion / mise à jour. Une cause peut être l'héritage.

Si votre date est héritée d'une classe de base et que vous ne faites pas de mappage, EF ne lira pas sa valeur.

Pour plus d'informations: https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and- choix-stratégie-directives

FrankyHollywood
la source
0

J'ai vu cette erreur lorsque j'ai voulu modifier une page en utilisant ASP.Net MVC. Je n'ai eu aucun problème lors de la création, mais la mise à jour de la base de données a rendu ma propriété DateCreated hors de portée!

Lorsque vous ne voulez pas que votre DateTimepropriété soit nullable et que vous ne vouliez pas vérifier si sa valeur est dans la plage sql DateTime (et @Html.HiddenForn'aide pas!), Ajoutez simplement un static DateTimechamp à l'intérieur de la classe associée (Controller) et donnez-lui la valeur lorsque GET fonctionne, puis utilisez-le lorsque POST fait son travail:

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
la source
0

J'ai rencontré ce problème sur un projet d'application console simple et ma solution rapide consiste à convertir toutes les dates datetime2 possibles en datetime nullable en exécutant cette méthode:

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

Ce n'est certainement pas une méthode complètement complète, mais elle a fonctionné pour mes besoins et peut-être qu'elle aidera les autres!

David Alan Condit
la source
0

Vérifiez le format de demande dans DB. Par exemple, ma base de données a une valeur par défaut ou une liaison(((1)/(1))/(1900))

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

entrez la description de l'image ici

Arsalan Maqsood
la source
-1

vous aurez une colonne de date qui a été définie pour lesathan la valeur minimale de l'heure autorisée comme 1/1/1001.

pour surmonter ce problème, vous pouvez définir la valeur datetime appropriée sur votre propriété et également définir une autre propriété magique comme IsSpecified = true.

Koteshwar
la source