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");
}
}
initializerは、モデルの日付を今年または来年の適切な値に設定します。
ただし、イニシャライザを実行すると、context.SaveChanges()
でこのエラーが発生します。
Datetime2データ型からdatetimeデータ型への変換の結果、範囲外の値が生じました。ステートメントは終了されました。
すべてが非常に単純なので、なぜこれが起こっているのかまったくわかりません。また、編集するedmxファイルがないため、修正方法もわかりません。
何か案は?
StartがSqlDateTime.MinValue(1753年1月1日)以上であることを確認する必要があります-デフォルトでは、StartはDateTime.MinValue(0001年1月1日)に等しくなります。
シンプル。最初にコードで、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; }
}
場合によっては、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();
特定のモデリングの問題に合う場合は、フィールドをヌル可能にすることができます。 NULL日付は、デフォルト値のようにSQL DateTime型の範囲内にない日付に強制されることはありません。別のオプションは、異なるタイプに明示的にマッピングすることです。おそらく、
.HasColumnType("datetime2")
この質問は非常に古く、すでに素晴らしい答えがありますが、この問題を解決するための3つの異なるアプローチを説明するものをもう1つ追加する必要があると思いました。
最初のアプローチ
テーブルの対応する列のDateTime
プロパティpublic virtual DateTime Start { get; set; }
を明示的にdatetime2
にマップします。 EFはデフォルトでdatetime
にマップするためです。
これは、流れるようなAPIまたはデータ注釈によって行うことができます。
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"));
}
データ注釈
[Column(TypeName="datetime2")]
public virtual DateTime Start { get; set; }
第2のアプローチ
Start
をEntityClassコンストラクターの既定値に初期化します。これは、何らかの理由で、エンティティをデータベースの開始に保存する前に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
-noteDateTime
の後の?
にする
public virtual DateTime? Start { get; set; }
詳細については、これをお読みください post
私の解決策は、すべてのdatetime列をdatetime2に切り替え、新しい列にdatetime2を使用することでした。つまり、デフォルトでEFがdatetime2を使用するようにします。これをコンテキストのOnModelCreatingメソッドに追加します。
modelBuilder.Properties<DateTime>().Configure(c => c.HasColumnType("datetime2"));
それはすべてのDateTimeとDateTimeを取得しますか?すべてのエンティティのプロパティ。
データベースでDateTime
プロパティがnull可能の場合、関連付けられたオブジェクトプロパティにDateTime?
を使用するか、SQL日時型が処理できる範囲外の未割り当て値にEFがDateTime.MinValue
を渡すようにしてください。
コンストラクターで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; }
}
ユーザー@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/915812 に関するユーザー@ sky-devのコメントから取得
私は同じ問題を抱えていて、私の場合は日付をDateTime.Nowではなくnew DateTime()に設定していました
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セクションに追加すると機能するはずです。
私の場合、これはエンティティを使用し、sqlテーブルにdatetime == getdate()のデフォルト値があるときに起こりました。このフィールドに値を設定するために私がしたこと。
私の場合、EF6でリファクタリングを行った後、テストは元のポスターと同じエラーメッセージで失敗しましたが、ソリューションはDateTimeフィールドとは関係ありませんでした。
エンティティを作成するときに、必須フィールドが欠落していました。不足しているフィールドを追加すると、エラーはなくなりました。私のエンティティには2つのDateTimeがありますか?フィールドですが、それらは問題ではありませんでした。
私はDatabase Firstを使用していますが、このエラーが発生したときの解決策は、edmxファイルでProviderManifestToken = "2005"を強制することでした(モデルとSQL Server 2005との互換性を確保する)。同様のことがCode Firstで可能かどうかわからない。