Entity Framework auto generate GUID

I am new to EF so here goes.I have a class which contains the following

public class EmailTemplate
{
    public Guid Id { get; set; }

    [MaxLength(2000)]
    public string Html { get; set; }
}

Here is my mapping class

class EmailMapper : EntityTypeConfiguration<EmailTemplate>
    {
        public EmailMapper()
        {
            ToTable("EmailTemplate");

            HasKey(c => c.Id);
            Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
            Property(c => c.Id).IsRequired();
        }
    }

I am trying to call DbContext.SaveChanges(), but I get the following error :

Exception Details: System.Data.SqlClient.SqlException: Cannot insert the value NULL into column 'Id', table 'AutoSendConnection.dbo.EmailTemplates'; column does not allow nulls. INSERT fails.

What am i doing wrong? Why won't EF auto create a unique GUID?


Just decorate the Id field on your EmailTemplate class as below and SQL Server will automatically generate the value on insert.

[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }

You can also remove your Mapper class as it's no longer needed.


If using .Net core then this should work for you ...

Use fluent API

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Node>().Property(x => x.ID).HasDefaultValueSql("NEWID()");
}

or

modelBuilder.Entity<Student>().Property(p => p.StudentID)
                .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);

Here is a more comprehensive Cheat Sheet for entity framework


Addressing other answers here

None of these other options seem to work and I've questioned this time and time again with the EF team over on github ...

https://github.com/aspnet/EntityFramework6/issues/762

... for some reason the EF dev team seem to think that this is "working by design" and repeatedly close tickets questioning this "bug".

The EF team explanation

For some reason they seem to think that "generating Guids in SQL is considered not best practice and that to ensure the keys are available immediately we should be generating the keys in the app code".

The issue here of course is that highly populated tables run the risk of you taking further business actions consuming an invalid key.

In my case this could break some extremely complex multi server DTC transactions so I don't believe the advice from MS to be correct, that said EF Core doesn't currently support distributed transactions at all so in a focused context they may have a point.

My answer (which actually works)

In short, I solved this by "manually hacking" the generated migration after generating it ...

EF code first migrations, DB generated guid keys

To quote the other question the answer is as follows:

Generate the migration script as you normally would putting both attributes on the key property like this ...

public class Foo
{
     [Key]
     [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
     public Guid Id { get; set; }
}

... declaratively speaking the entity is now correct.

The migration it will generate will look something like:

CreateTable(
    "dbo.Foos",
    c => new
        {
            Id = c.Guid(nullable: false),
            ...
        })
    .PrimaryKey(t => t.Id)
    ...;

... I have not been able to pin down why, but in some situations this will work and in others it won't (run the migration, perform an insert to test).

If it fails, roll the migration back then modify it to read something like ...

CreateTable(
    "dbo.Foos",
    c => new
        {
            Id = c.Guid(nullable: false, defaultValueSql: "newid()"),
            ...
        })
    .PrimaryKey(t => t.Id)
    ...;

... the extra code here tells SQL to generate the key as we would expect.

As a rule of thumb I would apply this change all the time for consistency reasons and it means that at a glance your migrations will show you exactly what keys are db generated and of course which ones don't.


After a long investigation, I found out that in EF Core 3.1 you need to use

builder.Property(e => e.Id).ValueGeneratedOnAdd();

Set the default sql value of the field to 'newsequentialid()' in the mapping configuration.