Преобразование типа данных datetime2 в тип данных datetime приводит к выходу за пределы допустимого значения


379

У меня есть таблица данных с 5 столбцами, где строка заполняется данными, а затем сохраняется в базе данных посредством транзакции.

При сохранении возвращается ошибка:

Преобразование типа данных datetime2 в тип данных datetime привело к значению вне допустимого диапазона

Из прочитанного следует, что моя таблица данных имеет тип DateTime2и базу данных a DateTime; это не правильно.

Столбец даты устанавливается DateTimeтак:

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

Вопрос

Это может быть решено в коде или что-то должно быть изменено на уровне базы данных?

Ответы:


60

Какие у вас даты в колонке?

Все они вписываются в диапазон типа?


Кроме того, правильный способ получить Typeобъект для DataColumnконструктора - это typeofключевое слово, которое на несколько порядков быстрее.

Поэтому, чтобы создать столбец, вы должны написать

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

3
Я изменил свои столбцы данных и использовал typeof сейчас ... Далее я нашел свою проблему. в 1 датарове содержалась неправильная дата, которая вызвала ошибку
Гербранд

739

Это может произойти, если вы не присвоите значение полю DateTime, когда поле не принимает значения NULL .

Это исправило это для меня!


43
В Entity Framework, если вы добавите столбец Created, который не равен NULL, то обновите свой EDMX, если вы не устанавливаете значение в коде, которое может вызвать эту ошибку таким образом
Брэд Томас,

6
Что это исправило для вас? Эта ошибка появляется, когда у вас есть поле datetime с вызовом getdate () в качестве значения по умолчанию.
user3046061

15
Почему Entity Framework не может игнорировать, если NULL, потому что на моей стороне SQL у меня есть значение по умолчанию = getdate ()?
JoshYates1980

33
Я верю, что это происходит, когда EntityFramework видит DateTime.MinValue, который является годом 0001, а в SQL datetime выходит за пределы диапазона, поэтому он отправляет это значение как значение DateTime2 (которое поддерживает год 0001), поэтому вставка / обновление допустимы, однако происходит сбой, когда SQL пытается преобразовать этот DateTime2 в DateTime, потому что это приведет к другому значению. Возможны два решения: 1 Использовать в вашей модели обнуляемую дату и время. 2. Инициализировать все значения даты и времени до правильного значения перед сохранением изменений контекста. Выбор, который вы делаете, зависит от значения даты и времени в вашей модели.
Гильермо Руффино

1
Решение @ GuillermoRuffino сработало для меня. Осмотрите все свои поля и найдите записи 0001 года.
Франческо Б.

158

Как DATETIMEи DATETIME2карту , чтобы System.DateTimeв .NET - вы не можете сделать «преобразования», так как это на самом деле тот же тип .NET.

См. Страницу документа MSDN: http://msdn.microsoft.com/en-us/library/bb675168.aspx.

Для этих двух значений есть два разных значения. SqlDbTypeМожете ли вы указать их в своем DataColumnопределении?

НО: на SQL Server поддерживаемый диапазон дат совсем другой.

DATETIMEподдерживает 1753/1/1 в «вечность» (9999/12/31), а DATETIME2поддерживает 0001/1/1 - в вечность.

Итак, что вам действительно нужно сделать, это проверить год даты - если это до 1753 года, вам нужно изменить его на что-то ПОСЛЕ 1753 года, чтобы DATETIMEстолбец в SQL Server мог его обработать.

Марк


7
Это объясняет проблему, которая у меня была. Хотя есть несколько ситуаций, когда нужно обрабатывать реальные даты до 1753/1/1, но есть много ситуаций, когда можно получить значение по умолчанию 0001/1/1, которое может привести к ошибке.
Hong

Я подтверждаю, что когда я пытался вставить «новый DateTime ()» в тип данных «datetime», я получил это исключение.
Джордж Онофрей

1
Я пытался присвоить значение по умолчанию DateTime.MinValue в моем коде C #, который записывал в базу данных. Это объясняет ошибку, которую я получал. +1
Мкалафут

Я использую Entity Framework Code First и использую модель со свойством DateTime. DtInit = new System.DateTime(1492, 10, 12),выходит из строя.
Kiquenet

Это одна из тех ситуаций, когда настоящая причина скрыта за патчем ... +1
Эудженио Миро,

41

В моей базе данных SQL Server 2008 у меня был DateTimeстолбец, помеченный как не обнуляемый, но с GetDate()функцией в качестве значения по умолчанию. При вставке нового объекта с использованием EF4 я получил эту ошибку, потому что я не передавал свойство DateTime в моем объекте явно. Я ожидал, что функция SQL будет обрабатывать дату для меня, но это не так. Моим решением было отправить значение даты из кода, а не полагаться на базу данных для ее генерации.

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

2
Рад помочь. Это раздражает, потому что вы думаете, что контекст данных EF сможет обнаружить, что поле имеет значение по умолчанию, когда объект создается из таблицы.
Грэм

Я бы много думал об EF. Я использую объекты самоконтроля POCO, и это такой кластер. Я собираюсь проверить код первой модели, и если он также полон бессмыслицы, я серьезно подумываю вернуться к linq to sql и использовать средство отображения объектов для сопоставления реквизитов с моими собственными сущностями ...

2
Я видел демо EF Code First на VS Live 2 недели назад, и это выглядело УДИВИТЕЛЬНО, кстати.
Грэм

Это хорошие новости. Мы скоро запускаем новый проект в моем офисе, и я разделен на EF-CF и dapper (используется / поддерживается SO). Вероятно, все сводится к тому, что лучше в приложении, которое используется через службу WCF.

1
Здравствуйте, летние комментарии! Я сам начинаю с EF Code-First и обнаружил, что в моем POCO мне просто нужно было определить свой элемент datetime как Nullable<DateTime>, и в коде я могу оставить это действительно нулевым (вместо 01.010000). Я был приятно удивлен, увидев, что EF to SQL знал, что игнорировать этот ноль в INSERT и использовать дату с сервера ( GetDate()) ... Для нас это было даже предпочтительнее, поскольку нам требовалась лучшая согласованность на сервере, не беспокоясь о разнице часов между веб-сервер и сервер SQL.
Funka

34

для меня это было потому, что дата была ..

01/01/0001 00:00:00

в этом случае вы хотите присвоить нулевой объект EF DateTime ... используя мой FirstYearRegistered код в качестве примера

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

Я анализирую эти данные с помощью ExcelDataReader, и он возвращает 01/01/0001 при вводе недопустимого текста (не выдает исключение, как ожидалось - с использованием метода .GetDateTime (columnIndex)). Сравнение с MinValue помогло предотвратить исключение вне диапазона в sql.
Томми

22

Этот сводил меня с ума. Я хотел избежать использования обнуляемой даты ( DateTime?). У меня не было возможности использовать datetime2тип SQL Server 2008 либо

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

В конце концов я выбрал следующее:

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
Используя [Column(TypeName = "datetime2")]?
Kiquenet

21

Иногда EF не знает, что имеет дело с вычисляемым столбцом или триггером . По замыслу эти операции будут устанавливать значение вне EF после вставки.

Исправление - указать Computedв EF edmxдля этого столбца в StoreGeneratedPatternсвойстве.

Для меня это было, когда в столбце был триггер, который вставил текущую дату и время, см. Ниже в третьем разделе.


Шаги для решения

В Visual Studio откройте Model Browserстраницу, Modelзатем Entity Types-> затем

  1. Выберите объект и свойство даты и времени
  2. Выбрать StoreGeneratedPattern
  3. Установлен в Computed

Диалоговое окно «Тип сущности модели обозревателя модели EF»


Для этой ситуации другие ответы - обходные пути, для столбца нужно указать время / дату, указанную при создании записи, и это задача SQL - выполнить триггер для добавления правильного времени. Например, этот триггер SQL:

DEFAULT (GETDATE()) FOR [DateCreated],


Обратите внимание, что я использовал, GETDATE()что я буквально сделал в то время. Но недавно был комментарий, который следует использовать SYSDATETIME()для любых операций DateTime2, которые я считаю верными.
ΩmegaMan

10

Я наткнулся на это и добавил следующее в свой объект datetime:

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

1
using System.ComponentModel.DataAnnotations.Schema; требуется
Kiquenet

9

Если мы не передадим поле даты в дату, будет передана дата по умолчанию {1/1/0001 12:00:00 AM}.

Но эта дата несовместима с работой фрейма сущности, поэтому она преобразует преобразование типа данных datetime2 в тип данных datetime, что приводит к значению вне допустимого диапазона.

Просто default DateTime.nowв поле даты, если вы не проходите ни одной даты.

movie.DateAdded = System.DateTime.Now

Я бы сказал, что передача DateTime.Now в качестве значения по умолчанию далека от правильности и вводит в заблуждение.
Бартош

6

Проще всего было бы изменить базу данных на использование datetime2 вместо datetime. Совместимость прекрасно работает, и вы не получите ошибок.

Вы все еще хотите сделать кучу тестирования ...

Ошибка, вероятно, связана с тем, что вы пытаетесь установить дату на год 0 или что-то еще, но все зависит от того, где у вас есть контроль, чтобы что-то изменить.


4

Я нашел этот пост, пытаясь понять, почему я продолжал получать следующую ошибку, которая объясняется другими ответами.

Преобразование типа данных datetime2 в тип данных datetime привело к значению вне допустимого диапазона.

Используйте обнуляемый объект DateTime.
общедоступный DateTime? PurchaseDate {get; набор; }

Если вы используете Entity Framework, установите для свойства nullable в файле edmx значение True.

Установите для свойства nullable в файле edmx значение ** True **


3

Как уже отмечал andyuk , это может произойти, когда значение NULL присваивается необнуляемому полю DateTime . Подумайте об изменении DateTime на DateTime? или Nullable < DateTime >. Имейте в виду, что в случае использования свойства зависимости также следует убедиться, что тип свойства зависимости также имеет тип DateTime, допускающий значение NULL.

Ниже приведен реальный пример неполного DateTime для DateTime? корректировка типа, которая вызывает странное поведение

введите описание изображения здесь


2

Entity Framework 4 работает с типом данных datetime2, поэтому в db соответствующее поле должно быть datetime2 для SQL Server 2008.

Для достижения решения есть два способа.

  1. Чтобы использовать тип данных datetime в Entity Framwork 4, вам необходимо переключить ProviderManifestToken в edmx-файле на «2005».
  2. Если вы установите соответствующее поле как Allow Null (оно преобразует его в NULLABLE), тогда EF автоматически использует объекты даты как datetime.

1
Я подобрал ваше второе замечание о моих моделях баз данных (классы POCO) и подумал, как установить поле в качестве обнуляемого типа. В случае, если кому-то интересно, вы можете сделать это, добавив знак вопроса (?) После типа даты. например публичный DateTime? StartTime {get; набор; } Это решило проблему для меня. Единственное, что мне нужно было сделать, - это поместить приведение TimeSpan вокруг строки кода, где я вычитал два обнуляемых значения DateTime друг из друга. например, var timeTaken = (TimeSpan) (endTime - startTime);
Кьяран Галлахер

1

Создан базовый класс на основе реализации @ sky-dev. Так что это может быть легко применено к нескольким контекстам и сущностям.

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

Применение:

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

Добавьте указанный ниже атрибут для свойства в классе вашей модели.

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

Изначально я забыл добавить этот атрибут. Так что в моей базе данных ограничение было создано как

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

и я добавил этот атрибут и обновил мой БД, то он был изменен на

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

[DatabaseGenerated (DatabaseGeneratedOption.Computed)]
Аджит Чандран

0

В моем случае мы приводили дату к дате и получили эту ошибку. Что происходит, так это то, что Date имеет «более ориентированный на программиста» минимум 01.01.0101, а Datetime застрял на 1753

Объедините это с ошибкой сбора данных с нашей стороны, и вы получите свое исключение!


Америка открывает в 1492 году, неправильно, если не использовать datetime2
Kiquenet

0

Иногда это прекрасно работает на машинах разработки, а не на серверах. В моем случае я должен был поставить:

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

В файле web.config.

Часовой пояс на компьютере (сервере) был правильным (в соответствии с локализацией CO), но веб-приложение - нет. Эта настройка выполнена, и она снова заработала нормально.

Конечно, все даты имели значение.

: D


0

Добавление этого кода в класс в ASP.NET сработало для меня:

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

0

Я знаю об этой проблеме, и вы все должны быть тоже

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

В SQL был создан новый тип поля, чтобы избежать этой проблемы (datetime2).

Этот тип поля «Дата» имеет те же значения диапазона, что и класс DateTime .Net. Это решит все ваши проблемы, поэтому я думаю, что лучший способ решить это - изменить тип столбца вашей базы данных (это не повлияет на данные вашей таблицы).


0

Проверьте следующие два: 1) Это поле не имеет значения NULL. Например:

 public DateTime MyDate { get; set; }

Заменить на:

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

2) Новая база данных снова. Например:

db=new MyDb();

Что если вы не хотите, чтобы значение было DateTime.Now по умолчанию?
Дикарь

Если вы не хотите: DateTime.Now. Вы можете использовать: новый DateTime (..., ..., ...)
RainyTears

0

Проблема с унаследованным атрибутом datetime

Это сообщение об ошибке часто отображается, когда поле даты без ненулевого значения имеет значение null во время вставки / обновления. Одной из причин может быть наследство.

Если ваша дата унаследована от базового класса, и вы не делаете отображение, EF не будет читать ее значение.

Для получения дополнительной информации: https://weblogs.asp.net/manavi/inheritance-mapping-strategies-with-entity-framework-code-first-ctp5-part-3-table-per-concrete-type-tpc-and- выбор-стратегии-принципы


0

Я увидел эту ошибку, когда хотел отредактировать страницу с помощью ASP.Net MVC. У меня не было проблем при создании, но обновление базы данных сделало мое свойство DateCreated вне диапазона!

Если вы не хотите, чтобы ваше DateTimeсвойство было Nullable, и не хотите проверять, находится ли его значение в диапазоне sql DateTime (и @Html.HiddenForэто не помогает!), Просто добавьте static DateTimeполе внутри связанного класса (Controller) и присвойте ему значение, когда GET работает, затем используйте его, когда POST делает свою работу:

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

Я столкнулся с этой проблемой в простом проекте консольного приложения, и мое быстрое решение - преобразовать любые возможные даты datetime2 в обнуляемую datetime, запустив этот метод:

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

Это, конечно, не совсем комплексный метод, но он работал для моих нужд, и, возможно, он поможет другим!


0

Проверьте формат req в БД. например, моя БД имеет значение по умолчанию или Binding(((1)/(1))/(1900))

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

введите описание изображения здесь


-1

у вас будет столбец даты, который был установлен как минимум значения минимальной разрешенной даты, например 1/1/1001.

Чтобы преодолеть эту проблему, вы можете установить правильное значение datetime, чтобы свойство urn также установило другое магическое свойство, например IsSpecified = true.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.