4.0 KiB
Syntax Deep Dive and Procedure Calls
This guide focuses on the two query syntaxes and advanced stored procedure invocation patterns.
Two Query Syntax Styles
DynamORM supports:
- Dynamic table syntax: concise runtime calls via
dynamic. - Fluent builder syntax: explicit SQL composition via interfaces and lambda parser.
Dynamic Table Syntax
Entry point:
dynamic users = db.Table("users");
Typical reads:
var count = users.Count(columns: "id");
var first = users.First(columns: "id,first,last");
var one = users.Single(id: 19);
var list = (users.Query(columns: "id,first", order: "id:desc") as IEnumerable<dynamic>).ToList();
Dynamic filters with DynamicColumn:
users.Count(where: new DynamicColumn("id").Greater(100));
users.Count(where: new DynamicColumn("last").In("Hendricks", "Goodwin", "Freeman"));
Modifications:
users.Insert(code: "201", first: "Juri", last: "Gagarin");
users.Update(values: new { first = "Yuri" }, where: new { code = "201" });
users.Delete(code: "201");
Coverage references:
DynamORM.Tests/Select/DynamicAccessTests.csDynamORM.Tests/Modify/DynamicModificationTests.cs
Fluent Builder Syntax
Entry points:
var q1 = db.From("users", "u");
var q2 = db.From<Users>("u");
Composable select:
using (var query = db.From<Users>("u")
.Where(x => x.u.id > 10)
.Select(x => x.u.id, x => x.u.first)
.OrderBy(x => x.u.id.Desc()))
{
var rows = query.Execute().ToList();
}
Parser forms supported by tests:
From(x => x.dbo.Users)From(x => x.dbo.Users.As(x.u))From(x => "dbo.Users AS u")From(x => x(subQuery).As("u"))Join(x => x.Left().Accounts.As(x.a).On(x.a.userId == x.u.id))
Coverage references:
DynamORM.Tests/Select/ParserTests.csDynamORM.Tests/Select/LegacyParserTests.cs
Choosing Between Syntaxes
Use dynamic table syntax when:
- You want short CRUD calls quickly.
- Table/column selection is runtime-driven.
Use fluent builder syntax when:
- You want explicit SQL structure and deterministic command text.
- You need complex joins/subqueries/parser features.
- You prefer typed projections (
Execute<T>(),ScalarAs<T>()).
Stored Procedure Deep Dive
db.Procedures provides dynamic invocation of stored procedures.
Basic Calls
var r0 = db.Procedures.sp_Exp_Scalar();
var r1 = db.Procedures.sp_Exp_Scalar<int>();
Namespaced Procedure Names
TryGetMember composes member segments before invocation:
var r = db.Procedures.dbo.reporting.sp_MonthlySales();
Final procedure name becomes dbo.reporting.sp_MonthlySales.
Direction Prefixes
Argument name prefixes drive parameter direction:
out_=>ParameterDirection.Outputret_=>ParameterDirection.ReturnValueboth_=>ParameterDirection.InputOutput
Example:
dynamic res = db.Procedures.sp_Test_Scalar_In_Out(
inp: Guid.NewGuid(),
out_outp: Guid.Empty,
ret_Return: 0);
Returned object exposes values without prefixes.
Advanced Parameter Shape
You can pass:
- plain values
DynamicColumnwith schema and direction metadataDynamicSchemaColumnDynamicExpando/ExpandoObject
Example with explicit output schema:
var res = db.Procedures.sp_Exp_SomeInputAndOutput<string, MyProcResult>(
Name: "G4g4r1n",
out_Result: new DynamicSchemaColumn { Name = "Result", Size = 256 },
ret_Return: 0);
Generic Result Shapes
From DynamicProcedureInvoker behavior:
T == IDataReader: returns cached reader (CachedReader()).T == DataTable: materializes viaToDataTable().T == IEnumerable<object>: dynamic row enumeration.T == IEnumerable<primitive>: scalar conversion per row.T == IEnumerable<class>: mapping with mapper cache.T == class: mapped single/object payload.
Return and Output Aggregation
When output/return params are present, DynamORM aggregates:
- main result
- each output parameter
- return value
into a dynamic object or mapped result type (if a mapping type is provided).