Hacktoberfest 2026: the issues maintainers tagged for October, open and beginner-friendly. Browse Hacktoberfest issues

Error: "No primary key was found in the database for table Table TestEntities" when using Database Migration to Spanner with EntityFramework

Open
#636 0 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
45/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
csharp
Domain
databases

Research direction

Start by reproducing the issue with the shown TestDbContext, its TestEntities DbSet, the migration, and SpannerEmulator. Read the provider's SpannerModelValidationConnectionProvider behavior around migrations and model validation; done means the migration creates the primary key and validation succeeds without globally disabling database model validation.

Written by the indexing model from the issue text.

Description

Description

When using Google.Cloud.EntityFrameworkCore.Spanner with EF Core migrations, creating a table via migrationBuilder.CreateTable(...) results in the error above:

No primary key was found in the database for table Table TestEntities.
Call SpannerModelValidationConnectionProvider.Instance.EnableDatabaseModelValidation(false)
to disable model validation if this error is a false positive.

It happens because the model validation starts before migrations are applied and therefore fails.
The only workaround suggested by the error message is disabling database model validation globally:

SpannerModelValidationConnectionProvider.Instance.EnableDatabaseModelValidation(false);

This is a significant behavioral change and not acceptable for production use.

Environment

EF Core version: 8.0.22
Google.Cloud.EntityFrameworkCore.Spanner version: 3.8.0
Database: Google Cloud Spanner
Migrations enabled ✅

Reproduction steps

Create a new C# Project with EF Core using the Spanner provider

Add the following migration:

20251216161442_InitialCreate.cs

public partial class InitialCreate : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "TestEntities",
            columns: table => new
            {
                Id = table.Column<Guid>(type: "STRING(36)", nullable: false),
                Name = table.Column<string>(type: "STRING", nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_TestEntities", x => x.Id);
            }
        );
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(name: "TestEntities");
    }
}

20251216161442_InitialCreate.Designer.cs

  [DbContext(typeof(TestDbContext))]
    [Migration("20251216161442_InitialCreate")]
    partial class InitialCreate
    {
        protected override void BuildTargetModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder.Entity("YOUR_NAMESPACE", b =>
            {
                b.Property<Guid>("Id")
                    .ValueGeneratedOnAdd()
                    .HasColumnType("STRING(36)");

                b.Property<string>("Name")
                    .IsRequired()
                    .HasColumnType("STRING");

                b.HasKey("Id");
                
                b.ToTable("TestEntities");
            });
#pragma warning restore 612, 618
        }
    }
 [DbContext(typeof(TestDbContext))]
    partial class TestDbContextModelSnapshot : ModelSnapshot
    {
        protected override void BuildModel(ModelBuilder modelBuilder)
        {
#pragma warning disable 612, 618
            modelBuilder.HasAnnotation("ProductVersion", "6.0.16");

            modelBuilder.Entity("YOUR_NAMESPACE", b =>
            {
                b.Property<Guid>("Id")
                    .HasColumnType("STRING(36)");

                b.Property<string>("Name")
                    .IsRequired()
                    .HasColumnType("STRING");

                b.HasKey("Id");
                
                b.ToTable("TestEntities");
            });
#pragma warning restore 612, 618
        }
    }
public class TestDbContext(DbContextOptions<TestDbContext> options, string connectionString)
    : DbContext(options)
{

    public virtual DbSet<TestEntity> TestEntities { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            optionsBuilder.UseSpanner(connectionString, options =>
            {
                options.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery);
            });
        }

        base.OnConfiguring(optionsBuilder);
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<TestEntity>(entity =>
        {
            entity.HasKey(it => it.Id);
            entity.ToTable("TestEntities");
        });
        base.OnModelCreating(modelBuilder);
    }
}

Important is to have this property as part of the DBContext. If it's not present, everything works as expected:

    public virtual DbSet<TestEntity> TestEntities { get; set; }

Start the application or integration test with SpannerEmulator and apply the migration to Cloud Spanner:

Expected behavior:
The generated Spanner table should have a primary key defined
EF Core model validation should succeed
No runtime error should occur

Actual behavior
On startup, EF Core throws:
Error Message Appears: No primary key was found in the database for table Table TestEntities. Call SpannerModelValidationConnectionProvider.Instance.EnableDatabaseModelValidation(false) to disable model validation if this error is a false positive.

Setting SpannerModelValidationConnectionProvider.Instance.EnableDatabaseModelValidation(false) fixes the issue but is inacceptable.

Thanks in advance!

Dominant language
C#
Stars
34
Forks
13
Avg merge
5h 53m
Merged PRs (30d)
11

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from googleapis/dotnet-spanner-entity-framework

All issues in googleapis/dotnet-spanner-entity-framework

Similar issues

More C# issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.