A conversão de um tipo de dados datetime2 para um tipo de dados datetime resulta em um valor fora do intervalo

379

Eu tenho uma tabela de dados com 5 colunas, onde uma linha está sendo preenchida com dados e salva no banco de dados por meio de uma transação.

Ao salvar, um erro é retornado:

A conversão de um tipo de dados datetime2 em um tipo de dados datetime resultou em um valor fora do intervalo

Implica, conforme lido, que minha tabela de dados tenha um tipo de DateTime2e meu banco de dados a DateTime; isso esta errado.

A coluna da data é configurada DateTimecomo esta:

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

Questão

Isso pode ser resolvido no código ou algo precisa ser alterado no nível do banco de dados?

Gerbrand
fonte

Respostas:

60

Que tipo de datas você tem na coluna?

Todos eles se encaixam dentro do intervalo do tipo?


Como um aparte, a maneira correta de obter um Typeobjeto para o DataColumnconstrutor é a typeofpalavra - chave, que é uma ordem de magnitude mais rápida.

Portanto, para criar a coluna, você deve escrever

new DataColumn("myDate", typeof(DateTime))
SLaks
fonte
3
Alterei minhas colunas de dados e usei typeof agora ... Além disso, encontrei meu problema. havia 1 datarow que continha uma data errada, o que provocou o erro
Gerbrand
739

Isso pode acontecer se você não atribuir um valor a um campo DateTime quando o campo não aceitar valores NULL .

Isso consertou para mim!

andyuk
fonte
43
Em Entity Framework, se você adicionar um Criado coluna que não é nulo, então atualizar seu EDMX, quando você não está definindo o valor em código, que pode jogar esse erro desta forma
Brad Thomas
6
O que foi corrigido para você? Este erro aparece quando você tem um campo de data e hora com uma chamada getdate () como valor padrão.
user3046061
15
Por que o Entity Framework não pode ignorar se NULL porque, no meu lado SQL, tenho um valor padrão = getdate ()?
precisa saber é o seguinte
33
O que eu acredito que isso acontece é que EntityFramework vê um DateTime.MinValue que é o ano 0001 e no datetime do SQL está fora do valor do intervalo, então ele envia esse valor como um valor DateTime2 (que suporta o ano 0001) para que a inserção / atualização seja válida. falha quando o SQL tenta converter este DateTime2 em um DateTime porque isso resultará em um valor diferente. Duas soluções são: 1 Use um datetime nulo no seu modelo ou 2. inicialize todos os seus valores de datetime, com o valor correto antes de salvar as alterações de contexto. A escolha que você faz depende do que a data e hora significa no seu modelo.
Guillermo Ruffino
11
A solução do @ GuillermoRuffino funcionou para mim. Inspecione todos os seus campos e encontre essas entradas de 0001 anos.
Francesco B.
158

Tanto o DATETIMEe DATETIME2mapa paraSystem.DateTime no .NET - você realmente não pode fazer uma "conversão", pois é realmente o mesmo tipo .NET.

Consulte a página de documento do MSDN: http://msdn.microsoft.com/en-us/library/bb675168.aspx

Existem dois valores diferentes para " SqlDbType" para esses dois - você pode especificar aqueles em seuDataColumn definição?

MAS: no SQL Server, o período suportado é bem diferente.

DATETIME suporta 1753/1/1 à "eternidade" (9999/12/31), enquanto DATETIME2 suporta 0001/1/1 por toda a eternidade.

Portanto, o que você realmente precisa fazer é verificar o ano da data - se for antes de 1753, será necessário alterá-lo para algo após o 1753 para que o DATETIME coluna no SQL Server possa lidar com isso.

Marc

marc_s
fonte
7
Isso explica o problema que eu tive. Embora existam poucas situações em que datas reais anteriores a 1753/1/1 precisem ser manipuladas, há muitas situações em que se obtém o valor padrão 0001/1/1 que pode resultar no erro.
Hong
Confirmo que, quando estava tentando inserir um 'novo DateTime ()' em um tipo de dados 'datetime', recebi essa exceção.
George Onofrei
11
Eu estava tentando atribuir um valor padrão de DateTime.MinValue no meu código C # que gravou em um banco de dados. Isso explica o erro que eu estava recebendo. +1
Mkalafut
Eu uso o Entity Framework Code First e o modelo com a propriedade DateTime. DtInit = new System.DateTime(1492, 10, 12),falha.
Kiquenet
Esta é uma daquelas situações em que o verdadeiro motivo está oculto por trás do patch ... +1
Eugenio Miró
41

No meu banco de dados do SQL Server 2008, eu tinha uma DateTimecoluna sinalizada como não anulável, mas com uma GetDate()função como seu valor padrão. Ao inserir um novo objeto usando o EF4, recebi esse erro porque não estava passando uma propriedade DateTime no meu objeto explicitamente. Eu esperava que a função SQL manipulasse a data para mim, mas isso não aconteceu. Minha solução foi enviar o valor da data do código em vez de confiar no banco de dados para gerá-lo.

obj.DateProperty = DateTime.now; // C#
Graham
fonte
2
Feliz em ajudar. É irritante porque você acha que o contexto de dados EF poderá descobrir que o campo tem um valor padrão quando o objeto é criado a partir da tabela.
Graham
Eu pensaria muitas coisas sobre a EF. Estou usando as entidades de rastreamento automático do POCO e é um cluster. Vou verificar o primeiro modelo de código e, se isso também estiver cheio de bobagens, estou pensando seriamente em voltar ao linq to sql e usar um mapeador de objetos para mapear adereços para minhas próprias entidades ...
2
Vi uma demonstração do EF Code First no VS Live há duas semanas e parecia INCRÍVEL, aliás.
Graham
Boas notícias. Em breve, iniciaremos um novo projeto no meu escritório, e eu estou dividido no EF-CF e napper (usado / mantido pelo SO). Provavelmente será melhor em um aplicativo usado por meio de um serviço WCF.
11
Olá, comentários de um ano! Eu mesmo estou começando com o EF Code-First e descobri que no meu POCO eu só precisava definir meu membro datetime como Nullable<DateTime>e, no código, posso deixar isso verdadeiramente nulo (em vez de 01/01/0000). Fiquei agradavelmente surpreso ao ver que o EF para o SQL sabia ignorar esse nulo no INSERT e usar a data do servidor ( GetDate()) ... Para nós, isso era preferível, já que precisávamos de melhor consistência no servidor, sem nos preocuparmos com as diferenças de clock entre o servidor da web e o do servidor sql.
Funka
34

para mim foi porque a data e hora eram ..

01/01/0001 00:00:00

nesse caso, você deseja atribuir nulo a você Objeto EF DateTime ... usando meu código FirstYearRegistered como exemplo

DateTime FirstYearRegistered = Convert.ToDateTime(Collection["FirstYearRegistered"]);
if (FirstYearRegistered != DateTime.MinValue)
{
    vehicleData.DateFirstReg = FirstYearRegistered;
}  
JGilmartin
fonte
Estou analisando esses dados usando ExcelDataReader e retornando 01/01/0001 quando um texto inválido foi inserido (não gera uma exceção conforme o esperado - usando o método .GetDateTime (columnIndex)). A comparação com o MinValue fez o truque para evitar a exceção fora do intervalo no sql.
Tommy
22

Este estava me deixando louco. Eu queria evitar o uso de uma data e hora anulável ( DateTime?). Eu também não tinha a opção de usar o datetime2tipo do SQL Server 2008

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

Acabei optando pelo seguinte:

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
fonte
11
Usando [Column(TypeName = "datetime2")]?
Kiquenet
21

Às vezes, a EF não sabe que está lidando com uma coluna computada ou um gatilho . Por design, essas operações definirão um valor fora do EF após uma inserção.

A correção é especificar Computednos EFs edmxpara essa coluna na StoreGeneratedPatternpropriedade

Para mim, foi quando a coluna teve um gatilho que inseriu a data e hora atuais, veja abaixo na terceira seção.


Etapas para resolver

No Visual Studio, abra a Model Browserpágina e Modeldepois Entity Types-> então

  1. Selecione a entidade e a propriedade de data e hora
  2. Selecione StoreGeneratedPattern
  3. Definido como Computed

Caixa de diálogo EF Model Browser Model Entity Type


Para essa situação, outras respostas são soluções alternativas, pois o objetivo da coluna é ter uma hora / data especificada quando o registro foi criado, e essa é a tarefa do SQL executar um gatilho para adicionar a hora correta. Como este gatilho SQL:

DEFAULT (GETDATE()) FOR [DateCreated].

ΩmegaMan
fonte
Note que eu tinha usado o GETDATE()que literalmente fiz na época. Mas houve um comentário recente que se deve usar SYSDATETIME()para qualquer operação DateTime2 que eu acredite ser verdadeira.
EgamegaMan
10

Encontrei isso e adicionei o seguinte à minha propriedade datetime:

 [Column(TypeName = "datetime2")]
 public DateTime? NullableDateTimePropUtc { get; set; }
Rogala
fonte
11
using System.ComponentModel.DataAnnotations.Schema; é necessário
Kiquenet
9

Se não passarmos um campo de data e hora, a data padrão {1/1/0001 12:00:00} será aprovada.

Mas essa data não é compatível com o trabalho de estrutura de entidade, portanto, ela lançará conversão de um tipo de dados datetime2 para um tipo de dados datetime, resultando em um valor fora do intervalo

Apenas default DateTime.nowno campo da data, se você não estiver passando nenhuma data.

movie.DateAdded = System.DateTime.Now
Lijo
fonte
Eu diria que passar 'DateTime.Now' como um valor padrão está longe de estar correto e é bastante enganador.
Bartosz
6

O mais fácil seria alterar seu banco de dados para usar datetime2 em vez de datetime. A compatibilidade funciona bem e você não receberá seus erros.

Você ainda vai querer fazer vários testes ...

O erro é provavelmente porque você está tentando definir uma data para o ano 0 ou algo assim - mas tudo depende de onde você tem controle para alterar as coisas.

Rob Farley
fonte
4

Eu encontrei este post tentando descobrir por que eu continuava recebendo o seguinte erro, explicado pelas outras respostas.

A conversão de um tipo de dados datetime2 em um tipo de dados datetime resultou em um valor fora do intervalo.

Use um objeto DateTime anulável.
DateTime público? PurchaseDate {get; conjunto; }

Se você estiver usando a estrutura da entidade, defina a propriedade anulável no arquivo edmx como True

Defina a propriedade anulável no arquivo edmx como ** True **

fedor
fonte
3

Como o andyuk já apontou, isso pode acontecer quando um valor NULL é atribuído a um campo DateTime não anulável . Considere alterar DateTime para DateTime? ou Anulável < DateTime >. Lembre-se de que, caso você esteja usando uma propriedade de dependência , verifique também se o tipo da propriedade de dependência também é do tipo DateTime que pode ser nulo.

Abaixo está um exemplo da vida real de um DateTime incompleto para DateTime? ajuste de tipo que aumenta o comportamento ímpar

insira a descrição da imagem aqui

Julio Nobre
fonte
2

O Entity Framework 4 trabalha com o tipo de dados datetime2, portanto, em db, o campo correspondente deve ser datetime2 para o SQL Server 2008.

Para obter a solução, existem duas maneiras.

  1. Para usar o tipo de dados datetime no Entity Framwork 4, é necessário alternar o ProviderManifestToken no arquivo edmx para "2005".
  2. Se você definir o campo correspondente como Permitir Nulo (ele será convertido em NULLABLE), o EF utilizará automaticamente os objetos de data como data e hora.
Mahmut C
fonte
11
Peguei seu segundo ponto para meus modelos de banco de dados (classes POCO) e me perguntei como definir um campo como um tipo que permite valor nulo. Caso alguém se pergunte, você pode fazer isso adicionando um ponto de interrogação (?) Após o tipo de data. por exemplo, DateTime público? StartTime {get; conjunto; } Isso resolveu o problema para mim. Apenas outra coisa que tive que fazer foi colocar um TimeSpan convertido em torno de uma linha de código em que subtraí dois valores DateTime anuláveis ​​um do outro. por exemplo, var timeTaken = (TimeSpan) (endTime - startTime);
Ciaran Gallagher
1

Criou uma classe base com base na implementação @ sky-dev. Portanto, isso pode ser facilmente aplicado a vários contextos e 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
fonte
1

Adicione o atributo abaixo mencionado na propriedade na sua classe de modelo.

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

Inicialmente eu esqueci de adicionar este atributo. Então, no meu banco de dados, a restrição foi criada como

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

e eu adicionei esse atributo e atualizei meu banco de dados, depois ele foi alterado para

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

Às vezes, funciona bem em máquinas de desenvolvimento e não em servidores. No meu caso, eu tive que colocar:

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

No arquivo web.config.

O fuso horário na máquina (Servidor) estava correto (no local CO), mas o aplicativo Web não. Essa configuração foi concluída e funcionou bem novamente.

Obviamente, todas as datas tinham valor.

: D

Jaime Enrique Espinosa Reyes
fonte
0

A adição desse código a uma classe no ASP.NET funcionou para mim:

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

Estou ciente desse problema e vocês também devem estar:

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

No SQL, um novo tipo de campo foi criado para evitar esse problema (datetime2).

Esse tipo de campo 'Data' tem os mesmos valores de intervalo que uma classe .net DateTime. Como resolverá todos os seus problemas, acho que a melhor maneira de resolvê-lo é alterar o tipo de coluna do banco de dados (não afetará os dados da tabela).

marcolomew
fonte
0

Confira os dois seguintes: 1) Este campo não possui valor NULL. Por exemplo:

 public DateTime MyDate { get; set; }

Substitua para:

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

2) Novo banco de dados novamente. Por exemplo:

db=new MyDb();
RainyTears
fonte
E se você não quiser que o valor seja DateTime.Now por padrão?
Savage
Se você não quiser: DateTime.Now. Você pode usar: new DateTime (..., ..., ...)
RainyTears
0

Problema com o atributo datetime herdado

Essa mensagem de erro geralmente é mostrada quando um campo de data não anulável tem valor nulo no momento da inserção / atualização. Uma causa pode ser herança.

Se sua data é herdada de uma classe base e você não faz um mapeamento, a EF não lerá seu valor.

Para obter mais informações: https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and- escolhendo-diretrizes-estratégicas

FrankyHollywood
fonte
0

Vi esse erro quando quis editar uma página usando o ASP.Net MVC. Não tive nenhum problema durante a criação, mas a atualização do banco de dados tornou minha propriedade DateCreated fora do intervalo!

Quando você não deseja que sua DateTimepropriedade seja anulável e não deseja verificar se seu valor está no intervalo DateTime sql (e @Html.HiddenFornão ajuda!), Basta adicionar um static DateTimecampo dentro da classe relacionada (Controller) e fornecer o valor quando GET está funcionando e use-o quando o POST estiver executando seu trabalho:

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
fonte
0

Eu deparei com esse problema em um projeto de aplicativo de console simples e minha solução rápida é converter todas as datas possíveis datetime2 em um datetime nulo, executando 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;
        }
    }

Esse certamente não é um método completamente abrangente, mas funcionou para minhas necessidades e talvez ajude outras pessoas!

David Alan Condit
fonte
0

Verifique o formato req no DB. por exemplo, meu banco de dados tem valor padrão ou vinculação(((1)/(1))/(1900))

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

insira a descrição da imagem aqui

Arsalan Maqsood
fonte
-1

você terá a coluna de data que foi configurada para determinar o valor mínimo do tempo de duração permitido, como 1/1/1001.

Para superar esse problema, você pode definir o valor de data e hora adequado para sua propriedade e também definir outra propriedade mágica como IsSpecified = true.

Koteshwar
fonte