Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,16 @@ jobs:
"samples/connection-string-mssql/ConnectionStringMssql.sln"
"samples/aspnet-core-appsettings/AspNetCoreAppSettings.sln"
"samples/split-data-and-models-between-multiple-projects/SampleApp.slnx"
# Per-provider reference samples (#191): minimal EF Core samples with committed
# generated code for the providers that don't have DACPAC support, so they build
# with -p:EfcptEnabled=false just like the rest of this list. provider-snowflake is
# entities-only (no first-party EF Core runtime provider exists for Snowflake) - see
# samples/provider-snowflake/README.md.
"samples/provider-postgres/ProviderPostgres.sln"
"samples/provider-mysql/ProviderMySql.sln"
"samples/provider-oracle/ProviderOracle.sln"
"samples/provider-firebird/ProviderFirebird.sln"
"samples/provider-snowflake/ProviderSnowflake.sln"
)
for sample in "${SAMPLES[@]}"; do
echo "::group::Build $sample"
Expand Down
20 changes: 20 additions & 0 deletions docs/user-guide/provider-support.md
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,26 @@ satellite-package resolution machinery. This is disabled by default (custom prov
third-party code at build time) and requires an explicit opt-in. See
[Custom Providers](custom-providers.md) for the full authoring and registration guide.

## Per-Provider Reference Samples

Minimal, buildable reference samples exist under `samples/provider-<name>/` for the five
providers that have no DACPAC support and therefore need Connection String Mode. Each one ships a
committed, compilable copy of the generated `AppDbContext` + entity classes under
`EntityFrameworkCoreProject/Generated/`, so the sample builds green in CI with `-p:EfcptEnabled=false`
and **no live database** - see each sample's README for how to point it at a real database and
regenerate locally.

| Sample | EF Core Runtime Provider | Notes |
|--------|--------------------------|-------|
| [provider-postgres](../../samples/provider-postgres/README.md) | `Npgsql.EntityFrameworkCore.PostgreSQL` | |
| [provider-mysql](../../samples/provider-mysql/README.md) | `Pomelo.EntityFrameworkCore.MySql` | Pinned to EF Core 9.x - Pomelo has no EF Core 10 release yet |
| [provider-oracle](../../samples/provider-oracle/README.md) | `Oracle.EntityFrameworkCore` | |
| [provider-firebird](../../samples/provider-firebird/README.md) | `FirebirdSql.EntityFrameworkCore.Firebird` | |
| [provider-snowflake](../../samples/provider-snowflake/README.md) | *(none - entities-only)* | No first-party EF Core runtime provider exists for Snowflake |

(SQL Server and SQLite already have full samples under `samples/dacpac-zero-config/` and
`samples/connection-string-sqlite/` respectively - see [samples/README.md](../../samples/README.md).)

## See Also

- [Configuration Reference](configuration.md) - All EfcptProvider values and properties
Expand Down
90 changes: 90 additions & 0 deletions samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,21 @@ This directory contains sample projects demonstrating various usage patterns of
| [connection-string-mssql](#connection-string-mssql) | SQL Server + Aspire | SQL Server container with .NET Aspire |
| [aspnet-core-appsettings](#aspnet-core-appsettings) | SQL Server + Aspire | appsettings.json + Aspire container |

### Per-Provider Reference Samples

Minimal reference samples for the providers that have no DACPAC support and only support
Connection String Mode. Each commits a reference copy of the generated code so it builds in CI
with `-p:EfcptEnabled=false` and no live database - see [Per-Provider Reference
Samples](#per-provider-reference-samples-1) below for details.

| Sample | Database Provider | EF Core Runtime Provider |
|--------|------------------|---------------------------|
| [provider-postgres](#provider-postgres) | PostgreSQL | `Npgsql.EntityFrameworkCore.PostgreSQL` |
| [provider-mysql](#provider-mysql) | MySQL | `Pomelo.EntityFrameworkCore.MySql` (EF Core 9.x pin) |
| [provider-oracle](#provider-oracle) | Oracle | `Oracle.EntityFrameworkCore` |
| [provider-firebird](#provider-firebird) | Firebird | `FirebirdSql.EntityFrameworkCore.Firebird` |
| [provider-snowflake](#provider-snowflake) | Snowflake | *(none - entities-only, see sample README)* |

## Input Modes

JD.Efcpt.Build supports two primary input modes:
Expand Down Expand Up @@ -426,6 +441,81 @@ dotnet build MyApp.Api

---

## Per-Provider Reference Samples

These five samples cover every JD.Efcpt.Build-supported provider that has no DACPAC support and
therefore relies entirely on Connection String Mode. Rather than requiring a live database in CI,
each one commits a reference copy of the code `efcpt` would generate under
`EntityFrameworkCoreProject/Generated/`, so `dotnet build <sample>.sln -p:EfcptEnabled=false`
succeeds with zero database dependency (see the `samples-build` job in
`.github/workflows/ci.yml`). Set `EfcptConnectionString` locally to regenerate against a real
database instead - see each sample's README for details.

### provider-postgres

**Location:** `provider-postgres/`

PostgreSQL via Connection String Mode, using the `Npgsql.EntityFrameworkCore.PostgreSQL` runtime
provider. See [provider-postgres/README.md](provider-postgres/README.md).

**Build:**
```bash
dotnet build provider-postgres/ProviderPostgres.sln
```

### provider-mysql

**Location:** `provider-mysql/`

MySQL via Connection String Mode, using the `Pomelo.EntityFrameworkCore.MySql` runtime provider.
Pinned to the EF Core 9.x line since Pomelo has no EF Core 10 release yet - see
[provider-mysql/README.md](provider-mysql/README.md).

**Build:**
```bash
dotnet build provider-mysql/ProviderMySql.sln
```

### provider-oracle

**Location:** `provider-oracle/`

Oracle via Connection String Mode, using the `Oracle.EntityFrameworkCore` runtime provider. See
[provider-oracle/README.md](provider-oracle/README.md).

**Build:**
```bash
dotnet build provider-oracle/ProviderOracle.sln
```

### provider-firebird

**Location:** `provider-firebird/`

Firebird via Connection String Mode, using the `FirebirdSql.EntityFrameworkCore.Firebird` runtime
provider. See [provider-firebird/README.md](provider-firebird/README.md).

**Build:**
```bash
dotnet build provider-firebird/ProviderFirebird.sln
```

### provider-snowflake

**Location:** `provider-snowflake/`

Snowflake via Connection String Mode - **entities-only**. No first-party EF Core runtime provider
exists for Snowflake, so `AppDbContext` has entity classes and `DbSet<T>` properties but no
`OnConfiguring`/`UseX` call. See [provider-snowflake/README.md](provider-snowflake/README.md) for
why and how a host application would wire it up.

**Build:**
```bash
dotnet build provider-snowflake/ProviderSnowflake.sln
```

---

## Common Configuration

All samples use:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<!-- Suppress CS8669 for generated code that doesn't have an explicit #nullable directive. -->
<NoWarn>$(NoWarn);CS8669</NoWarn>
</PropertyGroup>

<!--
============================================================================
JD.Efcpt.Build - Firebird Reference Sample
============================================================================
Firebird has no DACPAC equivalent, so this sample uses Connection String
Mode: set EfcptConnectionString (and install JD.Efcpt.Build.Firebird) to
regenerate models against a real Firebird database locally.

In CI there is no live database, so EfcptEnabled stays false (see below)
and the project instead compiles the COMMITTED reference code under
Generated/, which mirrors what `efcpt` would emit for this schema.
============================================================================
-->

<PropertyGroup>
<EfcptProvider>firebird</EfcptProvider>
<!-- Local dev: set EfcptConnectionString to enable real regeneration. CI (no connection string) stays inert. -->
<EfcptEnabled Condition="'$(EfcptConnectionString)' == ''">false</EfcptEnabled>
</PropertyGroup>

<ItemGroup>
<!-- Build-time source generator tool; inert here because EfcptEnabled=false (see above). -->
<PackageReference Include="JD.Efcpt.Build" Version="*" />
<!-- EF Core runtime + Firebird provider, needed so the committed Generated/ code compiles. -->
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="10.0.9" />
<PackageReference Include="FirebirdSql.EntityFrameworkCore.Firebird" Version="13.0.0" />
</ItemGroup>

<ItemGroup>
<None Include="efcpt-config.json" />
</ItemGroup>

<!--
When a real EfcptConnectionString IS supplied, JD.Efcpt.Build regenerates live models into
obj/efcpt/Generated. Exclude the committed Generated/ reference copy from compilation in that
case so the two don't collide on the same type names.
-->
<ItemGroup Condition="'$(EfcptEnabled)' != 'false'">
<Compile Remove="Generated\**\*.cs" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
// <auto-generated>
// Reference copy of what `efcpt` would emit for this schema against Firebird.
// Regenerate for real by setting EfcptConnectionString and building with a live
// Firebird database - see ../README.md.
// </auto-generated>
using EntityFrameworkCoreProject.Generated.Entities;
using Microsoft.EntityFrameworkCore;

namespace EntityFrameworkCoreProject.Generated;

public partial class AppDbContext : DbContext
{
public AppDbContext()
{
}

public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options)
{
}

public virtual DbSet<Customer> Customers { get; set; } = null!;

public virtual DbSet<Order> Orders { get; set; } = null!;

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
// Illustrative only - real efcpt output (enable-on-configuring=false in
// efcpt-config.json) omits this and expects the host app to configure the
// provider itself. Shown here so this sample demonstrates
// FirebirdSql.EntityFrameworkCore.Firebird end-to-end.
optionsBuilder.UseFirebird("Database=localhost:sample.fdb;User=SYSDBA;Password=masterkey");
}
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Customer>(entity =>
{
entity.HasKey(e => e.Id);
entity.HasIndex(e => e.Email).IsUnique();
entity.Property(e => e.Name).HasMaxLength(200).IsRequired();
entity.Property(e => e.Email).HasMaxLength(320).IsRequired();
});

modelBuilder.Entity<Order>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.TotalAmount).HasColumnType("DECIMAL(18,2)");

entity.HasOne(d => d.Customer)
.WithMany(p => p.Orders)
.HasForeignKey(d => d.CustomerId)
.OnDelete(DeleteBehavior.Cascade);
});

OnModelCreatingPartial(modelBuilder);
}

partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// <auto-generated>
// Reference copy of what `efcpt` would emit for the CUSTOMERS table.
// Regenerate for real by setting EfcptConnectionString and building with a live
// Firebird database - see ../../README.md.
// </auto-generated>
using System;
using System.Collections.Generic;

namespace EntityFrameworkCoreProject.Generated.Entities;

public partial class Customer
{
public int Id { get; set; }

public string Name { get; set; } = null!;

public string Email { get; set; } = null!;

public DateTime CreatedAtUtc { get; set; }

public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// <auto-generated>
// Reference copy of what `efcpt` would emit for the ORDERS table.
// Regenerate for real by setting EfcptConnectionString and building with a live
// Firebird database - see ../../README.md.
// </auto-generated>
using System;

namespace EntityFrameworkCoreProject.Generated.Entities;

public partial class Order
{
public int Id { get; set; }

public int CustomerId { get; set; }

public decimal TotalAmount { get; set; }

public DateTime OrderedAtUtc { get; set; }

public virtual Customer Customer { get; set; } = null!;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://raw.githubusercontent.com/ErikEJ/EFCorePowerTools/master/samples/efcpt-config.schema.json",
"names": {
"root-namespace": "EntityFrameworkCoreProject",
"dbcontext-name": "AppDbContext",
"dbcontext-namespace": "EntityFrameworkCoreProject.Generated",
"model-namespace": "EntityFrameworkCoreProject.Generated.Entities"
},
"code-generation": {
"use-t4": false,
"enable-on-configuring": false,
"use-nullable-reference-types": true,
"use-inflector": true
},
"file-layout": {
"output-path": "Models",
"output-dbcontext-path": "."
},
"tables": [
{ "name": "[CUSTOMERS]" },
{ "name": "[ORDERS]" }
]
}
27 changes: 27 additions & 0 deletions samples/provider-firebird/ProviderFirebird.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1A2B3C4D-0004-4000-8000-000000000001}"
ProjectSection(SolutionItems) = preProject
nuget.config = nuget.config
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EntityFrameworkCoreProject", "EntityFrameworkCoreProject\EntityFrameworkCoreProject.csproj", "{1A2B3C4D-0004-4000-8000-000000000002}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1A2B3C4D-0004-4000-8000-000000000002}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1A2B3C4D-0004-4000-8000-000000000002}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1A2B3C4D-0004-4000-8000-000000000002}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1A2B3C4D-0004-4000-8000-000000000002}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
Loading
Loading