DbContextとSetInitializerを使用してdatetime2の範囲外変換エラーを修正する方法


136

Entity Framework 4.1で導入されたDbContextおよびCode First APIを使用しています。

データモデルは、などの基本データ型を使用していますstringDateTime。場合によって使用している唯一のデータ注釈はですが[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、2011年

1
私の場合、テーブルと編集フォームにフィールドを追加しましたが、バインドインクルードを更新するのを忘れて、フィールドがNULLに設定されていました。したがって、エラーは私の見落としを修正するのに役立ちました。
strattonn 2014年

回答:


186

StartがSqlDateTime.MinValue(1753年1月1日)以上であることを確認する必要があります。デフォルトでは、StartはDateTime.MinValue(1月1日、0001)と等しくなります。


14
いくつかの初期化オブジェクトを日付を設定せずに残していたため、デフォルトでDateTime.MinValueになっていました。
Alex Angas、

私もそうしました^。カスタム日付フィールドをasp.net IDのApplicationUserオブジェクトに追加しましたが、意味のあるものに初期化するのを忘れていました。:(
Mike Devenney 2016年

私の場合、問題は最小日付で、0001/01/01がエラーを生成していました。
マチャド

dateTime.minvalueを確認するにはどうすればよいですか?
Anabeil

1
少し遅れますが、@ Anabeilでは、VS / linqpadのイミディエイトウィンドウでConsole.WriteLine(DateTime.MinValue)を実行できるはずです
SIRHAMY

22

シンプル。最初にコードで、DateTimeのタイプをDateTime?に設定します。したがって、データベースでnull許容の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

特定のモデリングの問題に適している場合は、フィールドをヌル可能にすることができます。nullの日付は、SQLのDateTime型の範囲内にない日付に強制されず、デフォルト値とは異なります。別のオプションは、おそらく別のタイプに明示的にマッピングすることです。

.HasColumnType("datetime2")

12

この質問はかなり古く、すでにすばらしい答えがありますが、この問題を解決するための3つの異なるアプローチを説明するもう1つを付けるべきだと思いました。

最初のアプローチ

DateTimeプロパティpublic virtual DateTime Start { get; set; }datetime2テーブルの対応する列に明示的にマップします。デフォルトでEFはそれをにマップするからdatetimeです。

これは、流れるようなAPIまたはデータアノテーションによって実行できます。

  1. Fluent 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; }

2番目のアプローチ

StartEntityClassコンストラクターでデフォルト値に初期化します。これは、何らかの理由でStartエンティティをデータベースに保存する前にの値が設定されていない場合と同じように、起動時に常にデフォルト値が設定されます。デフォルト値がSqlDateTime.MinValue以上であることを確認してください(1753年1月1日から9999年12月31日まで)

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

3番目のアプローチ

作るStartタイプNULL可能であるようにDateTime -NOTE ?DateTime-

public virtual DateTime? Start { get; set; }

詳細については、この投稿を読んでください


8

DateTimeデータベースでプロパティをnullにできる場合DateTime?は、必ず関連するオブジェクトプロパティに使用してください。そうしないとDateTime.MinValue、SQLの日時型が処理できる範囲外の未割り当ての値がEFに渡されます。


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のユーザーテーブル(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.Nowではなくnew DateTime()に設定していました。


0

私の場合、これは私がエンティティを使用し、SQLテーブルのデフォルト値がdatetime == getdate()のときに発生しました。このフィールドに値を設定するために何をしたか。


0

私はDatabase Firstを使用していますが、このエラーが発生したときの解決策は、edmxファイルでProviderManifestToken = "2005"を強制することでした(SQL Server 2005と互換性のあるモデルにする)。同様のことがCode Firstで可能かどうかわからない。


0

1行でこれを修正します。

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

だから、私のコードでは、私は追加しました:

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

その1行をDBContextサブクラスのオーバーライドに追加すると、void OnModelCreatingセクションが機能します。


0

私の場合、EF6でリファクタリングを行った後、元のポスターと同じエラーメッセージでテストが失敗しましたが、私の解決策はDateTimeフィールドとは何の関係もありませんでした。

エンティティを作成するときに、必須フィールドが欠落していました。欠けているフィールドを追加すると、エラーはなくなりました。私のエンティティには2つのDateTimeがありますか?フィールドが、彼らは問題ではなかった。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.