DbContext 및 SetInitializer를 사용하여 datetime2 범위를 벗어난 변환 오류를 수정하는 방법은 무엇입니까?


136

Entity Framework 4.1에 도입 된 DbContext 및 Code First API를 사용하고 있습니다.

데이터 모델 과 같은 기본 데이터 유형을 사용 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 데이터 유형을 datetime 데이터 유형으로 변환하면 범위를 벗어난 값이 발생했습니다. 그 진술서는 만료되었습니다.

모든 것이 매우 간단하기 때문에 왜 이런 일이 일어나고 있는지 이해할 수 없습니다. 편집 할 edmx 파일이 없으므로 수정 방법을 잘 모르겠습니다.

어떤 아이디어?


2
SQL 프로파일 러를 사용하여 SQL 문 삽입 / 업데이트를 볼 수 있습니까? 여기서 무슨 일이 일어나고 있는지 말하기는 어렵습니다. 초기화 프로그램이나 엔티티가 보이지 않습니다. SQL 프로파일 러는 문제를 현지화하는 데 많은 도움이됩니다.
Ladislav Mrnka

1
필자의 경우 테이블에 필드를 추가하고 양식을 편집하고 Bind Includes를 업데이트하는 것을 잊어 버렸고 필드가 NULL로 설정되었습니다. 따라서이 오류는 감독을 바로 잡는 데 도움이되었습니다.
strattonn

답변:


186

시작이 SqlDateTime.MinValue (1753 년 1 월 1 일) 이상인지 확인해야합니다. 기본적으로 시작은 DateTime.MinValue (0001 년 1 월 1 일)와 같습니다.


14
날짜를 설정하지 않고 이니셜 라이저 객체 중 일부를 그대로 두었으므로 기본값은 DateTime.MinValue입니다.
Alex Angas

나도 그렇게 했어 ^. asp.net ID ApplicationUser 오브젝트에 사용자 정의 날짜 필드를 추가 한 후 해당 필드를 초기화하는 것을 잊었습니다. : (
Mike Devenney

내 경우에는 문제가 최소 날짜에 있었고 01/01/0001이 오류를 생성했습니다.
Machado

dateTime.minvalue를 어떻게 확인할 수 있습니까?
Anabeil

1
조금 늦었지만 @Anabeil을 사용하면 VS / linqpad의 바로 창에서 Console.WriteLine (DateTime.MinValue)을 사용할 수 있습니다
SIRHAMY

22

단순한. 먼저 코드에서 DateTime 유형을 DateTime?으로 설정하십시오. 따라서 데이터베이스에서 nullable 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; }
    }

6
항상 그런 것은 아닙니다. {1/1/0001 12:00:00 AM}도이 오류가 발생합니다
eran otzap

20

경우에 따라 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();

13

특정 모델링 문제에 적합한 경우 필드를 널 입력 가능하게 만들 수 있습니다. 널 날짜는 기본값과 같은 방식으로 SQL DateTime 유형의 범위 내에 있지 않은 날짜로 강제 변환되지 않습니다. 다른 옵션은 다른 유형으로 명시 적으로 매핑하는 것입니다.

.HasColumnType("datetime2")

12

이 질문은 꽤 오래되었지만 이미 큰 대답이 있지만이 문제를 해결하기 위해 3 가지 접근법을 설명하는 방법을 하나 더 넣어야한다고 생각했습니다.

첫 번째 접근법

테이블의 해당 열에 DateTime속성 public virtual DateTime Start { get; set; }을 명시 적으로 매핑 datetime2합니다. EF는 기본적으로에 매핑하기 때문 datetime입니다.

유창한 API 또는 데이터 주석으로 수행 할 수 있습니다.

  1. 유창한 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"));
    }
  2. 데이터 주석

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

두 번째 접근법

StartEntityClass 생성자에서 기본값으로 초기화 합니다. 이것은 어떤 이유로 Start엔티티를 데이터베이스 시작에 저장하기 전에 값이 설정되지 않은 것처럼 항상 기본값을 갖는 것처럼 좋습니다 . 기본값이 SqlDateTime.MinValue 이상인지 확인하십시오 (1753 년 1 월 1 일부터 9999 년 12 월 31 일까지)

public class EntityClass
{
    public EntityClass()
    {
        Start= DateTime.Now;
    }
    public DateTime Start{ get; set; }
}

3 차 접근법

확인 StartNullable 형식의 수 DateTime - 주 ?DateTime-

public virtual DateTime? Start { get; set; }

자세한 설명은이 게시물을 읽으십시오


8

귀하의 경우 DateTime속성이 데이터베이스에 널 (NULL) 후 사용하십시오 DateTime?관련 개체 속성 또는 EF가 전달됩니다 DateTime.MinValue는 SQL이 날짜 형식이 처리 할 수있는 범위의 밖에 할당되지 않은 값.


8

내 솔루션은 모든 datetime 열을 datetime2로 전환하고 새로운 열에 datetime2를 사용하는 것이 었습니다. 즉, EF가 기본적으로 datetime2를 사용하도록합니다. 컨텍스트의 OnModelCreating 메소드에 이것을 추가하십시오.

modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));

모든 DateTime과 DateTime을 얻을 수 있습니까? 모든 엔티티의 속성.


3

생성자에서 Start 속성을 초기화합니다

Start = DateTime.Now;

Code First를 사용하여 ASP .Net Identity Framework의 Users 테이블 (AspNetUsers)에 몇 가지 새로운 필드를 추가하려고 할 때 유용했습니다. IdentityModels.cs에서 Class-ApplicationUser를 업데이트하고 DateTime 유형의 lastLogin 필드를 추가했습니다.

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

2

사용자 @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;
                    }
                }
            }
        }
    }
}

https://stackoverflow.com/a/11297294/9158120 에 대한 사용자 @ sky-dev의 의견에서 가져 왔습니다.


1

나는 같은 문제가 있었고 내 경우에는 DateTime 대신 new DateTime ()으로 날짜를 설정하고있었습니다.


0

필자의 경우 엔티티를 사용하고 SQL 테이블의 기본값이 datetime == getdate () 인 경우에 발생했습니다. 이 필드에 값을 설정하기 위해 한 것입니다.


0

Database First를 사용하고 있는데이 오류가 발생하면 솔루션이 edmx 파일에서 ProviderManifestToken = "2005"를 강제 실행하는 것입니다 (SQL Server 2005와 호환되는 모델 만들기). Code First와 비슷한 것이 있는지 모릅니다.


0

한 줄이 이것을 수정합니다.

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 섹션이 무시됩니다.


0

필자의 경우 EF6에서 일부 리팩토링 후 원래 포스터와 동일한 오류 메시지로 테스트가 실패했지만 솔루션은 DateTime 필드와 관련이 없었습니다.

엔터티를 만들 때 필수 필드가 누락되었습니다. 누락 된 필드를 추가하면 오류가 사라졌습니다. 내 엔터티에 두 개의 DateTime이 있습니까? 필드는 문제가되지 않았습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.