EF Code First ApplicationUser 需要 DateTime 未添加

EF Code First ApplicationUser required DateTime not added


我在使用新 ASP.NET 核心应用程序(代码优先)注册新用户时遇到问题。
注册时,我使用的是继承自 IdentityUser 的 ApplicationUser。
public class ApplicationUser : IdentityUser
{
    [Required]
    [DefaultValue(5)]
    public int ViewerRange { get; set; }
    [DefaultValue(false)]
    [Required]
    public bool IsTACAccepted { get; set; }
    public DateTime? TACAccepted { get; set; }
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime Created { get; set; }
    [Required]
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime Modified { get; set; }
    public string Role { get; set; }

    public ApplicationUser()
    {
        Modified = DateTime.Now;
        Created = DateTime.Now;
    }
}

这是Register.cshtml.cs

的部分
public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl ??= Url.Content("~/");
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList();
    if (ModelState.IsValid)
    {
        var user = new ApplicationUser
        {
            UserName = Input.Email,
            Email = Input.Email,
            Role = Input.Role,
            Created = DateTime.Now,
            Modified = DateTime.Now,
            IsTACAccepted = false,
            ViewerRange = 5
        };


        var result = await _userManager.CreateAsync(user, Input.Password);
        //[...]

注册时,CreateAsync 方法失败并出现以下错误:

InvalidOperationException: The value for property 'ApplicationUser.Modified' cannot be set to null because its type is 'System.DateTime' which is not a nullable type.

我不明白为什么会失败。
有人可以详细解释一下吗?
亲切的问候

public DateTime? Created { get; set; }
public DateTime? Modified { get; set; }

使用这个,你的模型需要被告知你的数据库中可以有空值,否则它会假设没有。

更新

**I did not actually carefully noticed your error. Now I will update my answer:-**

我看到你没有在你的控制器中使用这个 属性。所以最初这个 属性 可以为空。为此,您发现了这个问题。首先,使用此 属性 忽略可空值。

这样试试:-

public DateTime TACAccepted { get; set; }  = DateTime.Now;

您可以试试这个,因为您的 属性 它是空的。您可以像上面的代码一样设置此 属性 以忽略可为空的。或者,如果不需要,您可以从模型中删除此 属性。我认为它会解决您的问题。

此外,请确保该列在您的 SQL 数据库中声明为 DateTime。

错误的原因是[DatabaseGenerated(DatabaseGeneratedOption.Computed)]说它的值是由数据库生成的,所以任何分配的值都应该被忽略。错误显示情况并非如此。

这不是代码中唯一的奇怪之处。 [DatabaseGenerated(DatabaseGeneratedOption.Identity)] 在 DateTime 上没有意义。 IDENTITY 用于自动递增数字字段。这对 DateTime 列没有意义。

如果您想自己指定值,请删除 DatabaseGenerated 属性并将它们用作普通字段。您可以通过指定默认 属性 值来避免显式赋值,例如

public DateTime Created { get; set; } = DateTime.Now;
public DateTime Modified { get; set; } = DateTime.Now;

也可以配置 数据库 来生成这些值。这在文档的 Generated Values article. Adding Created and Modified columns is described in the Date/time generation 部分中进行了描述。

Created 列的默认值约束可以用 HasDefaultValueSql 指定:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .Property(b => b.Created)
        .HasDefaultValueSql("getdate()");
}

Modified 时间戳需要一个触发器,它不能在 DbContext 的模型中指定。这必须在数据库中直接创建:

CREATE TRIGGER [dbo].[Blogs_UPDATE] ON [dbo].[Blogs]
    AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;

    IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;

    DECLARE @Id INT

    SELECT @Id = INSERTED.BlogId
    FROM INSERTED

    UPDATE dbo.Blogs
    SET LastUpdated = GETDATE()
    WHERE BlogId = @Id
END

或者通过执行相同脚本的原始 SQL 迁移:

migrationBuilder.Sql(
@"
    EXEC ('CREATE TRIGGER [dbo].[Blogs_UPDATE] ON [dbo].[Blogs]
    AFTER UPDATE
AS
BEGIN
    SET NOCOUNT ON;

    IF ((SELECT TRIGGER_NESTLEVEL()) > 1) RETURN;

    DECLARE @Id INT

    SELECT @Id = INSERTED.BlogId
    FROM INSERTED

    UPDATE dbo.Blogs
    SET LastUpdated = GETDATE()
    WHERE BlogId = @Id
END')");