Error: "No primary key was found in the database for table Table TestEntities" when using Database Migration to Spanner with EntityFramework
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 45/100
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
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from googleapis/dotnet-spanner-entity-framework
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
googleapis/dotnet-spanner-entity-framework#775 ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
googleapis/dotnet-spanner-entity-framework#777 ·
Maintainers usually reply within 1 day
-
Difficulty 4/5 3-5 days Newbie friendliness 35/100
googleapis/dotnet-spanner-entity-framework#767 ·
Maintainers usually reply within 1 day
-
priority: p2 samples type: bug
Difficulty 4/5 3-5 days Newbie friendliness 45/100
googleapis/dotnet-spanner-entity-framework#722 ·
Maintainers usually reply within 1 day
-
priority: p2 type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 50/100
googleapis/dotnet-spanner-entity-framework#712 ·
Maintainers usually reply within 1 day
All issues in googleapis/dotnet-spanner-entity-framework
Similar issues
-
WPF: each page's `Title` overwrites the window title, and returning to a page does not restore itOpen
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
Maintainers usually reply within 1 day
-
agentic-workflows area/Docs partner/agentic-workflows
Difficulty 1/5 Under an hour Newbie friendliness 82/100
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
jamesmontemagno/tiny-clips#378 · 2 comments ·
Maintainers usually reply within 1 day
-
go 🏃 testing 🧪
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
valkey-io/valkey-glide#7239 ·
Maintainers usually reply within 2 days
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
SubtitleEdit/subtitleedit#15462 ·
Maintainers usually reply within 1 day