Skip to content

Commit fb5ee72

Browse files
committed
.
1 parent 59a0944 commit fb5ee72

8 files changed

Lines changed: 1248 additions & 0 deletions

File tree

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

docs/postgres-ef.md

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<!--
2+
GENERATED FILE - DO NOT EDIT
3+
This file was generated by [MarkdownSnippets](https://github.com/SimonCropp/MarkdownSnippets).
4+
Source File: /docs/mdsource/postgres-ef.source.md
5+
To change this file edit the source file and then run MarkdownSnippets.
6+
-->
7+
8+
# PostgreSQL usage with EntityFramework
9+
10+
[![NuGet Status](https://img.shields.io/nuget/v/Delta.svg?label=Delta)](https://www.nuget.org/packages/Delta/)
11+
[![NuGet Status](https://img.shields.io/nuget/v/Delta.EF.svg?label=Delta.EF)](https://www.nuget.org/packages/Delta.EF/)
12+
[![NuGet Status](https://img.shields.io/nuget/v/Delta.SqlServer.svg?label=Delta.SqlServer)](https://www.nuget.org/packages/Delta.SqlServer/)
13+
14+
15+
## Implementation
16+
17+
Postgres required [track_commit_timestamp](https://www.postgresql.org/docs/17/runtime-config-replication.html#GUC-TRACK-COMMIT-TIMESTAMP) to be enabled. This can be done using `ALTER SYSTEM SET track_commit_timestamp to "on"` and then restarting the Postgres service<!-- singleLineInclude: postgres-implemenation. path: /docs/mdsource/postgres-implemenation.include.md -->
18+
19+
20+
## Timestamp
21+
22+
<!-- snippet: PostgresTimeStamp -->
23+
<a id='snippet-PostgresTimeStamp'></a>
24+
```cs
25+
select pg_last_committed_xact();
26+
```
27+
<sup><a href='/src/Delta/DeltaExtensions_Sql.cs#L58-L60' title='Snippet source file'>snippet source</a> | <a href='#snippet-PostgresTimeStamp' title='Start of snippet'>anchor</a></sup>
28+
<!-- endSnippet -->
29+
30+
31+
## Usage
32+
33+
34+
### Example SQL schema
35+
36+
<!-- snippet: PostgresSchema -->
37+
<a id='snippet-PostgresSchema'></a>
38+
```cs
39+
create table IF NOT EXISTS public."Companies"
40+
(
41+
"Id" uuid not null
42+
constraint "PK_Companies"
43+
primary key,
44+
"Content" text
45+
);
46+
47+
alter table public."Companies"
48+
owner to postgres;
49+
50+
create table IF NOT EXISTS public."Employees"
51+
(
52+
"Id" uuid not null
53+
constraint "PK_Employees"
54+
primary key,
55+
"CompanyId" uuid not null
56+
constraint "FK_Employees_Companies_CompanyId"
57+
references public."Companies"
58+
on delete cascade,
59+
"Content" text,
60+
"Age" integer not null
61+
);
62+
63+
alter table public."Employees"
64+
owner to postgres;
65+
66+
create index IF NOT EXISTS "IX_Employees_CompanyId"
67+
on public."Employees" ("CompanyId");
68+
```
69+
<sup><a href='/src/WebApplicationPostgres/PostgresDbBuilder.cs#L9-L39' title='Snippet source file'>snippet source</a> | <a href='#snippet-PostgresSchema' title='Start of snippet'>anchor</a></sup>
70+
<!-- endSnippet -->
71+
72+
73+
### DbContext
74+
75+
<!-- snippet: SamplePostgresDbContext -->
76+
<a id='snippet-SamplePostgresDbContext'></a>
77+
```cs
78+
public class SampleDbContext(DbContextOptions options) :
79+
DbContext(options)
80+
{
81+
public DbSet<Employee> Employees { get; set; } = null!;
82+
public DbSet<Company> Companies { get; set; } = null!;
83+
protected override void OnModelCreating(ModelBuilder builder)
84+
{
85+
var company = builder.Entity<Company>();
86+
company.HasKey(_ => _.Id);
87+
company
88+
.HasMany(_ => _.Employees)
89+
.WithOne(_ => _.Company)
90+
.IsRequired();
91+
92+
var employee = builder.Entity<Employee>();
93+
employee.HasKey(_ => _.Id);
94+
}
95+
}
96+
```
97+
<sup><a href='/src/WebApplicationPostgresEF/DataContext/SampleDbContext.cs#L1-L22' title='Snippet source file'>snippet source</a> | <a href='#snippet-SamplePostgresDbContext' title='Start of snippet'>anchor</a></sup>
98+
<!-- endSnippet -->
99+
100+
101+
### Add to WebApplicationBuilder
102+
103+
<!-- snippet: UseDeltaPostgresEF -->
104+
<a id='snippet-UseDeltaPostgresEF'></a>
105+
```cs
106+
var builder = WebApplication.CreateBuilder();
107+
builder.Services.AddDbContext<SampleDbContext>(
108+
_ => _.UseNpgsql(connectionString));
109+
var app = builder.Build();
110+
app.UseDelta<SampleDbContext>();
111+
```
112+
<sup><a href='/src/WebApplicationPostgresEF/Program.cs#L3-L11' title='Snippet source file'>snippet source</a> | <a href='#snippet-UseDeltaPostgresEF' title='Start of snippet'>anchor</a></sup>
113+
<!-- endSnippet -->
114+
115+
116+
### Add to a Route Group<!-- include: map-group-ef. path: /docs/mdsource/map-group-ef.include.md -->
117+
118+
To add to a specific [Route Group](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/route-handlers#route-groups):
119+
120+
<!-- snippet: UseDeltaMapGroupEF -->
121+
<a id='snippet-UseDeltaMapGroupEF'></a>
122+
```cs
123+
app.MapGroup("/group")
124+
.UseDelta<SampleDbContext>()
125+
.MapGet("/", () => "Hello Group!");
126+
```
127+
<sup><a href='/src/WebApplicationPostgresEF/Program.cs#L44-L50' title='Snippet source file'>snippet source</a> | <a href='#snippet-UseDeltaMapGroupEF' title='Start of snippet'>anchor</a></sup>
128+
<a id='snippet-UseDeltaMapGroupEF-1'></a>
129+
```cs
130+
app.MapGroup("/group")
131+
.UseDelta<SampleDbContext>()
132+
.MapGet("/", () => "Hello Group!");
133+
```
134+
<sup><a href='/src/WebApplicationSqlServerEF/Program.cs#L44-L50' title='Snippet source file'>snippet source</a> | <a href='#snippet-UseDeltaMapGroupEF-1' title='Start of snippet'>anchor</a></sup>
135+
<!-- endSnippet -->
136+
<!-- endInclude -->
137+
138+
139+
### ShouldExecute<!-- include: should-execute-ef. path: /docs/mdsource/should-execute-ef.include.md -->
140+
141+
Optionally control what requests Delta is executed on.
142+
143+
<!-- snippet: ShouldExecuteEF -->
144+
<a id='snippet-ShouldExecuteEF'></a>
145+
```cs
146+
var app = builder.Build();
147+
app.UseDelta<SampleDbContext>(
148+
shouldExecute: httpContext =>
149+
{
150+
var path = httpContext.Request.Path.ToString();
151+
return path.Contains("match");
152+
});
153+
```
154+
<sup><a href='/src/Delta.EFTests/Usage.cs#L16-L26' title='Snippet source file'>snippet source</a> | <a href='#snippet-ShouldExecuteEF' title='Start of snippet'>anchor</a></sup>
155+
<!-- endSnippet -->
156+
<!-- endInclude -->
157+
158+
159+
### GetLastTimeStamp:
160+
161+
<!-- snippet: GetLastTimeStampEF -->
162+
<a id='snippet-GetLastTimeStampEF'></a>
163+
```cs
164+
var timeStamp = await dbContext.GetLastTimeStamp();
165+
```
166+
<sup><a href='/src/Delta.EFTests/Usage.cs#L41-L45' title='Snippet source file'>snippet source</a> | <a href='#snippet-GetLastTimeStampEF' title='Start of snippet'>anchor</a></sup>
167+
<!-- endSnippet -->

docs/postgres.md

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
<!--
2+
GENERATED FILE - DO NOT EDIT
3+
This file was generated by [MarkdownSnippets](https://github.com/SimonCropp/MarkdownSnippets).
4+
Source File: /docs/mdsource/postgres.source.md
5+
To change this file edit the source file and then run MarkdownSnippets.
6+
-->
7+
8+
# PostgreSQL usage
9+
10+
[![NuGet Status](https://img.shields.io/nuget/v/Delta.svg?label=Delta)](https://www.nuget.org/packages/Delta/)
11+
[![NuGet Status](https://img.shields.io/nuget/v/Delta.EF.svg?label=Delta.EF)](https://www.nuget.org/packages/Delta.EF/)
12+
[![NuGet Status](https://img.shields.io/nuget/v/Delta.SqlServer.svg?label=Delta.SqlServer)](https://www.nuget.org/packages/Delta.SqlServer/)
13+
14+
15+
## Implementation
16+
17+
Postgres required [track_commit_timestamp](https://www.postgresql.org/docs/17/runtime-config-replication.html#GUC-TRACK-COMMIT-TIMESTAMP) to be enabled. This can be done using `ALTER SYSTEM SET track_commit_timestamp to "on"` and then restarting the Postgres service<!-- singleLineInclude: postgres-implemenation. path: /docs/mdsource/postgres-implemenation.include.md -->
18+
19+
20+
## Timestamp
21+
22+
<!-- snippet: PostgresTimeStamp -->
23+
<a id='snippet-PostgresTimeStamp'></a>
24+
```cs
25+
select pg_last_committed_xact();
26+
```
27+
<sup><a href='/src/Delta/DeltaExtensions_Sql.cs#L58-L60' title='Snippet source file'>snippet source</a> | <a href='#snippet-PostgresTimeStamp' title='Start of snippet'>anchor</a></sup>
28+
<!-- endSnippet -->
29+
30+
31+
## Usage
32+
33+
34+
### Example SQL schema
35+
36+
<!-- snippet: PostgresSchema -->
37+
<a id='snippet-PostgresSchema'></a>
38+
```cs
39+
create table IF NOT EXISTS public."Companies"
40+
(
41+
"Id" uuid not null
42+
constraint "PK_Companies"
43+
primary key,
44+
"Content" text
45+
);
46+
47+
alter table public."Companies"
48+
owner to postgres;
49+
50+
create table IF NOT EXISTS public."Employees"
51+
(
52+
"Id" uuid not null
53+
constraint "PK_Employees"
54+
primary key,
55+
"CompanyId" uuid not null
56+
constraint "FK_Employees_Companies_CompanyId"
57+
references public."Companies"
58+
on delete cascade,
59+
"Content" text,
60+
"Age" integer not null
61+
);
62+
63+
alter table public."Employees"
64+
owner to postgres;
65+
66+
create index IF NOT EXISTS "IX_Employees_CompanyId"
67+
on public."Employees" ("CompanyId");
68+
```
69+
<sup><a href='/src/WebApplicationPostgres/PostgresDbBuilder.cs#L9-L39' title='Snippet source file'>snippet source</a> | <a href='#snippet-PostgresSchema' title='Start of snippet'>anchor</a></sup>
70+
<!-- endSnippet -->
71+
72+
73+
### Add to WebApplicationBuilder
74+
75+
<!-- snippet: UseDeltaPostgres -->
76+
<a id='snippet-UseDeltaPostgres'></a>
77+
```cs
78+
var builder = WebApplication.CreateBuilder();
79+
builder.Services.AddScoped(_ => new NpgsqlConnection(connectionString));
80+
var app = builder.Build();
81+
app.UseDelta();
82+
```
83+
<sup><a href='/src/WebApplicationPostgres/Program.cs#L3-L10' title='Snippet source file'>snippet source</a> | <a href='#snippet-UseDeltaPostgres' title='Start of snippet'>anchor</a></sup>
84+
<!-- endSnippet -->
85+
86+
87+
### Add to a Route Group<!-- include: map-group. path: /docs/mdsource/map-group.include.md -->
88+
89+
To add to a specific [Route Group](https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/route-handlers#route-groups):
90+
91+
<!-- snippet: UseDeltaMapGroup -->
92+
<a id='snippet-UseDeltaMapGroup'></a>
93+
```cs
94+
app.MapGroup("/group")
95+
.UseDelta()
96+
.MapGet("/", () => "Hello Group!");
97+
```
98+
<sup><a href='/src/WebApplicationSqlServer/Program.cs#L61-L67' title='Snippet source file'>snippet source</a> | <a href='#snippet-UseDeltaMapGroup' title='Start of snippet'>anchor</a></sup>
99+
<!-- endSnippet -->
100+
<!-- endInclude -->
101+
102+
103+
### ShouldExecute<!-- include: should-execute. path: /docs/mdsource/should-execute.include.md -->
104+
105+
Optionally control what requests Delta is executed on.
106+
107+
<!-- snippet: ShouldExecute -->
108+
<a id='snippet-ShouldExecute'></a>
109+
```cs
110+
var app = builder.Build();
111+
app.UseDelta(
112+
shouldExecute: httpContext =>
113+
{
114+
var path = httpContext.Request.Path.ToString();
115+
return path.Contains("match");
116+
});
117+
```
118+
<sup><a href='/src/DeltaTests/Usage.cs#L18-L28' title='Snippet source file'>snippet source</a> | <a href='#snippet-ShouldExecute' title='Start of snippet'>anchor</a></sup>
119+
<!-- endSnippet -->
120+
<!-- endInclude -->
121+
122+
123+
### Custom Connection discovery<!-- include: connection-discovery. path: /docs/mdsource/connection-discovery.include.md -->
124+
125+
By default, Delta uses `HttpContext.RequestServices` to discover the DbConnection and DbTransaction:
126+
127+
<!-- snippet: DiscoverConnection -->
128+
<a id='snippet-DiscoverConnection'></a>
129+
```cs
130+
static void InitConnectionTypes()
131+
{
132+
var sqlConnectionType = Type.GetType("Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient");
133+
if (sqlConnectionType != null)
134+
{
135+
connectionType = sqlConnectionType;
136+
transactionType = sqlConnectionType.Assembly.GetType("Microsoft.Data.SqlClient.SqlTransaction")!;
137+
return;
138+
}
139+
140+
var npgsqlConnection = Type.GetType("Npgsql.NpgsqlConnection, Npgsql");
141+
if (npgsqlConnection != null)
142+
{
143+
connectionType = npgsqlConnection;
144+
transactionType = npgsqlConnection.Assembly.GetType("Npgsql.NpgsqlTransaction")!;
145+
return;
146+
}
147+
148+
throw new("Could not find connection type. Tried Microsoft.Data.SqlClient.SqlConnection and Npgsql.NpgsqlTransaction");
149+
}
150+
151+
static Connection DiscoverConnection(HttpContext httpContext)
152+
{
153+
var provider = httpContext.RequestServices;
154+
var connection = (DbConnection) provider.GetRequiredService(connectionType);
155+
var transaction = (DbTransaction?) provider.GetService(transactionType);
156+
return new(connection, transaction);
157+
}
158+
```
159+
<sup><a href='/src/Delta/DeltaExtensions_ConnectionDiscovery.cs#L10-L40' title='Snippet source file'>snippet source</a> | <a href='#snippet-DiscoverConnection' title='Start of snippet'>anchor</a></sup>
160+
<!-- endSnippet -->
161+
162+
To use custom connection discovery:
163+
164+
<!-- snippet: CustomDiscoveryConnection -->
165+
<a id='snippet-CustomDiscoveryConnection'></a>
166+
```cs
167+
var application = webApplicationBuilder.Build();
168+
application.UseDelta(
169+
getConnection: httpContext => httpContext.RequestServices.GetRequiredService<SqlConnection>());
170+
```
171+
<sup><a href='/src/DeltaTests/Usage.cs#L314-L320' title='Snippet source file'>snippet source</a> | <a href='#snippet-CustomDiscoveryConnection' title='Start of snippet'>anchor</a></sup>
172+
<!-- endSnippet -->
173+
174+
To use custom connection and transaction discovery:
175+
176+
<!-- snippet: CustomDiscoveryConnectionAndTransaction -->
177+
<a id='snippet-CustomDiscoveryConnectionAndTransaction'></a>
178+
```cs
179+
var application = webApplicationBuilder.Build();
180+
application.UseDelta(
181+
getConnection: httpContext =>
182+
{
183+
var provider = httpContext.RequestServices;
184+
var connection = provider.GetRequiredService<SqlConnection>();
185+
var transaction = provider.GetService<SqlTransaction>();
186+
return new(connection, transaction);
187+
});
188+
```
189+
<sup><a href='/src/DeltaTests/Usage.cs#L325-L337' title='Snippet source file'>snippet source</a> | <a href='#snippet-CustomDiscoveryConnectionAndTransaction' title='Start of snippet'>anchor</a></sup>
190+
<!-- endSnippet -->
191+
<!-- endInclude -->
192+
193+
194+
### GetLastTimeStamp
195+
196+
<!-- snippet: GetLastTimeStampConnection -->
197+
<a id='snippet-GetLastTimeStampConnection'></a>
198+
```cs
199+
var timeStamp = await connection.GetLastTimeStamp();
200+
```
201+
<sup><a href='/src/DeltaTests/Usage.cs#L187-L191' title='Snippet source file'>snippet source</a> | <a href='#snippet-GetLastTimeStampConnection' title='Start of snippet'>anchor</a></sup>
202+
<!-- endSnippet -->

0 commit comments

Comments
 (0)