lref �?Core ORM Crate
EFCore-inspired ORM core: traits, query builder, change tracking, migration engine, DI integration.
Quick Example
use *;
// DI registration
use *;
use *;
use DbContextOptionsBuilderExt as _;
let provider = new
.add_dbcontext
.build.unwrap;
let mut ctx: DbContext = provider.get_owned.unwrap;
Module Map
lref/src/
├── entity.rs �?IEntityType, IFromRow, IGetKeyValues, IEntitySnapshot
├── metadata.rs �?EntityTypeMeta, PropertyMeta, NavigationMeta
├── provider.rs �?IDatabaseProvider, ISqlGenerator, IAsyncConnection, DbValue
├── db_context.rs �?DbContext, DbContextOptions
├── db_set.rs �?IDbSet<T>, DbSet<T>
├── query.rs �?IQueryable<T>, QueryBuilder<T>
├── change_executor.rs �?ChangeExecutor (INSERT/UPDATE/DELETE)
├── model_builder.rs �?ModelBuilder, IEntityTypeConfiguration<T>
├── tracking.rs �?ChangeTracker (property-level snapshots)
├── relations.rs �?BelongsTo, HasMany, HasOne (no trait bounds)
├── migration.rs �?MigrationEngine
├── di.rs ?rust-dix integration (add_dbcontext / add_dbcontext_keyed)
├── cache.rs �?DbCache (Identity Map)
└── error.rs �?EFError, EFResult
Core Traits
Entity
Session (concrete context type)
Collection
Provider
DI Integration
use *;
use *;
use DbContextOptionsBuilderExt as _;
let provider = new
.add_dbcontext
.build.unwrap;
// Owned (recommended): &mut self access, no locks
let mut ctx: DbContext = provider.get_owned.unwrap;
// Shared (within a scope): Arc<DbContext>, &self only
// use rust_dix::scope::ScopeFactory;
// let scope = provider.create_scope();
// let ctx: Arc<DbContext> = scope.get().unwrap();
Provider factory: use_sqlite() injects a closure into DbContextOptions. DbContext::from_options() calls it to create the provider �?core stays fully decoupled.
QueryBuilder API
All query operations go through the linq! macro �?the string-based APIs (include_named / order_by("col") / sum("col") / find_by_id etc.) have been removed. The macro expands to #[doc(hidden)] *_internal methods at compile time.
// Form A: filter closure (reusable BoolExpr or direct query)
let expr = linq!;
let blogs = ctx..filter.to_list.await?;
// Form B: multi-clause query (filter + clauses separated by `;`)
let blogs = linq!.to_list.await?;
// Aggregates (terminals)
let total: f64 = linq!.await?;
let top: i32 = linq!.await?.unwrap_or;
let n: i64 = linq!.await?;
// JOIN via multi-param closure
let rows = linq!.to_list.await?;
// Bulk update
let affected = linq!.await?;
// Bulk delete
let affected = linq!
.execute_delete.await?;
// Form C: value-producing (for ModelBuilder)
builder.has_query_filter;
builder.has_index;
builder.has_key;
// Terminals on QueryBuilder<T>
ctx..query.find.await? // Option<T> (PK metadata, no hardcoded "id")
ctx..query.first.await? // T (errors if empty)
ctx..query.first_or_default.await?// Option<T>
ctx..query.last.await? // T (PK desc when no explicit order)
ctx..query.last_or_default.await? // Option<T>
ctx..query.single.await? // T (errors if !=1)
ctx..query.single_or_default.await? // Option<T> (errors if >1)
ctx..query.count.await? // i64
ctx..query.long_count.await? // i64 (alias)
ctx..query.any.await? // bool
ctx..query.all.await? // bool (Rust-side predicate)
ctx..query.contains.await? // bool (PK existence)
ctx..query.distinct.to_list.await? // SELECT DISTINCT
License
MIT