Ответ 1
Вы должны убедиться, что Start больше или равно SqlDateTime.MinValue(1 января 1753 г.) - по умолчанию Start равно DateTime.MinValue(1 января 0001 г.).
Я использую API-интерфейсы DbContext и Code First, представленные с Entity Framework 4.1.
Модель данных использует базовые типы данных, такие как string
и DateTime
. Единственная аннотация, которую я использую в некоторых случаях, это [Required]
, но это не для любого из свойств DateTime
. Пример:
public virtual DateTime Start { get; set; }
Подкласс DbContext также прост и выглядит следующим образом:
public class EventsContext : DbContext
{
public DbSet<Event> Events { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Event>().ToTable("Events");
}
}
Инициализатор устанавливает даты в модели на разумные значения в этом году или в следующем году.
Однако, когда я запускаю инициализатор, я получаю эту ошибку в context.SaveChanges()
:
Преобразование данных datetime2 тип к типу данных даты и времени в значении вне диапазона. утверждение завершено.
Я не понимаю, почему это происходит вообще, потому что все так просто. Я также не знаю, как это исправить, так как нет edmx файла для редактирования.
Любые идеи?
Вы должны убедиться, что Start больше или равно SqlDateTime.MinValue(1 января 1753 г.) - по умолчанию Start равно DateTime.MinValue(1 января 0001 г.).
Simple. В коде сначала укажите тип DateTime для DateTime?. Таким образом, вы можете работать с нулевым типом DateTime в базе данных. Пример сущности:
public class Alarme
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public DateTime? DataDisparado { get; set; }//.This allow you to work with nullable datetime in database.
public DateTime? DataResolvido { get; set; }//.This allow you to work with nullable datetime in database.
public long Latencia { get; set; }
public bool Resolvido { get; set; }
public int SensorId { get; set; }
[ForeignKey("SensorId")]
public virtual Sensor Sensor { get; set; }
}
В некоторых случаях DateTime.MinValue
(или эквивалентно default(DateTime)
) используется для указания неизвестного значения.
Этот простой метод расширения может помочь справиться с такими ситуациями:
public static class DbDateHelper
{
/// <summary>
/// Replaces any date before 01.01.1753 with a Nullable of
/// DateTime with a value of null.
/// </summary>
/// <param name="date">Date to check</param>
/// <returns>Input date if valid in the DB, or Null if date is
/// too early to be DB compatible.</returns>
public static DateTime? ToNullIfTooEarlyForDb(this DateTime date)
{
return (date >= (DateTime) SqlDateTime.MinValue) ? date : (DateTime?)null;
}
}
Использование:
DateTime? dateToPassOnToDb = tooEarlyDate.ToNullIfTooEarlyForDb();
Вы можете сделать поле нулевым, если это соответствует вашим конкретным проблемам моделирования. Нулевая дата не будет привязана к дате, которая не находится в пределах диапазона типа SQL DateTime, как значение по умолчанию. Другой вариант - явно отобразить другой тип, возможно, с помощью
.HasColumnType("datetime2")
Несмотря на то, что этот вопрос довольно старый, и уже есть большие ответы, я подумал, что должен добавить еще один, который объясняет три разных подхода к решению этой проблемы.
1-й подход
Явно сопоставить DateTime
свойство public virtual DateTime Start { get; set; }
- datetime2
в соответствующем столбце таблицы. Поскольку по умолчанию EF отобразит его на DateTime
.
Это можно сделать с помощью свободного API или аннотации данных.
Свободный API
В классе DbContext переопределить OnModelCreating
и настроить свойство Start
(для объяснения причин это свойство класса EntityClass).
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//Configure only one property
modelBuilder.Entity<EntityClass>()
.Property(e => e.Start)
.HasColumnType("datetime2");
//or configure all DateTime Preperties globally(EF 6 and Above)
modelBuilder.Properties<DateTime>()
.Configure(c => c.HasColumnType("datetime2"));
}
Аннотации данных
[Column(TypeName="datetime2")]
public virtual DateTime Start { get; set; }
Второй подход
Инициализировать Start
до значения по умолчанию в конструкторе EntityClass. Это хорошо, так как по какой-то причине значение Start
не задано перед сохранением объекта в начале базы данных, всегда будет иметь значение по умолчанию. Убедитесь, что значение по умолчанию больше или равно SqlDateTime.MinValue (с 1 января 1753 г. по 31 декабря 9999 г.)
public class EntityClass
{
public EntityClass()
{
Start= DateTime.Now;
}
public DateTime Start{ get; set; }
}
Третий подход
Сделать Start
типом nullable DateTime
-note ?
после DateTime
-
public virtual DateTime? Start { get; set; }
Подробнее об этом читайте post
Если ваши свойства DateTime
имеют значение NULL в базе данных, то не забудьте использовать DateTime?
для связанных свойств объекта, или EF будет проходить в DateTime.MinValue
для неназначенных значений, которые находятся за пределами диапазона того, что тип SQL datetime может обрабатывать.
Моим решением было переключить все столбцы datetime на datetime2 и использовать datetime2 для любых новых столбцов. Другими словами, EF использует значение datetime2 по умолчанию. Добавьте это в метод OnModelCreating в вашем контексте:
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
Что получит все DateTime и DateTime? свойства для всех ваших объектов.
инициализировать свойство Start в конструкторе
Start = DateTime.Now;
Это сработало для меня, когда я пытался добавить несколько новых полей в таблицу ASP.Net Identity Framework Users (AspNetUsers), используя Code First. Я обновил класс - ApplicationUser в IdentityModels.cs, и я добавил поле lastLogin типа DateTime.
public class ApplicationUser : IdentityUser
{
public ApplicationUser()
{
CreatedOn = DateTime.Now;
LastPassUpdate = DateTime.Now;
LastLogin = DateTime.Now;
}
public String FirstName { get; set; }
public String MiddleName { get; set; }
public String LastName { get; set; }
public String EmailId { get; set; }
public String ContactNo { get; set; }
public String HintQuestion { get; set; }
public String HintAnswer { get; set; }
public Boolean IsUserActive { get; set; }
//Auditing Fields
public DateTime CreatedOn { get; set; }
public DateTime LastPassUpdate { get; set; }
public DateTime LastLogin { get; set; }
}
Исходя из ответа пользователя @andygjp, лучше переопределить базовый Db.SaveChanges()
и добавить функцию для переопределения любой даты, которая не попадает между SqlDateTime.MinValue и SqlDateTime.MaxValue.
Вот пример кода
public class MyDb : DbContext
{
public override int SaveChanges()
{
UpdateDates();
return base.SaveChanges();
}
private void UpdateDates()
{
foreach (var change in ChangeTracker.Entries().Where(x => (x.State == EntityState.Added || x.State == EntityState.Modified)))
{
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 комментарий на fooobar.com/questions/42108/...
У меня была такая же проблема, и в моем случае я устанавливал дату в новую DateTime() вместо DateTime.Now
В моем случае это произошло, когда я использовал сущность, а таблица sql имела значение по умолчанию datetime == getdate(). поэтому я сделал, чтобы установить значение для этого поля.
Я использую Database First, и когда эта ошибка произошла со мной, моим решением было заставить ProviderManifestToken = "2005" в файле edmx (что делает модели совместимыми с SQL Server 2005). Не знаю, возможно ли что-то подобное для Code First.
Одна строка исправляет это:
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
Итак, в своем коде я добавил:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
}
Добавление этой строки в переопределение подкласса DBContext void OnModelCreating должно работать.
В моем случае после некоторого рефакторинга в EF6 мои тесты не прошли с тем же сообщением об ошибке, что и у исходного постера, но мое решение не имело ничего общего с полями DateTime.
Я просто пропустил обязательное поле при создании объекта. Как только я добавил недостающее поле, ошибка исчезла. У моей сущности есть два DateTime? поля, но они не были проблемой.