{"record":{"id":"30ec55e0d6c6c7ab","repo":"dotnet/efcore","slug":"the-keyless-entity-type-entitytype-was-configu","errorCode":null,"errorMessage":"The keyless entity type '{entityType}' was configured to use '{sproc}'. An entity type requires a primary key to be able to be mapped to a stored procedure.","messagePattern":"The keyless entity type '(.+?)' was configured to use '(.+?)'\\. An entity type requires a primary key to be able to be mapped to a stored procedure\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":573,"sourceCode":"                        mappedTypes[0].DisplayName(),\n                        mappedType.DisplayName(),\n                        storedProcedure.DisplayName()));\n            }\n        }\n    }\n\n    private static void ValidateSproc(\n        IStoredProcedure sproc,\n        string mappingStrategy,\n        IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)\n    {\n        var entityType = sproc.EntityType;\n        var storeObjectIdentifier = sproc.GetStoreIdentifier();\n\n        var primaryKey = entityType.FindPrimaryKey();\n        if (primaryKey == null)\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.StoredProcedureKeyless(\n                    entityType.DisplayName(), storeObjectIdentifier.DisplayName()));\n        }\n\n        var properties = entityType.GetDeclaredProperties().ToDictionary(p => p.Name);\n        if (mappingStrategy == RelationalAnnotationNames.TphMappingStrategy)\n        {\n            if (entityType.BaseType != null)\n            {\n                return;\n            }\n\n            foreach (var property in entityType.GetDerivedProperties())\n            {\n                properties.Add(property.Name, property);\n            }\n        }\n        else if (mappingStrategy == RelationalAnnotationNames.TpcMappingStrategy)","sourceCodeStart":555,"sourceCodeEnd":591,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L555-L591","documentation":"Thrown when a keyless entity type (no primary key, HasNoKey) is mapped to a stored procedure. Stored procedures require a primary key to identify rows for insert/update/delete operations; the validator rejects a null primary key in ValidateSproc.","triggerScenarios":"Configuring Insert/Update/Delete sprocs on a query type or a HasNoKey() entity; converting a keyless view entity to sproc-based mapping.","commonSituations":"Treating a read-only/keyless projection as if it were writable; sproc config copied from a keyed entity onto a keyless one.","solutions":["Define a primary key on the entity (HasKey) so it can be identified for sproc operations.","Or remove the stored procedure mapping and keep the entity as a query/view (read-only)."],"exampleFix":"// before\nmodelBuilder.Entity<BlogStat>().HasNoKey().InsertStoredProcedure(\"sp_InsertStat\");\n\n// after\nmodelBuilder.Entity<BlogStat>().HasKey(x => x.Id).InsertStoredProcedure(\"sp_InsertStat\");","handlingStrategy":"validation","validationCode":"foreach (var et in modelBuilder.Model.GetEntityTypes())\n{\n    if (et.FindPrimaryKey() == null && (et.GetInsertStoredProcedure() != null || et.GetUpdateStoredProcedure() != null || et.GetDeleteStoredProcedure() != null))\n        throw new InvalidOperationException($\"Keyless {et.DisplayName()} cannot be mapped to sprocs\");\n}","typeGuard":null,"tryCatchPattern":"try { _ = ctx.Model; } catch (InvalidOperationException ex) when (ex.Message.Contains(\"requires a primary key\")) { /* add a key or remove the sproc mapping */ }","preventionTips":["Never configure sprocs on HasNoKey entities.","Keep keyless read models separate from writable, keyed entities."],"tags":["ef-core","stored-procedures","keyless","model-validation","configuration"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}