Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

EF Core DatabaseGeneratedOption.Computed not working

I've recently started working with .NET CORE v2. I'm trying to set up my database by using a code-first approach in my web-api template.

Background: I've previously worked with the Laravel framework and I would like to replicate laravel's timestamp() function in migration files which basically creates two columns: UpdatedAt and CreatedAt in a table.

The values in those columns are populated with the correct values when the ORM's (Elqoquent) functions that INSERT or UPDATE columns are used. It's seamless and you don't need to worry about it.


In my c# code I have the following model

public class A {
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id { get; set; }

    public string Name { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime Created_At { get; set; } = DateTime.UtcNow;

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime Updated_At { get; set; }

    // I've tried to add "= DateTime.UtcNow;" at the end of Updated_At as well
}

I also have the following class that is used to seed the database.

public static class DatabaseSeeder
{
    private static AppContext _context;

    public static void SeedDatabase(this AppContext appContext)
    {
        _context = appContext;
        _context.Database.EnsureCreated();

        // Verify if data exist.
        if (_context.A.Any())
        {
            return;
        }

        SeedAs();
    }

    private static void SeedAs()
    {
        var defaults = new A[]
        {
            new A
            {
                Name = "Value 1",
            },
            new A
            {
                Name = "Value 2",
            },
            new A
            {
                Name = "Value 3",
            }
        };

        _context.As.AddRange(defaults);
        _context.SaveChanges();
    }
}

The SeedDatabase function is called in the Configure function of the Startup class which basically seeds the database should it not contain any data at startup.

Problem: The issue I am encoutering is that when I launch my development server the first time, the application notices that the database does not contain any values so it tries to seed it. The following error is returned:

MySql.Data.MySqlClient.MySqlException (0x80004005): Field 'Updated_At' doesn't have a default value

I don't seem to understand why this fails because when I ran the same piece of code by removing the Updated_At property and its annotation, no error was returned and the database was seeded as expected with the Created_At field containing the value of DateTime.UtcNow.

The expected behavior of the DatabaseGenerated(DatabaseGeneratedOption.Computed annotation is to have a database generated value based on the data type of the property on insert or update.

Can anyone tell me why, it fails when I try to seed my database.

like image 889
Gloire Avatar asked Nov 08 '22 12:11

Gloire


1 Answers

At first, you have already defined the initial value for Created_At in your class: = DateTime.UtcNow;

That's why it works for Created_At but does not work for Updated_At. Since Updated_At does not have an initial value and the Database does not have any default value defined for this column.

To make it work right, you have to define the default values for your SQL Columns in the DbContext Class.

I guess, with MySQL you should use the function NOW():

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<A>()
            .Property(s => s.Created_At )
            .HasDefaultValueSql("NOW()");

    modelBuilder.Entity<A>()
            .Property(s => s.Updated_At )
            .HasDefaultValueSql("NOW()");
}

Docs: Data Annotations - DatabaseGenerated Attribute in EF 6 & EF Core

like image 126
Tolbxela Avatar answered Nov 15 '22 05:11

Tolbxela