Data Annotations - DatabaseGenerated Attribute in EF 6 & EF Core

As you know, EF creates an IDENTITY column in the database for all the id (key) properties of the entity, by default. So, the underlying database generates a value for this column on each insert command, e.g., SQL Server creates an integer IDENTITY column with identity seed and increment to 1.

EF 6 and EF Core provide the DatabaseGenerated data annotation attribute to configure how the value of a property will be generated. The DatabaseGenerated attribute takes one out of the following three DatabaseGeneratedOption enum values:

  1. DatabaseGeneratedOption.None
  2. DatabaseGeneratedOption.Identity
  3. DatabaseGeneratedOption.Computed

DatabaseGeneratedOption.None

DatabaseGeneratedOption.None option specifies that the value of a property will not be generated by the underlying database. This will be useful to override the default convention for the id properties.

For example, if you want to provide your own values to id properties instead of database generated values, use the None option, as shown below.

public class Course
{
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int CourseId { get; set; }
    public string CourseName { get; set; }
}

In the above example, EF will create the CourseId column in the database and will not mark it as an IDENTITY column. So, each time you will have to provide the value of the CourseId property before calling the SaveChanges() method.

using (var context = new SchoolContext())
{
    // you must provide the unique CourseId value
    var maths = new Course(){ CourseId=1,  CourseName="Maths"};
    context.Courses.Add(maths);

    // you must provide the unique CourseId value
    var eng = new Course(){ CourseId=2,  CourseName="English"};
    context.Courses.Add(eng);

    // the following will throw an exception as CourseId has duplicate value
    //var sci = new Course(){ CourseId=2,  CourseName="sci"};

    context.SaveChanges();
}

Note: EF will throw an exception if you do not provide unique values each time because CourseId is a primary key property.

Use the ValueGeneratedNever() method of Fluent API to specify an Identity property in EF Core, as shown below.

modelBuilder.Entity<Course>()
    .Property(p => p.CourseId)
    .ValueGeneratedNever();

DatabaseGeneratedOption.Identity

You can mark the non-key (non-id) properties as DB-generated properties by using the DatabaseGeneratedOption.Identity option. This specifies that the value of the property will be generated by the database on the INSERT statement. This Identity property cannot be updated.

Please note that the way the value of the Identity property will be generated by the database depends on the database provider. It can be identity, rowversion or GUID. SQL Server makes an identity column for an integer property.

public class Course
{
    public int CourseId { get; set; }
    public string CourseName { get; set; }

    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int RecordNum { get; set; }
}

In the above example, the RecordNum property will be an identity property. This means that EF will create an IDENTITY column in the SQL Server database for this property.

Use the ValueGeneratedOnAdd() method of Fluent API to specify an Identity property in EF Core, as shown below.

modelBuilder.Entity<Course>()
    .Property(p => p.RecordNum)
    .ValueGeneratedOnAdd();

DatabaseGeneratedOption.Compute

DatabaseGeneratedOption.Compute specifies that the value of the property will be generated by the underlying database on insert and then, on each subsequent update. Also, EF will not include the property in the INSERT or UPDATE statements.

Same as Identity, the way the database generates the value depends on the database provider. You may configure a default value or use a trigger for this computed column.

Consider the following example.

public class Student
{
    public int StudentID { get; set; }
    public string StudentName { get; set; }
    public DateTime? DateOfBirth { get; set; }
    public decimal Height { get; set; }
    public float Weight { get; set; }

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

In the above example, the CreateOrUpdate property is marked with the DatabaseGeneratedOption.Computed option. So, SQL Server will generate a current datetime stamp on the INSERT and on each UPDATE statement. This way you can know when the record was last updated.

Use the ValueGeneratedOnAddOrUpdate() method of Fluent API to specify an Identity property in EF Core, as shown below.

modelBuilder.Entity<Course>()
    .Property(p => p.LastUpdated)
    .ValueGeneratedOnAddOrUpdate();