An Enthusiastic Programmer

Data Annotation - DatabaseGenerated Attribute

|

According to the Code First convention, a primary key column is going to be applied IDENTITY constraint and AutoIncrement that the default seed and step are both numeric 1 by default.

The DatabaseGeneratedAttribute specifies how the database generates values for a property. The DatabaseGeneratedAttribute has a constructor that accepts a DatabaseGeneratedOption instance, which is an Enum type that contains three available fields.

  • DatabaseGeneratedOption.None
  • DatabaseGeneratedOption.Identity
  • DatabaseGeneratedOption.Computed

DatabaseGeneratedOption.None

None represents the database doesn’t generate value automatically. As per the default convention, Entity Framework will map a property that is an integer type and named as Id into a primary key. This mechanism means the underlying database will generate a new value for this column each time an insert operation occurred.

In the below example, we applied the DatabaseGeneratedOption.None to breaks the default convention.

public class Student
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { set; get; }
    public string name { set; get; }
}

Database screenshot as below Alt

The Id column doesn’t specify as an identity. Now, the Id value needs to be specified explicitly.

DatabaseGeneratedOption.Identity

Identity represents that the database generates a value when an insert statement occurs. This property would not be affected by the UPDATE statement.

Please note that the way the value generated by the database is depending on the provider. It can be Identity, rowversion, GUID.

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public DateTime add_time { set; get; }

DatabaseGeneratedOption.Computed

Computed represents that the database generates a value when an INSERT statement or an UPDATE statement occurs. This property would be affected by both the UPDATE statement and the INSERT statement.

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

Summary

According to the Official document

This just lets EF know that values are generated for added entities, it does not guarantee that EF will setup the actual mechanism to generate values. See Value generated on add section or Value generated on add or update section for more details.
class SchoolContext : DbContext
{
    public DbSet<Student> student { set; get; }
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer("Server=_server;Database=_database;Trusted_Connection=True;");
    }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Student>().Property(p => p.add_time).HasDefaultValueSql("getdate()");
        modelBuilder.Entity<Student>().Property(p => p.last_modify_time).HasComputedColumnSql("getdate()");
    }
}
public class Student
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int Id { set; get; }
    public string name { set; get; }
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public DateTime add_time { set; get; }
    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime last_modify_time { set; get; }
}

Because the Entity Framework doesn’t set up the actual mechanism to generate values. so it needs to be specified explicitly with fluent API.

modelBuilder.Entity<Student>().Property(p => p.add_time).HasDefaultValueSql("getdate()");
modelBuilder.Entity<Student>().Property(p => p.last_modify_time).HasComputedColumnSql("getdate()");

operate code example:

using (var context = new SchoolContext()) {
    context.student.Add(new Student(){Id = 1,name = "curry"});
    context.SaveChanges();

    Student _student = context.student.Where<Student>(_st => _st.Id == 1).FirstOrDefault();
    Console.WriteLine("name:{0}", _student.name);
    Console.WriteLine("addtime:{0}", _student.add_time);
    Console.WriteLine("last_modify_time:{0}", _student.last_modify_time);
    _student.name = "curry1";
    context.SaveChanges();

    Thread.Sleep(1000);
    _student = context.student.Where<Student>(_st => _st.Id == 1).FirstOrDefault();
    Console.WriteLine("-------------------------");
    Console.WriteLine("name:{0}", _student.name);
    Console.WriteLine("addtime:{0}", _student.add_time);
    Console.WriteLine("last_modify_time:{0}", _student.last_modify_time);
}

the output:

name:curry
addtime:2020/4/9 22:58:51
last_modify_time:2020/4/9 22:58:51
-------------------------
name:curry1
addtime:2020/4/9 22:58:51
last_modify_time:2020/4/9 22:58:52

Comments