【问题标题】:Why does EF Seed Method Insert Null on DateTime?为什么 EF Seed 方法在 DateTime 上插入 Null?
【发布时间】:2018-07-28 04:55:29
【问题描述】:

我正在尝试在我的 Code-First EF 6 项目中实现 AddOrUpdate 方法。我收到一条错误消息,指出属性 AdmCreatedDate 中不允许使用空值。错误下方:

运行种子方法。 System.Data.Entity.Infrastructure.DbUpdateException:更新条目时出错。有关详细信息,请参阅内部异常。 ---> System.Data.Entity.Core.UpdateException:更新条目时出错。有关详细信息,请参阅内部异常。 ---> System.Data.SqlClient.SqlException:无法将值 NULL 插入到列“AdmCreatedDate”、表“TPPX.dbo.ExemptionCalculationConfig”中;列不允许空值。插入失败。声明已终止。

这是我的代码... 我有一个名为 ExemptionCalculationConfig 的模型:

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TPPX.Domain.ExemptionModels.Entities.Lookups;

namespace TPPX.Domain.ExemptionModels
{
    [Table("ExemptionCalculationConfig")]
    public class ExemptionCalculationConfig : TPPXBaseEntity
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.None)]
        public int Priority { get; set; }

        [ForeignKey("ExemptionApplyLevel")]
        public string ApplyAtLevelCode { get; set; }

        public virtual ExemptionApplyLevel ExemptionApplyLevel { get; set; }

        [ForeignKey("ExemptionApplyType")]
        public string ApplyByValueOrPercentageCode { get; set; }

        public virtual ExemptionApplyType ExemptionApplyType { get; set; }
        public bool IsProratable { get; set; }
    }
}

如你所见,这个类继承了 TPPXBaseEntity:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;

namespace TPPX.Domain
{
    public class TPPXBaseEntity
    {
        [DefaultValue(true)]
        public bool IsActive { get; set; }

        public DateTime  AdmCreatedDate { get; set; }

        [StringLength(50)]
        public string AdmCreatedUser { get; set; }

        [StringLength(255)]
        public string AdmCreatedUserFullName { get; set; }
        public DateTime? AdmModifiedDate { get; set; }

        [StringLength(50)]
        public string AdmModifiedUser { get; set; }

        [StringLength(255)]
        public string AdmModifiedUserFullName { get; set; }

    }
}

然后我的 Migrations 文件夹中有我的 Configuration.cs 文件: 我尝试添加要保存在数据库中的对象列表以及单个实例。此外,我明确尝试创建一个名为 seedCreatedDate 的 DateTime 对象,使用 DateTime.Today 甚至 DateTime.ParseExact() 作为 AdmCreatedDate 的值,但没有运气:(

using System.Collections.Generic;
using System.Web;
using PA.Web.Configuration.WebConfigurationManager;
using TPPX.Domain.ExemptionModels;
using System;
using System.Data.Entity;
using System.Data.Entity.Migrations;
using System.Linq;

namespace TPPX.DAL.Migrations.TPPXDBContext
{


    internal sealed class Configuration : DbMigrationsConfiguration<TPPX.DAL.DBContexts.TPPXDBContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
            MigrationsDirectory = @"Migrations\TPPXDBContext";
        }

        protected override void Seed(TPPX.DAL.DBContexts.TPPXDBContext context)
        {
            //  This method will be called after migrating to the latest version.

            //  You can use the DbSet<T>.AddOrUpdate() helper extension method 
            //  to avoid creating duplicate seed data.
            //var seedCreatedDate = new DateTime(2018, 07, 26);

            //var exemptionCalculationConfigs = new List<ExemptionCalculationConfig>
            //{
            //    new ExemptionCalculationConfig
            //    {
            //        AdmCreatedDate = DateTime.Today,
            //        AdmCreatedUser = "carcruz",
            //        AdmCreatedUserFullName = "Cruz, Carlos (PA)",
            //        Priority = 1,
            //        IsProratable = false,
            //        ApplyAtLevelCode = "A",
            //        ApplyByValueOrPercentageCode = "P",
            //        IsActive = true
            //    },
            //    new ExemptionCalculationConfig
            //    {
            //        AdmCreatedDate = DateTime.Today,
            //        AdmCreatedUser = "carcruz",
            //        AdmCreatedUserFullName = "Cruz, Carlos (PA)",
            //        Priority = 2,
            //        IsProratable = false,
            //        ApplyAtLevelCode = "V",
            //        ApplyByValueOrPercentageCode = "V",
            //        IsActive = true
            //    }
            //};

            //exemptionCalculationConfigs.ForEach(
            //    x => context.ExemptionCalculationConfigs.AddOrUpdate(e => e.Priority, x));

            context.ExemptionCalculationConfigs.AddOrUpdate(
                e => e.Priority,
                new ExemptionCalculationConfig
                {
                    AdmCreatedDate = DateTime.Now,
                    AdmCreatedUser = "carcruz",
                    AdmCreatedUserFullName = "Cruz, Carlos (PA)",
                    Priority = 1,
                    IsProratable = false,
                    ApplyAtLevelCode = "A",
                    ApplyByValueOrPercentageCode = "P",
                    IsActive = true,
                    AdmModifiedDate = null,
                    AdmModifiedUser = null,
                    AdmModifiedUserFullName = null
                });
            context.SaveChanges();
        }
    }
}

我看到其他人在没有明确说他们的主键不应该是标识列时也有同样的错误,但我的情况不是这样。我错过了什么?

【问题讨论】:

  • [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 属性添加到 AdmCreatedDate 属性。数据库中的该列可能应该使用默认的 GETDATE() 或 GETUTCDATE() 创建,因此数据库生成值,而不是应用程序。
  • 看起来 AdmCreatedDate 已通过 fluent API 配置为 DatabaseGeneratedOption.Identity,在这种情况下,EF 在执行 INSERT 时不会发送该值。但同时数据库表列没有设置DEFAULT,所以异常。
  • @RobertMcKee 恕我直言,异常消息与您所说的相反。
  • @RobertMcKee 查看模型中的属性类型 - 它是DateTime(不可为空),因此您无法显式尝试插入空值。只有 EF 可以做到这一点,当属性被标记为身份或计算时就会发生这种情况。
  • 感谢大家花时间阅读并提供反馈,感谢@IvanStoev 对计算属性的评论,我已经解决了问题。如果您回答为什么我不能使用 fluent API 计算属性并使用种子方法,我会给您正确的答案。请记住,我也尝试不给 AdmCreatedDate 赋值,但种子方法仍然失败。了解为什么会发生这种情况会很棒:)

标签: c# entity-framework entity-framework-6


【解决方案1】:

好的,伙计们。

我想通了(有点)。

感谢 IvanStoev 指出计算和身份属性。

我的 DbContext 中确实有以下行:

modelBuilder.Properties<DateTime>().Where(x => x.Name == "AdmCreatedDate")
.Configure(c => c.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed));

由于某种原因,当 Seed 方法尝试运行并且对象具有计算属性时,EF 不喜欢它。我与项目负责人交谈并说服她从 EF 中取出计算结果(因为它甚至不会影响数据库。EF 仅在代码上处理它。在 SQL Server 中检查数据库后,我注意到该列实际上并未设置为计算)老实说,我不喜欢这样,因为如果将来我们决定不使用 EF,计算的属性将会丢失。

因此,总而言之,您不能在 Seed() 方法中拥有具有计算属性的模型

现在,我们处理实际 DB 中的计算列。

很高兴知道为什么 EF 会以这种方式运行,但我无法在网上找到。如果有人知道,请告诉我。

希望这会有所帮助:)

【讨论】:

  • 我注意到该列实际上并未设置为计算列——嗯,这就是问题所在,因为我已经在上一条评论中告诉过你。当您告诉 EF 列值是由数据库生成时,值应该 是由数据库生成的。 EF 依赖它并且不在插入语句中提供值。它只读取 LINQ 语句中的值。
  • @GertArnold 对,但 EF 不应该将列设置为我在实际 SQL Server DB 中使用流式 API 放置以下行所计算的吗? modelBuilder.Properties&lt;DateTime&gt;().Where(x =&gt; x.Name == "AdmCreatedDate").Configure(c =&gt; c.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed)); 如果不是这样,那这条线实际上是做什么的?因为我的数据库没有计算出来,只有 EF 知道这一点
  • 有人知道吗?我花了一整天的时间与默认日期和指南作斗争,这一事实让我大吃一惊。我不明白为什么此时要使用 EF6。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-17
  • 2017-01-20
  • 2023-03-04
  • 2012-10-17
相关资源
最近更新 更多