La conversione di un tipo di dati datetime2 in un tipo di dati datetime risulta fuori range


379

Ho un datatable con 5 colonne, in cui una riga viene riempita con i dati quindi salvata nel database tramite una transazione.

Durante il salvataggio, viene restituito un errore:

La conversione di un tipo di dati datetime2 in un tipo di dati datetime ha prodotto un valore fuori intervallo

Implica, come letto, che il mio datatable abbia un tipo di DateTime2e il mio database a DateTime; Questo è sbagliato.

La colonna della data è impostata in DateTimequesto modo:

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

Domanda

Questo può essere risolto nel codice o qualcosa deve essere cambiato a livello di database?

Risposte:


60

Che tipo di date hai nella colonna?

Si adattano tutti alla gamma del tipo?


A parte questo, il modo corretto di ottenere un Typeoggetto per il DataColumncostruttore è la typeofparola chiave, che è ordini di grandezza più veloci.

Pertanto, per creare la colonna, è necessario scrivere

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

3
Ho cambiato le mie colonne di dati e ho usato il tipo di ora ... Inoltre ho trovato il mio problema. c'era 1 datarow che conteneva una data sbagliata, che ha scatenato l'errore
Gerbrand,

739

Ciò può accadere se non si assegna un valore a un campo DateTime quando il campo non accetta valori NULL .

Questo mi ha risolto!


43
In Entity Framework, se aggiungi una colonna Creata che non è nulla, aggiorna il tuo EDMX, quando non stai impostando il valore nel codice, che può generare questo errore in questo modo
Brad Thomas

6
Cosa l'ha risolto per te? Questo errore appare quando si dispone di un campo datetime con una chiamata getdate () come valore predefinito.
user3046061

15
Perché Entity Framework non può ignorare se NULL perché sul mio lato SQL ho un valore predefinito = getdate ()?
JoshYates1980,

33
Quello che credo accada è che EntityFramework vede un DateTime.MinValue che è l'anno 0001 e in SQL datetime non è compreso nell'intervallo, quindi invia questo valore come un valore DateTime2 (che supporta l'anno 0001), quindi l'inserimento / aggiornamento è valido, tuttavia non riesce quando SQL tenta di convertire questo DateTime2 in un DateTime perché ciò comporterà un valore diverso. Due soluzioni sono: 1 Utilizzare un datetime nullable nel modello o 2. inizializzare tutti i valori datetime, sul valore corretto prima di salvare le modifiche al contesto. La scelta effettuata dipende dal significato del datetime nel modello.
Guillermo Ruffino,

1
La soluzione di @ GuillermoRuffino ha funzionato per me. Ispeziona tutti i tuoi campi e trova quelle voci per l'anno 0001.
Francesco B.

158

Sia l' DATETIMEe DATETIME2mappare a System.DateTimeNET - non si può davvero fare una "conversione", dal momento che è in realtà lo stesso tipo di .NET.

Vedi la pagina del documento MSDN: http://msdn.microsoft.com/en-us/library/bb675168.aspx

Esistono due valori diversi per " SqlDbType" per questi due: puoi specificare quelli nella tua DataColumndefinizione?

MA: su SQL Server, l'intervallo di date supportato è piuttosto diverso.

DATETIMEsupporta il 1753/1/1 fino all'eternità (9999/12/31), mentre DATETIME2supporta il 0001/1/1 fino all'eternità.

Quindi quello che devi veramente fare è controllare l'anno della data - se è prima del 1753, devi cambiarlo in qualcosa DOPO il 1753 affinché la DATETIMEcolonna in SQL Server possa gestirlo.

Marc


7
Questo spiega il problema che ho avuto. Sebbene ci siano poche situazioni in cui è necessario gestire date reali prima del 1753/1/1, ma ci sono molte situazioni in cui si ottiene il valore predefinito 0001/1/1 che può causare l'errore.
Hong

Confermo che quando stavo cercando di inserire un 'nuovo DateTime ()' in un tipo di dati 'datetime' ho ricevuto questa eccezione.
George Onofrei

1
Stavo cercando di assegnare un valore predefinito di DateTime.MinValue nel mio codice C # che ha scritto su un database. Questo spiega l'errore che stavo riscontrando. +1
Mkalafut,

Uso First Entity Framework Code e utilizzo il modello con la proprietà DateTime. DtInit = new System.DateTime(1492, 10, 12),non riesce.
Kiquenet,

Questa è una di quelle situazioni in cui il vero motivo è nascosto dietro la patch ... +1
Eugenio Miró

41

Nel mio database di SQL Server 2008, avevo una DateTimecolonna contrassegnata come non nullable, ma con una GetDate()funzione come valore predefinito. Quando ho inserito un nuovo oggetto usando EF4, ho ricevuto questo errore perché non stavo trasmettendo esplicitamente una proprietà DateTime sul mio oggetto. Mi aspettavo che la funzione SQL gestisse la data per me, ma non è così. La mia soluzione era di inviare il valore della data dal codice invece di fare affidamento sul database per generarlo.

obj.DateProperty = DateTime.now; // C#

2
Felice di aiutare. È fastidioso perché penseresti che il contesto dei dati EF sarebbe in grado di scoprire che il campo ha un valore predefinito quando l'oggetto viene creato dalla tabella.
Graham,

Penserei un sacco di cose su EF. Sto usando le entità di auto-tracking POCO ed è un tale cluster. Vado a controllare il primo modello di codice, e se anche quello è pieno di sciocchezze sto seriamente pensando di tornare a linq a sql e usare un mappatore di oggetti per mappare oggetti di scena alle mie entità ...

2
Ho visto una demo di EF Code First su VS Live 2 settimane fa e sembrava FANTASTICO, a proposito.
Graham,

Questa è una buona notizia. Presto inizieremo un nuovo progetto nel mio ufficio e sono diviso su EF-CF e dapper (usato / gestito da SO). Probabilmente si riduce a quale è meglio in un'app utilizzata tramite un servizio WCF.

1
Ciao, commenti di un anno! Io stesso sto iniziando con EF Code-First e ho scoperto che sul mio POCO avevo solo bisogno di definire il mio membro datetime come Nullable<DateTime>, e nel codice posso lasciarlo veramente nullo (invece del 01/01/0000). Sono stato piacevolmente sorpreso di vedere che EF to SQL sapeva ignorare questo null sull'INSERTO e usare la data dal server ( GetDate()) ... Per noi questo era persino preferibile poiché avevamo bisogno di una migliore coerenza sul server, senza preoccuparci delle differenze di clock tra il server web e quello del server sql.
Funka,

34

per me è stato perché il datetime era ..

01/01/0001 00:00:00

in questo caso vuoi assegnare null al tuo oggetto EF DateTime ... usando il mio codice FirstYearRegistered come esempio

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

Sto analizzando questi dati utilizzando ExcelDataReader e restituisce il 01/01/0001 quando è stato inserito un testo non valido (non genera un'eccezione come previsto - utilizzando il metodo .GetDateTime (columnIndex)). Il confronto con MinValue ha fatto il trucco per evitare l'eccezione fuori range in sql.
Tommy,

22

Questo mi stava facendo impazzire. Volevo evitare di usare una data / ora nullable ( DateTime?). Non avevo nemmeno la possibilità di usare il datetime2tipo di SQL Server 2008

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

Alla fine ho optato per il seguente:

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

1
Usando [Column(TypeName = "datetime2")]?
Kiquenet,

21

A volte EF non sa che ha a che fare con una colonna calcolata o un trigger . In base alla progettazione, tali operazioni imposteranno un valore esterno a EF dopo un inserimento.

La correzione è specificare Computedin EF edmxper quella colonna nella StoreGeneratedPatternproprietà.

Per me è stato quando la colonna ha avuto un trigger che ha inserito la data e l'ora correnti, vedi sotto nella terza sezione.


I passaggi per risolvere

In Visual Studio aprire la Model Browserpagina Modelquindi Entity Types-> quindi

  1. Seleziona l'entità e la proprietà data e ora
  2. Selezionare StoreGeneratedPattern
  3. Impostato Computed

Finestra di dialogo Tipo entità modello browser modello EF


Per questa situazione, altre risposte sono soluzioni alternative, allo scopo della colonna è di avere una data / ora specificata quando è stato creato il record e che è il lavoro di SQL eseguire un trigger per aggiungere l'ora corretta. Come questo trigger SQL:

DEFAULT (GETDATE()) FOR [DateCreated].


Si noti che avevo usato ciò GETDATE()che ho letteralmente fatto in quel momento. Ma c'è stato un commento recente che si dovrebbe usare SYSDATETIME()per qualsiasi operazione DateTime2 che credo sia vera.
ΩmegaMan,

10

Mi sono imbattuto in questo e ho aggiunto quanto segue alla mia proprietà datetime:

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

1
using System.ComponentModel.DataAnnotations.Schema; è richiesto
Kiquenet il

9

Se non passiamo un campo da ora data a ora data, verrà passata la data predefinita {1/1/0001 12:00:00 AM}.

Ma questa data non è compatibile con il lavoro del frame di entità, quindi genererà una conversione di un tipo di dati datetime2 in un tipo di dati datetime risultante in un valore fuori intervallo

Solo default DateTime.nowal campo della data se non si passa alcuna data.

movie.DateAdded = System.DateTime.Now

Direi che passare 'DateTime.Now' come valore predefinito è lungi dall'essere corretto ed è piuttosto fuorviante.
Bartosz,

6

La cosa più semplice sarebbe cambiare il tuo database per usare datetime2 invece di datetime. La compatibilità funziona bene e non otterrai errori.

Avrai ancora voglia di fare un sacco di test ...

L'errore è probabilmente perché stai cercando di impostare una data sull'anno 0 o qualcosa del genere, ma tutto dipende da dove hai il controllo per cambiare le cose.


4

Ho trovato questo post cercando di capire perché continuavo a ricevere il seguente errore, spiegato dalle altre risposte.

La conversione di un tipo di dati datetime2 in un tipo di dati datetime ha prodotto un valore fuori range.

Utilizzare un oggetto DateTime nullable.
public DateTime? PurchaseDate {get; impostato; }

Se si utilizza il framework di entità Impostare la proprietà nullable nel file edmx su True

Impostare la proprietà nullable nel file edmx su ** True **


3

Come ha già sottolineato Andyuk , ciò può accadere quando un valore NULL è assegnato a un campo DateTime non annullabile . Considerare di modificare DateTime in DateTime? o Nullable < DateTime >. Tenere presente che, nel caso in cui si utilizzi una proprietà di dipendenza , è necessario assicurarsi che anche il tipo di proprietà di dipendenza sia un tipo DateTime nullable.

Di seguito è riportato un esempio di vita reale di un DateTime to DateTime incompleto ? regolazione del tipo che aumenta il comportamento strano

inserisci qui la descrizione dell'immagine


2

Entity Framework 4 funziona con il tipo di dati datetime2, quindi in db il campo corrispondente deve essere datetime2 per SQL Server 2008.

Per raggiungere la soluzione ci sono due modi.

  1. Per utilizzare il tipo di dati datetime in Entity Framwork 4, è necessario impostare ProviderManifestToken nel file edmx su "2005".
  2. Se imposti il ​​campo corrispondente come Consenti null (lo converte in NULLABLE), quindi EF utilizza automaticamente gli oggetti data come datetime.

1
Ho raccolto il tuo secondo punto per i miei modelli di database (classi POCO) e mi chiedevo come impostare un campo come tipo nullable. Nel caso qualcuno si chiedesse, puoi farlo aggiungendo un punto interrogativo (?) Dopo il tipo di data. es. DateTime pubbliche? StartTime {get; impostato; } Questo ha risolto il problema per me. L'unica altra cosa che dovevo fare era mettere un cast di TimeSpan attorno a una riga di codice in cui sottraevo due valori DateTime nullable l'uno dall'altro. es. var timeTaken = (TimeSpan) (endTime - startTime);
Ciaran Gallagher,

1

Creata una classe base basata sull'implementazione di @ sky-dev. Quindi questo può essere facilmente applicato a più contesti ed entità.

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.)
 }

1

Aggiungere l'attributo di seguito indicato sulla proprietà nella classe del modello.

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

Inizialmente ho dimenticato di aggiungere questo attributo. Quindi nel mio database il vincolo è stato creato come

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

e ho aggiunto questo attributo e aggiornato il mio db quindi è stato modificato in

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

[DatabaseGenerated (DatabaseGeneratedOption.Computed)]
Ajith Chandran,


0

A volte funziona bene su macchine di sviluppo e non su server. Nel mio caso ho dovuto mettere:

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

Nel file web.config.

Il fuso orario nella macchina (Server) era corretto (rispetto alle impostazioni internazionali di CO), ma l'app Web no. Questa impostazione è stata eseguita e ha funzionato di nuovo bene.

Ovviamente, tutte le date avevano un valore.

: D


0

L'aggiunta di questo codice a una classe in ASP.NET ha funzionato per me:

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

0

Sono consapevole di questo problema e dovresti esserlo anche tu:

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

In SQL è stato creato un nuovo tipo di campo per evitare questo problema (datetime2).

Questo tipo di campo "Data" ha gli stessi valori di intervallo di una classe .Net DateTime. Risolverà tutti i tuoi problemi, quindi penso che il modo migliore per risolverlo sia cambiare il tipo di colonna del database (non influirà sui dati della tabella).


0

Dai un'occhiata ai seguenti due: 1) Questo campo non ha valore NULL. Per esempio:

 public DateTime MyDate { get; set; }

Sostituisci con:

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

2) Nuovo di nuovo il database. Per esempio:

db=new MyDb();

Cosa succede se non si desidera che il valore sia DateTime.Now per impostazione predefinita?
Savage

Se non vuoi: DateTime.Now. Puoi usare: nuovo DateTime (..., ..., ...)
RainyTears,

0

Problema con l'attributo datetime ereditato

Questo messaggio di errore viene spesso visualizzato quando un campo data non annullabile ha valore null al momento dell'inserimento / aggiornamento. Una causa può essere l'eredità.

Se la tua data è ereditata da una classe base e non esegui una mappatura EF non leggerà il suo valore.

Per maggiori informazioni: https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and- scegliendo-strategia-linee guida


0

Ho visto questo errore quando volevo modificare una pagina usando ASP.Net MVC. Non ho avuto problemi durante la creazione ma l'aggiornamento del database ha reso la mia proprietà DateCreated fuori portata!

Quando non vuoi che la tua DateTimeproprietà sia Nullable e non desideri verificare se il suo valore è compreso nell'intervallo sql DateTime (e @Html.HiddenFornon aiuta!), Aggiungi semplicemente un static DateTimecampo all'interno della classe correlata (Controller) e assegnagli il valore quando GET è in funzione, quindi usalo quando POST sta facendo il suo lavoro:

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");

    }
}

0

Ho riscontrato questo problema in un semplice progetto di app per console e la mia soluzione rapida è convertire tutte le possibili date datetime2 in un datetime nullable eseguendo questo metodo:

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

Questo non è certamente un metodo completamente completo, ma ha funzionato per le mie esigenze e forse aiuterà gli altri!


0

Controllare il formato req in DB. ad es. il mio DB ha un valore predefinito o Binding(((1)/(1))/(1900))

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

inserisci qui la descrizione dell'immagine


-1

avrai la colonna della data che è stata impostata su lesathan il valore minimo del periodo di tempo consentito come 1/1/1001.

per ovviare a questo problema è possibile impostare il valore datetime corretto su ur proprietà e anche impostare un'altra proprietà magica come IsSpecified = true.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.