[英]Insert datetime from C# to SqlSrv
我需要使用 EntityFramework 在数据库中保存来自 C# 的日期字段类型“datetime”。
在 MySql 中工作正常但在 Sqlsrv 中没有。
这个想法是系统可以使用 MySql 或 SqlSrv,这就是我使用 datetime 而不是 datetime2 的原因。
我的model:
public partial class Entity: ITimeStamp
{
public long Id { get; set; }
public string Name { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime UpdatedAt { get; set; }
}
我的数据库上下文:
protected override void OnModelCreating(ModelBuilder modelBuilder) {
.......
modelBuilder.Entity<Entity>(entity =>
{
entity.ToTable("entities");
entity.HasIndex(e => e.Name, "entities_name_unique")
.IsUnique();
entity.Property(e => e.Id)
.HasColumnType("int")
.HasColumnName("id").ValueGeneratedOnAdd();
entity.Property(e => e.CreatedAt)
.HasColumnType("datetime")
.HasColumnName("created_at");
entity.Property(e => e.Name)
.IsRequired()
.HasColumnType("varchar(255)")
.HasColumnName("name");
entity.Property(e => e.UpdatedAt)
.HasColumnType("datetime")
.HasColumnName("updated_at");
});
......
}
public override int SaveChanges()
{
var entries = ChangeTracker
.Entries()
.Where(e => e.Entity is ITimeStamp && (
e.State is EntityState.Added or EntityState.Modified));
foreach (var entityEntry in entries)
{
((ITimeStamp)entityEntry.Entity).UpdatedAt = DateTime.Now;
if (entityEntry.State == EntityState.Added)
{
((ITimeStamp)entityEntry.Entity).CreatedAt = DateTime.Now;
}
}
return base.SaveChanges();
}
我的Controller:
var entity = new Entity
{
Name = installer.CompanyName,
...
};
_context.Entities.Add(entity);
await _context.SaveChangesAsync();
例外:
System.Data.SqlTypes.SqlTypeException: SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
at Microsoft.Data.SqlClient.SqlCommand.<>c.<ExecuteDbDataReaderAsync>b__169_0(Task`1 result)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
at System.Threading.Tasks.Task.<>c.<.cctor>b__277_0(Object obj)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Update.ReaderModificationCommandBatch.ExecuteAsync(IRelationalConnection connection, CancellationToken cancellationToken)
我尝试将字段设置为可为空,但它没有抛出异常,而是不保存任何日期。
问题是 .NET 中DateTime
实例的默认值是0001-01-01T00:00:00
(ISO8601 表示法)。 在 Sql 服务器中,日期时间的范围是有限的,必须大于1753-1-1T00:00:00
(也是 ISO8601 表示法)。 您必须指定一个大于此日期的DateTime
实例值。
另一种方法是使用 Nullable DateTime? 实例并使列值在您的数据库架构中接受空值,这样缺少值会导致数据库中出现 NULL 值。
如果您确定在保存之前正确设置了值,您应该使用 Sql Profiler 分析操作并查看正在传递并导致异常的值是什么。 可能是列的名称与模式列的名称不对应,或者数据库中有另一个列未映射回您的实体。
我在我的项目中做了类似的事情。 下面是我的代码,它在 10 多个项目中运行良好。 下面是我的 DbContext
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
//This allows the audit fields to automatically be added, or updated.
public override int SaveChanges()
{
var state = this.ChangeTracker.Entries().Select(x => x.State).ToList();
state.ForEach(x => {
switch(x)
{
case EntityState.Added:
UpdateAddedEntity();
break;
case EntityState.Modified:
UpdateModifiedEntity();
break;
}
});
return base.SaveChanges();
}
//Update Entity Pattern
protected void UpdateAddedEntity()
{
var created = this.ChangeTracker.Entries().Where(e => e.State == EntityState.Added).Select(e => e.Entity).ToArray();
foreach (var entity in created)
{
if (entity is AuditFields)
{
var auditFields = entity as AuditFields;
auditFields.CreateDateTimeUtc = DateTime.UtcNow;
auditFields.ModifiedDateTimeUtc = DateTime.UtcNow;
auditFields.Active = true;
}
}
}
protected void UpdateModifiedEntity()
{
//Modified record changes
var modified = this.ChangeTracker.Entries().Where(e => e.State == EntityState.Modified).Select(e => e.Entity).ToArray();
foreach (var entity in modified)
{
if (entity is AuditFields)
{
var auditFields = entity as AuditFields;
auditFields.ModifiedDateTimeUtc = DateTime.UtcNow;
}
}
}
哦,我想如果你想要 model 作为我的审计字段,那也是:
public class AuditFields
{
protected AuditFields()
{
Active = true;
CreateDateTimeUtc = DateTime.UtcNow;
ModifiedDateTimeUtc = DateTime.UtcNow;
}
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
[IndexColumn]
public DateTime CreateDateTimeUtc { get; set; }
[Required]
[IndexColumn]
public DateTime ModifiedDateTimeUtc { get; set; }
[IndexColumn]
public bool Active { get; set; }
}
经过多次测试,终于解决了我的问题。
我从 DBContext 中删除日期时间定义并将其保留在 model 定义中,以便 EF 决定为客户端选择的 DB 类型选择哪种类型的日期时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.