{"record":{"id":"d6020da0885eccd7","repo":"dotnet/efcore","slug":"cannot-create-a-selectexpression-with-a-custom","errorCode":null,"errorMessage":"Cannot create a 'SelectExpression' with a custom 'TableExpressionBase' since the result type '{entityType}' is part of a hierarchy and does not contain a discriminator property.","messagePattern":"Cannot create a 'SelectExpression' with a custom 'TableExpressionBase' since the result type '(.+?)' is part of a hierarchy and does not contain a discriminator property\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.CreateSelect.cs","lineNumber":665,"sourceCode":"            complexProperty.ClrType,\n            complexProperty.IsCollection);\n\n        return complexProperty.IsCollection\n            ? new CollectionResultExpression(jsonQuery, complexProperty, elementType: complexType.ClrType)\n            : new RelationalStructuralTypeShaperExpression(complexType, jsonQuery, isNullable);\n    }\n\n    /// <summary>\n    ///     Used to create a <see cref=\"SelectExpression\" /> representing a query of the given entity type, when its table expression has\n    ///     already been constructed externally. This overload is used for cases such as <see cref=\"FromSqlExpression\" />,\n    ///     <see cref=\"TableValuedFunctionExpression\" />, etc.\n    /// </summary>\n    private SelectExpression CreateSelect(IEntityType entityType, TableExpressionBase tableExpressionBase)\n    {\n        if ((entityType.BaseType != null || entityType.GetDirectlyDerivedTypes().Any())\n            && entityType.FindDiscriminatorProperty() == null)\n        {\n            throw new InvalidOperationException(RelationalStrings.SelectExpressionNonTphWithCustomTable(entityType.DisplayName()));\n        }\n\n        if (tableExpressionBase is not ITableBasedExpression { Table: ITableBase table })\n        {\n            throw new UnreachableException(\"SelectExpression with unexpected missing table\");\n        }\n\n        var select = GenerateSingleTableSelect(entityType, table, tableExpressionBase);\n        AddEntitySelectConditions(select, entityType);\n\n        return select;\n    }\n\n    /***\n     * We need to add additional conditions on basic SelectExpression for certain cases\n     * - If we are selecting from TPH then we need to add condition for discriminator if mapping is incomplete\n     * - When we are selecting optional dependent sharing table, we need to add condition to figure out existence\n     *  ** Optional Dependent **","sourceCodeStart":647,"sourceCodeEnd":683,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Query/RelationalQueryableMethodTranslatingExpressionVisitor.CreateSelect.cs#L647-L683","documentation":"CreateSelect(IEntityType, TableExpressionBase) builds a SelectExpression over an externally-constructed table (FromSqlExpression, TableValuedFunctionExpression, ...). It refuses entity types that participate in an inheritance hierarchy but have no discriminator property, because EF needs a discriminator column to distinguish concrete types within the single composed SQL. TPT/TPC hierarchies or unmapped discriminators therefore cannot be used with FromSql*/TVF roots.","triggerScenarios":"context.Set<BaseEntity>().FromSqlRaw(\"SELECT * FROM vw_Base\") where BaseEntity has derived types but no discriminator configured; using a TVF (HasDbFunction -> HasTranslation returning a TableValuedFunctionExpression) over a hierarchy root without a discriminator; calling FromSqlInterpolated on a TPT-mapped hierarchy root.","commonSituations":"Migrating a query to FromSql/TVF on an entity that was later added to an inheritance hierarchy; TPT/TPC hierarchies where discriminators are not configured; view-backed entities participating in inheritance.","solutions":["Configure a discriminator on the hierarchy (TPH) so EF can distinguish types: modelBuilder.Entity<Base>().HasDiscriminator(b => b.Type).","Avoid FromSql*/TVF roots on hierarchy roots; instead target a concrete (leaf) entity type that is not part of a hierarchy, or remap to TPH.","If TPT/TPC is required, query through regular LINQ (not FromSql) so EF can emit per-table SELECTs."],"exampleFix":"// before (hierarchy root, no discriminator)\nvar q = db.Set<BaseEntity>().FromSqlRaw(\"SELECT * FROM base_view\").Where(b => b.Active);\n// after (configure TPH discriminator)\nmodelBuilder.Entity<BaseEntity>()\n    .HasDiscriminator<string>(\"Discriminator\")\n    .IsComplete();\nvar q = db.Set<BaseEntity>().FromSqlRaw(\"SELECT * FROM base_view\").Where(b => b.Active);","handlingStrategy":"validation","validationCode":"// Before FromSql*/TVF over a hierarchy, ensure a discriminator exists.\nvar et = db.Model.FindEntityType(typeof(BaseEntity))!;\nbool inHierarchy = et.BaseType is not null || et.GetDirectlyDerivedTypes().Any();\nbool hasDiscriminator = et.FindDiscriminatorProperty() is not null;\nif (inHierarchy && !hasDiscriminator)\n    throw new InvalidOperationException(\"Configure a TPH discriminator before using FromSql/TVF on this hierarchy.\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use FromSql*/TVF only on TPH hierarchies with a discriminator configured.","Avoid FromSql* on TPT/TPC roots; query through regular LINQ instead.","Add an integration test that exercises FromSql on every hierarchy root in the model."],"tags":["efcore","inheritance","fromsql","discriminator","select-expression"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}