From 5d41f5c42bfbb417e422cfb0b523d3cca9c4da49 Mon Sep 17 00:00:00 2001 From: "F.D.Castel" Date: Mon, 23 Mar 2026 01:38:57 -0300 Subject: [PATCH] GetIndexesQuery: Exclude expression indexes at the database level. Fix #1188. --- .../Scaffolding/ScaffoldingTests.cs | 48 +++++++++++++++++++ .../Internal/FbDatabaseModelFactory.cs | 9 +++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Scaffolding/ScaffoldingTests.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Scaffolding/ScaffoldingTests.cs index 18e903462..4b33cb2eb 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Scaffolding/ScaffoldingTests.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird.Tests/Scaffolding/ScaffoldingTests.cs @@ -107,6 +107,54 @@ public async Task ReadsCorrectFieldType(string dataType) Assert.That(column.StoreType, Is.EqualTo(dataType)); } + [Test] + public async Task ExpressionIndexDoesNotBreakScaffolding() + { + var tableName = "TEST_EXPR_IDX"; + + using var commandTable = Connection.CreateCommand(); + commandTable.CommandText = $"recreate table {tableName} (ID INTEGER NOT NULL, DATA VARCHAR(100))"; + await commandTable.ExecuteNonQueryAsync(); + + using var commandIndex = Connection.CreateCommand(); + commandIndex.CommandText = $"create index IDX_EXPR on {tableName} computed by (upper(DATA))"; + await commandIndex.ExecuteNonQueryAsync(); + + var modelFactory = GetModelFactory(); + var model = modelFactory.Create(Connection.ConnectionString, new DatabaseModelFactoryOptions(new string[] { tableName })); + var table = model.Tables.Single(x => x.Name == tableName); + + Assert.That(table.Indexes, Has.None.Matches(x => x.Name == "IDX_EXPR")); + } + + [Test] + public async Task RegularIndexScaffoldedAlongsideExpressionIndex() + { + var tableName = "TEST_MIX_IDX"; + + using var commandTable = Connection.CreateCommand(); + commandTable.CommandText = $"recreate table {tableName} (ID INTEGER NOT NULL, DATA VARCHAR(100))"; + await commandTable.ExecuteNonQueryAsync(); + + using var commandRegularIndex = Connection.CreateCommand(); + commandRegularIndex.CommandText = $"create index IDX_REGULAR on {tableName} (DATA)"; + await commandRegularIndex.ExecuteNonQueryAsync(); + + using var commandExprIndex = Connection.CreateCommand(); + commandExprIndex.CommandText = $"create index IDX_EXPR_MIX on {tableName} computed by (upper(DATA))"; + await commandExprIndex.ExecuteNonQueryAsync(); + + var modelFactory = GetModelFactory(); + var model = modelFactory.Create(Connection.ConnectionString, new DatabaseModelFactoryOptions(new string[] { tableName })); + var table = model.Tables.Single(x => x.Name == tableName); + + Assert.Multiple(() => + { + Assert.That(table.Indexes, Has.Some.Matches(x => x.Name == "IDX_REGULAR")); + Assert.That(table.Indexes, Has.None.Matches(x => x.Name == "IDX_EXPR_MIX")); + }); + } + static IDatabaseModelFactory GetModelFactory() { return new FbDatabaseModelFactory(); diff --git a/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs b/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs index a636e2cb5..d99193722 100644 --- a/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs +++ b/src/FirebirdSql.EntityFrameworkCore.Firebird/Scaffolding/Internal/FbDatabaseModelFactory.cs @@ -319,6 +319,7 @@ private void GetPrimaryKeys(DbConnection connection, IReadOnlyList ta { while (reader.Read()) { + var columns = reader.IsDBNull(3) ? string.Empty : reader.GetString(3); + if (string.IsNullOrEmpty(columns)) + { + continue; + } + var index = new DatabaseIndex { Table = table, @@ -344,7 +351,7 @@ private void GetIndexes(DbConnection connection, IReadOnlyList ta IsUnique = reader.GetBoolean(1), }; - foreach (var column in reader.GetString(3).Split(',')) + foreach (var column in columns.Split(',')) { index.Columns.Add(table.Columns.Single(y => y.Name == column.Trim())); }