web-dev-qa-db-fra.com

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

J'ai un datatable avec 5 colonnes, où une ligne est remplie avec des données puis sauvegardées dans la base de données via une transaction.

Lors de la sauvegarde, une erreur est renvoyée:

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

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

La colonne de date est définie sur DateTime comme ceci:

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

Question

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

347
Gerbrand

Quel genre de dates avez-vous dans la colonne?

Est-ce que tous correspondent à la gamme du type?


En passant, la méthode correcte pour obtenir un objet Type pour le constructeur DataColumn est le mot clé typeof, qui accélère les ordres de grandeur.

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

new DataColumn("myDate", typeof(DateTime))
54
SLaks

Cela peut arriver si vous n'attribuez pas de valeur à un champ DateTime lorsque le champ n'accepte pas NULL valeurs.

Cela l'a corrigé pour moi!

696
andyuk

Les DATETIME et DATETIME2 sont tous deux mappés sur System.DateTime dans .NET. Vous ne pouvez pas réellement effectuer de "conversion", car il s'agit en réalité du même type .NET.

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

Il existe deux valeurs différentes pour "SqlDbType" pour ces deux personnes. Pouvez-vous les spécifier dans votre définition DataColumn?

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

DATETIME prend en charge les résolutions 1753/1/1 à "éternité" (9999/12/31), tandis que DATETIME2 prend en charge 0001/1/1 à travers l'éternité.

Vous devez donc vérifier l'année de la date. Si elle est antérieure à 1753, vous devez la remplacer par APERTE 1753 pour que la colonne DATETIME de SQL Server la gère.

Marc

150
marc_s

Dans ma base de données SQL Server 2008, j'avais une colonne DateTime marquée comme non nullable, mais avec une fonction GetDate() comme valeur par défaut. Lors de l'insertion d'un nouvel objet à l'aide de EF4, j'ai eu cette erreur parce que je ne transmettais pas explicitement une propriété DateTime à 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 consistait à 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#
40
Graham

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

01/01/0001 00:00:00

dans ce cas, vous souhaitez affecter la valeur null à un objet DateTime EF ... en utilisant mon code FirstYearRegistered comme exemple

DateTime FirstYearRegistered = Convert.ToDateTime(Collection["FirstYearRegistered"]);
if (FirstYearRegistered != DateTime.MinValue)
{
    vehicleData.DateFirstReg = FirstYearRegistered;
}  
30
JGilmartin

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 Computed dans edmx de EF pour cette colonne dans la propriété StoreGeneratedPattern.

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 à suivre pour résoudre

Dans Visual Studio, ouvrez la page Model Browser puis Model puis Entity Types -> puis

  1. Sélectionnez l'entité et la propriété date/heure
  2. Sélectionnez StoreGeneratedPattern
  3. Régler sur Computed

EF Model Browser Model Entity Type dialog


Pour cette situation, d'autres solutions sont des solutions de contournement, l'objectif de la colonne étant de spécifier une heure/date lors de la création de l'enregistrement. Il s'agit du travail de SQL qui consiste à exécuter un déclencheur pour ajouter l'heure correcte. Tels que ce déclencheur SQL:

DEFAULT (GETDATE()) FOR [DateCreated].

20
ΩmegaMan

Celui-ci me rendait fou. Je voulais éviter d'utiliser une date nullable (DateTime?). Je n'avais pas la possibilité d'utiliser le type datetime2 de SQL Server 2008 soit

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;
                    }
                }
            }
        }
    }
}
19
sky-dev

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

 [Column(TypeName = "datetime2")]
 public DateTime? NullableDateTimePropUtc { get; set; }
10
Rogala

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 sur le cadre d’entité, elle se déclenche donc la conversion d’un type de données datetime2 en un type de données datetime a entraîné une valeur hors limites

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

movie.DateAdded = System.DateTime.Now
9
Lijo

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

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

L'erreur est probablement due au fait que vous essayez de définir une date sur l'année 0 ou quelque chose du genre - mais tout dépend de l'endroit où vous avez le contrôle pour modifier des éléments.

6
Rob Farley

J'ai trouvé cet article en train d'essayer de comprendre pourquoi j'ai gardé 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 généré une valeur hors limites.

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

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

Set the nullable property in the edmx file to **True**

4
stink

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

Vous trouverez ci-dessous un exemple concret d’un type incomplet DateTime à DateTime? ajustement qui soulève le comportement étrange

enter image description here

3
Julio Nobre

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

Pour trouver la solution, il y a deux façons.

  1. Pour utiliser le type de données datetime dans Entity Framwork 4, vous devez faire basculer ProviderManifestToken dans le fichier edmx sur "2005".
  2. Si vous définissez le champ correspondant sur Autoriser la valeur Null (le convertit en NULLABLE), EF utilise alors automatiquement les objets de date comme date-heure.
2
Mahmut C

Création d'une classe de base basée sur l'implémentation @ 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.)
 }
1
C0r3yh

Parfois, cela fonctionne très bien sur les machines de développement et non sur les serveurs. Dans mon cas je devais mettre:

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

Dans le fichier web.config.

Le fuseau horaire de la machine (Serveur) était correct (aux paramètres régionaux CO), mais l'application Web ne l'avait pas. Ce réglage effectué et cela a fonctionné bien à nouveau.

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

:RÉ

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 d'intervalle qu'une classe DateNet .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 les données de votre table).

0
marcolomew

Dans mon cas, nous avons enregistré une date sur une date et nous avons eu cette erreur. Ce qui se passe, c'est que Date a un minimum "plus orienté programmeur" du 01/01/0001, alors que Datetime est bloqué à 175

Combinez cela avec une erreur de collecte de données de notre part, et vous obtenez votre exception!

0
Chris

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

 public DateTime MyDate { get; set; }

Remplacer pour:

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

2) Nouveau la base de données à nouveau. Par exemple:

db=new MyDb();
0
MSM19

Ajouter 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"));
}
0
Howie Krauth