Skip to content

Commit be2d386

Browse files
committed
Fix migration history table lookup (#2788)
(cherry picked from commit 9418c25)
1 parent 0770cc8 commit be2d386

File tree

2 files changed

+198
-18
lines changed

2 files changed

+198
-18
lines changed

src/EFCore.PG/Migrations/Internal/NpgsqlHistoryRepository.cs

+9-18
Original file line numberDiff line numberDiff line change
@@ -31,26 +31,17 @@ protected override string ExistsSql
3131
{
3232
get
3333
{
34-
var builder = new StringBuilder();
35-
36-
builder.Append("SELECT EXISTS (SELECT 1 FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace WHERE ");
37-
3834
var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));
3935

40-
if (TableSchema is not null)
41-
{
42-
builder
43-
.Append("n.nspname=")
44-
.Append(stringTypeMapping.GenerateSqlLiteral(TableSchema))
45-
.Append(" AND ");
46-
}
47-
48-
builder
49-
.Append("c.relname=")
50-
.Append(stringTypeMapping.GenerateSqlLiteral(TableName))
51-
.Append(");");
52-
53-
return builder.ToString();
36+
return
37+
$"""
38+
SELECT EXISTS (
39+
SELECT 1 FROM pg_catalog.pg_class c
40+
JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace
41+
WHERE n.nspname={stringTypeMapping.GenerateSqlLiteral(TableSchema ?? "public")} AND
42+
c.relname={stringTypeMapping.GenerateSqlLiteral(TableName)}
43+
)
44+
""";
5445
}
5546
}
5647

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
using Npgsql.EntityFrameworkCore.PostgreSQL.TestUtilities;
2+
3+
namespace Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
4+
5+
public class NpgsqlHistoryRepositoryTest
6+
{
7+
[ConditionalFact]
8+
public void GetCreateScript_works()
9+
{
10+
var sql = CreateHistoryRepository().GetCreateScript();
11+
12+
Assert.Equal(
13+
"""
14+
CREATE TABLE "__EFMigrationsHistory" (
15+
"MigrationId" character varying(150) NOT NULL,
16+
"ProductVersion" character varying(32) NOT NULL,
17+
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
18+
);
19+
20+
""", sql, ignoreLineEndingDifferences: true);
21+
}
22+
23+
[ConditionalFact]
24+
public void GetCreateScript_works_with_schema()
25+
{
26+
var sql = CreateHistoryRepository("my").GetCreateScript();
27+
28+
Assert.Equal(
29+
"""
30+
DO $EF$
31+
BEGIN
32+
IF NOT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = 'my') THEN
33+
CREATE SCHEMA my;
34+
END IF;
35+
END $EF$;
36+
CREATE TABLE my."__EFMigrationsHistory" (
37+
"MigrationId" character varying(150) NOT NULL,
38+
"ProductVersion" character varying(32) NOT NULL,
39+
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
40+
);
41+
42+
""", sql, ignoreLineEndingDifferences: true);
43+
}
44+
45+
[ConditionalFact]
46+
public void GetCreateIfNotExistsScript_works()
47+
{
48+
var sql = CreateHistoryRepository().GetCreateIfNotExistsScript();
49+
50+
Assert.Equal(
51+
"""
52+
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
53+
"MigrationId" character varying(150) NOT NULL,
54+
"ProductVersion" character varying(32) NOT NULL,
55+
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
56+
);
57+
58+
""", sql, ignoreLineEndingDifferences: true);
59+
}
60+
61+
[ConditionalFact]
62+
public void GetCreateIfNotExistsScript_works_with_schema()
63+
{
64+
var sql = CreateHistoryRepository("my").GetCreateIfNotExistsScript();
65+
66+
Assert.Equal(
67+
"""
68+
DO $EF$
69+
BEGIN
70+
IF NOT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = 'my') THEN
71+
CREATE SCHEMA my;
72+
END IF;
73+
END $EF$;
74+
CREATE TABLE IF NOT EXISTS my."__EFMigrationsHistory" (
75+
"MigrationId" character varying(150) NOT NULL,
76+
"ProductVersion" character varying(32) NOT NULL,
77+
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
78+
);
79+
80+
""", sql, ignoreLineEndingDifferences: true);
81+
}
82+
83+
[ConditionalFact]
84+
public void GetDeleteScript_works()
85+
{
86+
var sql = CreateHistoryRepository().GetDeleteScript("Migration1");
87+
88+
Assert.Equal(
89+
"""
90+
DELETE FROM "__EFMigrationsHistory"
91+
WHERE "MigrationId" = 'Migration1';
92+
93+
""", sql, ignoreLineEndingDifferences: true);
94+
}
95+
96+
[ConditionalFact]
97+
public void GetInsertScript_works()
98+
{
99+
var sql = CreateHistoryRepository().GetInsertScript(
100+
new HistoryRow("Migration1", "7.0.0"));
101+
102+
Assert.Equal(
103+
"""
104+
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
105+
VALUES ('Migration1', '7.0.0');
106+
107+
""", sql, ignoreLineEndingDifferences: true);
108+
}
109+
110+
[ConditionalFact]
111+
public void GetBeginIfNotExistsScript_works()
112+
{
113+
var sql = CreateHistoryRepository().GetBeginIfNotExistsScript("Migration1");
114+
115+
Assert.Equal(
116+
"""
117+
118+
DO $EF$
119+
BEGIN
120+
IF NOT EXISTS(SELECT 1 FROM "__EFMigrationsHistory" WHERE "MigrationId" = 'Migration1') THEN
121+
""", sql, ignoreLineEndingDifferences: true);
122+
}
123+
124+
[ConditionalFact]
125+
public void GetBeginIfExistsScript_works()
126+
{
127+
var sql = CreateHistoryRepository().GetBeginIfExistsScript("Migration1");
128+
129+
Assert.Equal(
130+
"""
131+
132+
DO $EF$
133+
BEGIN
134+
IF EXISTS(SELECT 1 FROM "__EFMigrationsHistory" WHERE "MigrationId" = 'Migration1') THEN
135+
""", sql, ignoreLineEndingDifferences: true);
136+
}
137+
138+
[ConditionalFact]
139+
public void GetEndIfScript_works()
140+
{
141+
var sql = CreateHistoryRepository().GetEndIfScript();
142+
143+
Assert.Equal(
144+
"""
145+
END IF;
146+
END $EF$;
147+
""", sql, ignoreLineEndingDifferences: true);
148+
}
149+
150+
private static IHistoryRepository CreateHistoryRepository(string schema = null)
151+
=> new TestDbContext(
152+
new DbContextOptionsBuilder()
153+
.UseInternalServiceProvider(NpgsqlTestHelpers.Instance.CreateServiceProvider())
154+
.UseNpgsql(
155+
new NpgsqlConnection("Host=localhost;Database=DummyDatabase"),
156+
b => b.MigrationsHistoryTable(HistoryRepository.DefaultTableName, schema))
157+
.Options)
158+
.GetService<IHistoryRepository>();
159+
160+
private class TestDbContext : DbContext
161+
{
162+
public TestDbContext(DbContextOptions options)
163+
: base(options)
164+
{
165+
}
166+
167+
public DbSet<Blog> Blogs { get; set; }
168+
169+
[DbFunction("TableFunction")]
170+
public IQueryable<TableFunction> TableFunction()
171+
=> FromExpression(() => TableFunction());
172+
173+
protected override void OnModelCreating(ModelBuilder modelBuilder)
174+
{
175+
}
176+
}
177+
178+
private class Blog
179+
{
180+
public int Id { get; set; }
181+
}
182+
183+
private class TableFunction
184+
{
185+
public int Id { get; set; }
186+
public int BlogId { get; set; }
187+
public Blog Blog { get; set; }
188+
}
189+
}

0 commit comments

Comments
 (0)