Apache.Calcite.EntityFrameworkCore.Adapter
1.0.0-pre.42
dotnet add package Apache.Calcite.EntityFrameworkCore.Adapter --version 1.0.0-pre.42
NuGet\Install-Package Apache.Calcite.EntityFrameworkCore.Adapter -Version 1.0.0-pre.42
<PackageReference Include="Apache.Calcite.EntityFrameworkCore.Adapter" Version="1.0.0-pre.42" />
<PackageVersion Include="Apache.Calcite.EntityFrameworkCore.Adapter" Version="1.0.0-pre.42" />
<PackageReference Include="Apache.Calcite.EntityFrameworkCore.Adapter" />
paket add Apache.Calcite.EntityFrameworkCore.Adapter --version 1.0.0-pre.42
#r "nuget: Apache.Calcite.EntityFrameworkCore.Adapter, 1.0.0-pre.42"
#:package Apache.Calcite.EntityFrameworkCore.Adapter@1.0.0-pre.42
#addin nuget:?package=Apache.Calcite.EntityFrameworkCore.Adapter&version=1.0.0-pre.42&prerelease
#tool nuget:?package=Apache.Calcite.EntityFrameworkCore.Adapter&version=1.0.0-pre.42&prerelease
Apache.Calcite.EntityFrameworkCore.Adapter
An Apache Calcite adapter that executes relational plans as Entity Framework Core
LINQ. Register a DbContext as a Calcite schema, and Calcite treats your EF Core model like any other adapter —
plan SQL over it, federate it with CSV files, JDBC databases, and in-memory schemas, and join across all of them in
one query.
This is the Calcite on EF Core direction. For the other direction — a DbContext whose store is Calcite — see
Apache.Calcite.EntityFrameworkCore.
Calcite runs in-process through IKVM: no JDBC driver, no Avatica server, no second process.
dotnet add package Apache.Calcite.EntityFrameworkCore.Adapter
Quick start
using Apache.Calcite.Data;
using Apache.Calcite.EntityFrameworkCore.Adapter;
using var connection = new CalciteConnection("caseSensitive=false");
connection.Open();
// Expose the DbSet<T> properties of ProductDbContext as tables in a Calcite schema named "efcore".
var schema = EfCoreSchema.Create(connection.RootSchema, "efcore", () => new ProductDbContext(connectionString));
connection.RootSchema.add("efcore", schema);
using var cmd = connection.CreateCommand();
cmd.CommandText = @"SELECT ""Id"", ""Name"" FROM ""efcore"".""Product"" WHERE ""InStock"" = TRUE";
using var reader = cmd.ExecuteReader();
while (reader.Read())
Console.WriteLine($"{reader.GetInt32(0)} {reader.GetString(1)}");
Two details worth knowing up front:
Createdoes not register the schema for you — pass the parent schema so the adapter can resolve against it, thenaddit under the name you want, as above.- Tables are named after the entity CLR type, not the
DbSetproperty and not the mapped table. ADbSet<Product> Productson a table calledProductsis the Calcite table"Product".
The factory is called every time the adapter needs a context — once to read the model, and again for each execution — and the context is disposed afterwards, so it must return a fresh, independently usable instance each time rather than a shared one.
Registering from a Calcite model file
EfCoreSchemaFactory wires the same thing up from model JSON, so a schema can be declared in a connection string
instead of in code. The operand map takes either dbContextType (an assembly-qualified DbContext subclass with
a public parameterless constructor) or dbContextFactory (an assembly-qualified IDbContextFactory), plus an
optional rexTranslatorFactory:
{
"version": "1.0",
"defaultSchema": "efcore",
"schemas": [
{
"name": "efcore",
"type": "custom",
"factory": "Apache.Calcite.EntityFrameworkCore.Adapter.EfCoreSchemaFactory",
"operand": { "dbContextType": "MyApp.ProductDbContext, MyApp" }
}
]
}
How it works
EfCoreConvention is a Calcite calling convention. Converter rules in EfCoreRules pull relational nodes into it —
Filter, Project/Calc, Join and left join, Aggregate, Sort, Union, Intersect, Minus, Values —
and each node's implement builds a LINQ Expression typed as IQueryable<T> over the DbSet<T> it came from.
Rex trees become LINQ predicates and projections through RexToLinqTranslator, with SQL operator coverage supplied
by a replaceable ISqlOperatorTranslationProvider.
The convention carries a cost multiplier below 1, so where the planner can express an operation either way it prefers pushing it into EF Core — which in turn means EF Core's own provider gets to push it down to the store. Work the convention cannot express stays in Calcite's enumerable convention above it and runs there, on rows the adapter streams out.
There is exactly one way out: EfCoreToClrAsyncEnumerableConverter into ClrAsyncEnumerableConvention. EF Core's
pipeline is natively asynchronous, so rows leave the convention as an IAsyncEnumerable, and the bridge converters
in Apache.Calcite.Extensions carry them onward to whatever convention the rest of the plan needs.
Extending the translation
EfCoreSchema.Create takes an optional IRexToLinqTranslatorFactory (rexTranslatorFactory in a model file),
which is the single hook for everything below it. To add SQL functions the default translator does not cover,
subclass SqlOperatorTranslationProvider, override Build — calling base.Build to keep the standard mappings —
and hand your table to a RexToLinqTranslator from your own factory:
sealed class MyOperators : SqlOperatorTranslationProvider
{
protected override void Build(Dictionary<SqlOperator, SqlOperatorTranslator> translators)
{
base.Build(translators);
translators[SqlStdOperatorTable.INITCAP] = StaticCall(typeof(MyFunctions), nameof(MyFunctions.InitCap));
}
}
sealed class MyTranslatorFactory : IRexToLinqTranslatorFactory
{
public IRexToLinqTranslator Create() => new RexToLinqTranslator(new MyOperators());
}
Each translator delegate receives the already-translated CLR operand expressions and returns the expression that
implements the function; StaticCall, InstanceCall, and PropRead cover the common shapes. SqlOperatorTranslationProvider.Default
is the built-in table — UPPER, LOWER, CHAR_LENGTH, REPLACE, POSITION, the math operators, and the rest.
An untranslated SQL function is not an error. The planner simply leaves that part of the plan above the convention and evaluates it in Calcite, on rows the adapter feeds it.
Requirements
.NET 10 and EF Core 10. Any EF Core provider works as the underlying store — the adapter only builds IQueryable
expressions and lets that provider execute them.
Links
- Repository and full documentation
Apache.Calcite.EntityFrameworkCore— the EF Core provider- calcite-dotnet — Apache Calcite for .NET
- Calcite adapter documentation
License
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Apache.Calcite.Data (>= 2.0.0-pre.9)
- Apache.Calcite.EntityFrameworkCore.Core (>= 1.0.0-pre.42)
- IKVM (>= 8.16.0)
- IKVM.Java.Extensions (>= 8.16.0)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.8)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0-pre.42 | 36 | 9/1/2026 |
| 1.0.0-pre.41 | 43 | 9/1/2026 |