繁体   English   中英

将日期时间从 C# 插入到 SqlSrv

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM