PostgreSQL Enum Type Not Found When Using Non-Public Schema
Maintainer antworten meist innerhalb von 1 Tag
Dieses Issue hat noch niemand übernommen.
Bewertung
- Schwierigkeit
- 4/5
- Geschätzter Aufwand
- 3-5 Tage
- Anfängerfreundlichkeit
- 25/100
Rechercherichtung
Start by reproducing the reported query with the provided PostgreSQL schema and C# EF Core example, then inspect the provider's enum type handling during SQL generation. The issue does not name source files or tests, so locate the relevant code and regression-test entry point from that reproduction. Done means the generated comparison qualifies the enum type as app.mood and the query succeeds.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Beschreibung
Bug Description
Entity Framework Core queries fail when filtering on enum properties where the PostgreSQL enum type is defined in a non-public schema. The generated SQL incorrectly references the enum type without the schema qualifier, causing a "type does not exist" error.
Expected Behavior
EF Core should generate SQL that properly qualifies enum types with their schema name when the enum is not in the public schema, similar to how it handles table names.
Actual Behavior
The generated SQL uses unqualified enum type names (e.g., 'happy'::mood) instead of schema-qualified names (e.g., 'happy'::app.mood), resulting in PostgreSQL error: 42704: type "mood" does not exist.
Reproduction Steps
Database Setup
CREATE SCHEMA app;
SET search_path TO app;
CREATE TYPE mood AS ENUM ('sad', 'ok', 'happy');
CREATE TABLE person (
name text,
current_mood mood
);
INSERT INTO person VALUES ('Moe', 'happy');
C# Code
using Microsoft.EntityFrameworkCore;
using var db = new AppContext();
// Query that fails
var list = db.Persons.Where(x => x.CurrentMood == Mood.Happy).ToList();
Console.WriteLine($"Found {list.Count} persons with mood Happy");
internal class PersonEntity
{
public string? Name { get; set; }
public Mood CurrentMood { get; set; }
}
internal enum Mood { Sad, Ok, Happy }
internal class AppContext : DbContext
{
public virtual DbSet<PersonEntity> Persons { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.LogTo(Console.WriteLine).EnableSensitiveDataLogging();
options.UseNpgsql(
"Username=test;Password=test;Host=localhost;Port=5432;Database=d_app;",
builder => { builder.MapEnum<Mood>("mood"); });
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("app");
modelBuilder.Entity<PersonEntity>(
entity =>
{
entity.HasKey(e => e.Name);
entity.ToTable("person");
entity.Property(e => e.Name).HasColumnName("name");
entity.Property(e => e.CurrentMood).HasColumnName("current_mood");
});
}
}
Error Details
Generated SQL (Incorrect):
SELECT p.name, p.current_mood
FROM app.person AS p
WHERE p.current_mood = 'happy'::mood
Expected SQL:
SELECT p.name, p.current_mood
FROM app.person AS p
WHERE p.current_mood = 'happy'::app.mood
PostgreSQL Error:
Npgsql.PostgresException (0x80004005): 42704: type "mood" does not exist
Full Logs
dbug: 27.06.2025 21:04:59.716 CoreEventId.ContextInitialized[10403] (Microsoft.EntityFrameworkCore.Infrastructure)
Entity Framework Core 9.0.1 initialized 'AppContext' using provider 'Npgsql.EntityFrameworkCore.PostgreSQL:9.0.4+fd2380957bee5cd86f336466af36b08c0163f1a5' with options: None
dbug: 27.06.2025 21:04:59.757 CoreEventId.QueryCompilationStarting[10111] (Microsoft.EntityFrameworkCore.Query)
Compiling query expression:
'DbSet<PersonEntity>()
.Where(x => (int)x.CurrentMood == 2)'
dbug: 27.06.2025 21:04:59.993 CoreEventId.QueryExecutionPlanned[10107] (Microsoft.EntityFrameworkCore.Query)
Generated query execution expression:
'queryContext => SingleQueryingEnumerable.Create<PersonEntity>(
relationalQueryContext: (RelationalQueryContext)queryContext,
relationalCommandResolver: parameters => [LIFTABLE Constant: RelationalCommandCache.QueryExpression(
Projection Mapping:
EmptyProjectionMember -> Dictionary<IProperty, int> { [Property: PersonEntity.Name (string) Required PK AfterSave:Throw, 0], [Property: PersonEntity.CurrentMood (Mood) Required, 1] }
SELECT p.name, p.current_mood
FROM app.person AS p
WHERE p.current_mood == 'happy'::mood) | Resolver: c => new RelationalCommandCache(
c.Dependencies.MemoryCache,
c.RelationalDependencies.QuerySqlGeneratorFactory,
c.RelationalDependencies.RelationalParameterBasedSqlProcessorFactory,
Projection Mapping:
EmptyProjectionMember -> Dictionary<IProperty, int> { [Property: PersonEntity.Name (string) Required PK AfterSave:Throw, 0], [Property: PersonEntity.CurrentMood (Mood) Required, 1] }
SELECT p.name, p.current_mood
FROM app.person AS p
WHERE p.current_mood == 'happy'::mood,
False,
new HashSet<string>(
new string[]{ },
StringComparer.Ordinal
)
)].GetRelationalCommandTemplate(parameters),
readerColumns: null,
shaper: (queryContext, dataReader, resultContext, resultCoordinator) =>
{
PersonEntity entity;
entity =
{
MaterializationContext materializationContext1;
IEntityType entityType1;
PersonEntity instance1;
InternalEntityEntry entry1;
bool hasNullKey1;
materializationContext1 = new MaterializationContext(
[LIFTABLE Constant: ValueBuffer | Resolver: _ => (object)ValueBuffer.Empty],
queryContext.Context
);
instance1 = default(PersonEntity);
entry1 = queryContext.TryGetEntry(
key: [LIFTABLE Constant: Key: PersonEntity.Name PK | Resolver: c => c.Dependencies.Model.FindEntityType("PersonEntity").FindPrimaryKey()],
keyValues: new object[]{ (object)dataReader.GetString(0) },
throwOnNullKey: True,
hasNullKey: hasNullKey1);
!(hasNullKey1) ? entry1 != default(InternalEntityEntry) ?
{
entityType1 = entry1.EntityType;
return instance1 = (PersonEntity)entry1.Entity;
} :
{
ISnapshot shadowSnapshot1;
shadowSnapshot1 = [LIFTABLE Constant: Snapshot | Resolver: _ => Snapshot.Empty];
entityType1 = [LIFTABLE Constant: EntityType: PersonEntity | Resolver: namelessParameter{0} => namelessParameter{0}.Dependencies.Model.FindEntityType("PersonEntity")];
instance1 = switch (entityType1)
{
case [LIFTABLE Constant: EntityType: PersonEntity | Resolver: namelessParameter{1} => namelessParameter{1}.Dependencies.Model.FindEntityType("PersonEntity")]:
{
return
{
PersonEntity instance;
instance = new PersonEntity();
instance.<Name>k__BackingField = dataReader.GetString(0);
instance.<CurrentMood>k__BackingField = dataReader.GetFieldValue<Mood>(1);
(instance is IInjectableService) ? ((IInjectableService)instance).Injected(
context: materializationContext1.Context,
entity: instance,
queryTrackingBehavior: TrackAll,
structuralType: [LIFTABLE Constant: EntityType: PersonEntity | Resolver: namelessParameter{2} => namelessParameter{2}.Dependencies.Model.FindEntityType("PersonEntity")]) : default(void);
return instance;
}}
default:
default(PersonEntity)
}
;
entry1 = entityType1 == default(IEntityType) ? default(InternalEntityEntry) : queryContext.StartTracking(
entityType: entityType1,
entity: instance1,
snapshot: shadowSnapshot1);
return instance1;
} : default(void);
return instance1;
};
return entity;
},
contextType: AppContext,
standAloneStateManager: False,
detailedErrorsEnabled: False,
threadSafetyChecksEnabled: True)'
dbug: 27.06.2025 21:05:00.038 RelationalEventId.ConnectionCreating[20005] (Microsoft.EntityFrameworkCore.Database.Connection)
Creating DbConnection.
dbug: 27.06.2025 21:05:00.045 RelationalEventId.ConnectionCreated[20006] (Microsoft.EntityFrameworkCore.Database.Connection)
Created DbConnection. (6ms).
dbug: 27.06.2025 21:05:00.049 RelationalEventId.ConnectionOpening[20000] (Microsoft.EntityFrameworkCore.Database.Connection)
Opening connection to database 'd_app' on server 'tcp://localhost:5432'.
dbug: 27.06.2025 21:05:00.172 RelationalEventId.ConnectionOpened[20001] (Microsoft.EntityFrameworkCore.Database.Connection)
Opened connection to database 'd_app' on server 'tcp://localhost:5432'.
dbug: 27.06.2025 21:05:00.182 RelationalEventId.CommandCreating[20103] (Microsoft.EntityFrameworkCore.Database.Command)
Creating DbCommand for 'ExecuteReader'.
dbug: 27.06.2025 21:05:00.187 RelationalEventId.CommandCreated[20104] (Microsoft.EntityFrameworkCore.Database.Command)
Created DbCommand for 'ExecuteReader' (5ms).
dbug: 27.06.2025 21:05:00.188 RelationalEventId.CommandInitialized[20106] (Microsoft.EntityFrameworkCore.Database.Command)
Initialized DbCommand for 'ExecuteReader' (8ms).
dbug: 27.06.2025 21:05:00.194 RelationalEventId.CommandExecuting[20100] (Microsoft.EntityFrameworkCore.Database.Command)
Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT p.name, p.current_mood
FROM app.person AS p
WHERE p.current_mood = 'happy'::mood
fail: 27.06.2025 21:05:00.230 RelationalEventId.CommandError[20102] (Microsoft.EntityFrameworkCore.Database.Command)
Failed executing DbCommand (34ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
SELECT p.name, p.current_mood
FROM app.person AS p
WHERE p.current_mood = 'happy'::mood
dbug: 27.06.2025 21:05:00.233 RelationalEventId.ConnectionClosing[20002] (Microsoft.EntityFrameworkCore.Database.Connection)
Closing connection to database 'd_app' on server 'tcp://localhost:5432'.
dbug: 27.06.2025 21:05:00.240 RelationalEventId.ConnectionClosed[20003] (Microsoft.EntityFrameworkCore.Database.Connection)
Closed connection to database 'd_app' on server 'tcp://localhost:5432' (5ms).
fail: 27.06.2025 21:05:00.262 CoreEventId.QueryIterationFailed[10100] (Microsoft.EntityFrameworkCore.Query)
An exception occurred while iterating over the results of a query for context type 'AppContext'.
Npgsql.PostgresException (0x80004005): 42704: type "mood" does not exist
POSITION: 86
at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult()
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior)
at Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(Enumerator enumerator)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.<>c.<MoveNext>b__21_0(DbContext _, Enumerator enumerator)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
Exception data:
Severity: ERROR
SqlState: 42704
MessageText: type "mood" does not exist
Position: 86
File: parse_type.c
Line: 270
Routine: typenameType
Unhandled exception. Npgsql.PostgresException (0x80004005): 42704: type "mood" does not exist
POSITION: 86
at Npgsql.Internal.NpgsqlConnector.ReadMessageLong(Boolean async, DataRowLoadingMode dataRowLoadingMode, Boolean readingNotifications, Boolean isReadingPrependedMessage)
at System.Runtime.CompilerServices.PoolingAsyncValueTaskMethodBuilder`1.StateMachineBox`1.System.Threading.Tasks.Sources.IValueTaskSource<TResult>.GetResult(Int16 token)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult(Boolean async, Boolean isConsuming, CancellationToken cancellationToken)
at Npgsql.NpgsqlDataReader.NextResult()
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(Boolean async, CommandBehavior behavior, CancellationToken cancellationToken)
at Npgsql.NpgsqlCommand.ExecuteReader(CommandBehavior behavior)
at Npgsql.NpgsqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.InitializeReader(Enumerator enumerator)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.<>c.<MoveNext>b__21_0(DbContext _, Enumerator enumerator)
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
at Program.<Main>$(String[] args) in C:\Projekte\testing\NpgsqlEnumBug\NpgsqlEnumBug\Program.cs:line 5
Exception data:
Severity: ERROR
SqlState: 42704
MessageText: type "mood" does not exist
Position: 86
File: parse_type.c
Line: 270
Routine: typenameType
dbug: 27.06.2025 21:05:02.274 CoreEventId.ContextDisposed[10407] (Microsoft.EntityFrameworkCore.Infrastructure)
'AppContext' disposed.
dbug: 27.06.2025 21:05:02.276 RelationalEventId.ConnectionDisposing[20007] (Microsoft.EntityFrameworkCore.Database.Connection)
Disposing connection to database 'd_app' on server 'tcp://localhost:5432'.
dbug: 27.06.2025 21:05:02.277 RelationalEventId.ConnectionDisposed[20008] (Microsoft.EntityFrameworkCore.Database.Connection)
Disposed connection to database 'd_app' on server 'tcp://localhost:5432' (0ms).
Workaround
Moving the enum type to the public schema resolves the issue:
Environment
- Npgsql Version: 9.0.3
- Entity Framework Core Version: 9.0.4
- PostgreSQL Version: PostgreSQL 17.5 (Debian 17.5-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit
- .NET Version: 8
Reproduction Repository
Complete reproduction case available at: https://github.com/can-oezkan/npgsql-enum-bug
To reproduce:
- Clone the repository
- Run
docker compose -f 'compose.yml' up -d --buildto start PostgreSQL - Run
dotnet run --project .\NpgsqlEnumBug\ro run the .NET project - Observe the error
- Vorherrschende Sprache
- C#
- Sterne
- 1.8k
- Forks
- 268
- Ø Merge
- 2 Std. 35 Min.
- Gemergte PRs (30 T.)
- 136
Entwicklungsumgebung
Dieses Projekt bietet weder Dev-Container noch Dockerfile noch Beitragsleitfaden – die Einrichtung liegt bei Ihnen. Beginnen Sie mit der README; die allgemeinen Schritte stehen in unserem Leitfaden für den ersten Beitrag.
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus npgsql/efcore.pg
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
Maintainer antworten meist innerhalb von 1 Tag
-
NTS: the M ordinate is dropped from geometry SQL literals and from geometries stored in JSONEvtl. vergeben @Ahmed7991 hat das vor 5 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 85/100
npgsql/efcore.pg#4093 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
-
`TimeSpan`/`Duration` component members: negative values are floored, and intervals computed in SQL are read field by fieldEvtl. vergeben @jeremy-morren hat das vor 11 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 70/100
Maintainer antworten meist innerhalb von 1 Tag
-
Numeric storage parameters are formatted with the current culture, so migrations emit 0,01 instead of 0.01Evtl. vergeben @Sorbitol hat das vor 12 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 30/100
Maintainer antworten meist innerhalb von 1 Tag
-
`Contains` on a JSON primitive collection compares JSON text, so `DateTime` and `TimeOnly` items never matchEvtl. vergeben @Mr444-dev hat das vor 7 Tagen übernommen. Offen
Schwierigkeit 4/5 3-5 Tage Anfängerfreundlichkeit 45/100
npgsql/efcore.pg#4099 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 1 Tag
Alle Issues in npgsql/efcore.pg
Ähnliche Issues
-
Issue-Bug Needs-Triage
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
Maintainer antworten meist innerhalb von 2 Tagen
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 66/100
JiaFeiMiao-K-Cat/DiscImageStudio#281 ·
Maintainer antworten meist innerhalb von 1 Tag
-
area/access-management Frontend onboarding candidate :handshake:
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 65/100
Altinn/altinn-auth#4941 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
aws/aws-sdk-net#4586 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
Kryptos-FR/MarkView.Avalonia#269 · 1 Reaktion ·
Maintainer antworten meist innerhalb von 1 Tag