Перетворення типу даних 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 ви додали стовпець «Створений», який не є нульовим, то оновіть свій EDMX, коли ви не встановлюєте значення в коді, що може призвести до цієї помилки таким чином
Бред Томас,

6
Що це зафіксувало для вас? Ця помилка з’являється, коли у вас є поле дати з датою дзвінка getdate () як значення за замовчуванням.
користувач3046061

15
Чому Entity Framework не може ігнорувати, якщо NULL, оскільки на моєму SQL, у мене є значення за замовчуванням = getdate ()?
JoshYates1980

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

1
@ Рішення ГільєрмоРуффіно працювало на мене. Перевірте всі ваші поля та знайдіть ці записи в 0001 рік.
Франческо Б.

158

І те, DATETIMEі DATETIME2карту System.DateTimeв .NET - реально не можна "перетворити", оскільки це дійсно той самий тип .NET.

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

Є два різних значення для " SqlDbType" для цих двох - чи можете ви вказати їх у своєму DataColumnвизначенні?

АЛЕ: на SQL сервері підтримуваний діапазон дат зовсім інший.

DATETIMEпідтримує 1753/1/1 до "вічності" (9999/12/31), тоді як DATETIME2підтримує 0001/1/1 через вічність.

Отже, що вам потрібно зробити, це перевірити рік дати - якщо це до 1753 року, вам потрібно змінити його на щось ПІСЛЯ 1753, щоб DATETIMEстовпець на SQL Server обробляв його.

Марк


7
Це пояснює проблему, яку я мав. Хоча є кілька ситуацій, коли реальні дати до 1753/1/1 потребують обробки, але є багато ситуацій, коли людина отримує значення за замовчуванням 0001/1/1, що може призвести до помилки.
Гонг

Я підтверджую, що коли я намагався вставити "новий DateTime ()" у тип даних "datetime", я отримав це виключення.
Джордж Онофрей

1
Я намагався призначити значення за замовчуванням DateTime.MinValue у своєму коді C #, який записав у базу даних. Це пояснює помилку, яку я отримував. +1
Мкалафут

Спочатку я використовую Entity Framework Code і використовую модель із властивістю DateTime. DtInit = new System.DateTime(1492, 10, 12),не вдається.
Кікенет

Це одна з тих ситуацій, коли справжня причина ховається за патчем ... +1
Eugenio Miró

41

У моїй базі даних SQL Server 2008 у мене був DateTimeстовпець, позначений як не нульовий, але з GetDate()функцією як його значення за замовчуванням. Під час вставлення нового об’єкта за допомогою EF4 я отримав цю помилку, оскільки я не передав властивість DateTime на мій об'єкт явно. Я очікував, що функція SQL буде обробляти дату для мене, але вона цього не зробила. Моє рішення полягало в тому, щоб надіслати значення дати з коду, а не покладатися на базу даних для її генерації.

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

2
Радий допомогти. Це дратує, оскільки ви можете подумати, що контекст даних EF зможе виявити, що поле має значення за замовчуванням, коли об’єкт створюється з таблиці.
Грем

Я думаю, що багато чого про EF. Я використовую об'єкти самовідстеження POCO, і це такий кластер. Я збираюся перевірити першу модель коду, і якщо це теж повна дурниця, я серйозно замислююся про те, щоб повернутися до linq до sql та використовувати картографічний об’єкт для картографування реквізитів для моїх власних сутностей ...

2
Я побачив демонстрацію коду EF спершу в VS Live 2 тижні тому, і це виглядало ДУЖЕ, btw.
Грем

Це гарна новина. Ми незабаром починаємо новий проект у моєму офісі, і я розділений на EF-CF та Dapper (використовуваний / підтримуваний SO). Напевно, це дійде до того, що краще в додатку, який використовується через сервіс WCF.

1
Привіт, річні коментарі! Я сам починаю з коду EF-First і виявив, що в моєму POCO мені просто потрібно було визначити мого учасника дати як Nullable<DateTime>, і в коді я можу залишити це справді нульовим (замість 01.01.20000). Я був приємно здивований, побачивши, що EF до SQL знав ігнорувати цю нуль на INSERT та використовувати дату з сервера ( GetDate()) ... Для нас це було навіть кращим, оскільки нам потрібна була краща послідовність на сервері, не турбуючись про різниці годин між веб-сервер і сервер sql.
Funka

34

для мене це було, тому що дата була ..

01.01.10001 00:00:00

у цьому випадку ви хочете призначити вам null об’єкт EF DateTime ..., використовуючи мій код FirstYearRegistered як приклад

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

Я аналізую ці дані за допомогою ExcelDataReader, і він повертається 01.01.2001, коли був введений недійсний текст (не викидає виняток, як очікувалося - за допомогою методу .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")]?
Кікенет

21

Іноді EF не знає, що має справу з обчисленою колоною або тригером . За задумом ці операції встановлюють значення поза EF після вставки.

Виправлення полягає в тому, щоб вказати Computedв EF edmxдля цього стовпця у StoreGeneratedPatternвластивості.

Для мене це було тоді, коли стовпець мав тригер, який вставляв поточну дату та час, див. Нижче в третьому розділі.


Кроки для вирішення

У візуальній студії відкрийте Model Browserсторінку, Modelпотім Entity Types-> потім

  1. Виберіть об'єкт та властивість часу
  2. Виберіть StoreGeneratedPattern
  3. Встановлений в Computed

Діалогове вікно типу браузера моделі моделі EF


У цій ситуації інші відповіді є обхідними, для цього стовпець повинен мати час / дату, вказану під час створення запису, і це завдання SQL виконати тригер, щоб додати правильний час. Такий, як цей тригер SQL:

DEFAULT (GETDATE()) FOR [DateCreated].


Зауважте, що я використовував те, GETDATE()що я буквально робив у той час. Але нещодавно з'явився коментар, який слід використовувати SYSDATETIME()для будь-яких операцій DateTime2, які я вважаю правдивими.
ΩmegaMan

10

Я зіткнувся з цим і додав у свій власний час дату наступне:

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

1
using System.ComponentModel.DataAnnotations.Schema; потрібно
Кіквенет

9

Якщо ми не передамо поле дати дати в полі часу, дата за замовчуванням {1/1/0001 00: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 {отримати; набір; }

Якщо ви використовуєте структуру сутності, встановіть для властивості nullable у файлі edmx значення True

Встановіть властивість нульових значень у файлі edmx ** True **


3

Як вже зазначав andyuk , це може статися, коли значення NULL присвоюється ненульовому полі DateTime . Подумайте про зміну DateTime на DateTime? або Nullable < DateTime >. Майте на увазі, що, якщо ви використовуєте властивість Dependency , ви також повинні переконатися, що тип вашої залежності також є нульовим типом DateTime.

Нижче наводиться приклад із реального життя неповного DateTime to DateTime? тип регулювання, що підвищує дивну поведінку

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


2

Entity Framework 4 працює з типом даних datetime2, тому в db відповідному полі має бути datetime2 для SQL Server 2008.

Домогтися рішення існує двома способами.

  1. Щоб використовувати тип даних datetime в Entity Framwork 4, вам потрібно переключити ProviderManifestToken у файлі edmx на "2005".
  2. Якщо встановити відповідне поле як Allow Null (воно перетворює його в NULLABLE), то EF автоматично використовує об'єкти дати як час дати.

1
Я підібрав вашу другу точку для моїх моделей баз даних (класи POCO) і поцікавився, як встановити поле як нульовий тип. Якщо хтось задумався, ви можете це зробити, додавши знак запитання (?) Після типу дати. наприклад, загальнодоступний DateTime? StartTime {get; набір; } Це вирішило для мене питання. Єдине, що мені довелося зробити, - це поставити TimeSpan вказівник навколо рядка коду, де я віднімав два нульових значення DateTime один від одного. наприклад, var timeTaken = (TimeSpan) (endTime - startTime);
Ciaran Gallagher

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]

і я додав цей атрибут та оновив свій db, після чого він змінився

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

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

0

У моєму випадку ми передавали Date в Datetime, і ми отримали цю помилку. Що трапляється, це те, що Дата має "більш орієнтований на програмування" мінімум 01.01.2001 р., А дата - 1753

Поєднайте це з помилкою збору даних з нашого боку, і ви отримаєте виняток!


Знайдіть Америку 1492 року,
помиляйтесь

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. Ви можете використовувати: new 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

Я побачив цю помилку, коли хотів редагувати сторінку usnig ASP.Net MVC. У мене не було проблем під час створення, але оновлення бази даних зробило моє властивість DateCreate поза діапазоном!

Якщо ви не хочете, щоб ваш DateTimeресурс був нульовим і не хочете перевіряти, чи відповідає його значення в 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

Я зіткнувся з цією проблемою на простому проекті консольного додатка, і моє швидке рішення полягає в перетворенні будь-яких можливих дат date2 в обнулену дату за допомогою цього методу:

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

Це, звичайно, не зовсім комплексний метод, але він працював для моїх потреб і, можливо, він допоможе іншим!


0

Перевірте формат req в БД. наприклад, у моєї БД є значення за замовчуванням або Прив'язка(((1)/(1))/(1900))

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

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


-1

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

Щоб подолати цю проблему, ви можете встановити правильне значення дати, щоб властивість ur adn також встановило інше магічне властивість, як IsSpecified = true.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.