From 6a219fc194b0c2c9e2a66b067c8f25c37b52c1b7 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 26 Feb 2026 08:09:29 +0100 Subject: [PATCH] Add generic real-world extension method samples --- docs/ado-net-extensions.md | 159 +++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) diff --git a/docs/ado-net-extensions.md b/docs/ado-net-extensions.md index ff8cc52..258e786 100644 --- a/docs/ado-net-extensions.md +++ b/docs/ado-net-extensions.md @@ -161,3 +161,162 @@ When to use it: Tradeoff: - Higher memory use proportional to result size. + +## End-to-End Samples (Genericized) + +These samples mirror real production patterns while using generic names. + +## Sample 1: Stored Procedure with Multiple Result Sets + Null-Safe Reader Accessors + +```csharp +var records = new Dictionary(); + +using var con = Database.Open(); +using var cmd = con.CreateCommand() + .SetCommand(CommandType.StoredProcedure, "usp_get_messages"); + +using var r = cmd.ExecuteReader(); + +while (r.Read()) +{ + var msg = new GenericMessage + { + Id = r.GetStringIfNotNull("id"), + Type = r.GetStringIfNotNull("type"), + Value = r.GetStringIfNotNull("value"), + State = (GenericMessageState)(r.GetInt32IfNotNull("state") ?? 0), + Date = r.GetDateTimeIfNotNull("date") ?? new DateTime(2099, 12, 31), + }; + + records.Add(msg.Id, msg); +} + +if (r.NextResult()) +{ + while (r.Read()) + { + var messageId = r.GetStringIfNotNull("message_id"); + if (!records.ContainsKey(messageId)) + continue; + + records[messageId].Items.Add(new GenericMessageItem + { + Id = r.GetStringIfNotNull("id"), + Type = r.GetStringIfNotNull("type"), + Value = r.GetStringIfNotNull("value"), + }); + } +} +``` + +Extension methods used: + +- `SetCommand(CommandType, string)` +- `GetStringIfNotNull` +- `GetInt32IfNotNull` +- `GetDateTimeIfNotNull` + +## Sample 2: Stored Procedure with Input/Output Parameters + Result Check + +```csharp +using var con = Database.Open(); +using var cmd = con.CreateCommand() + .SetCommand(CommandType.StoredProcedure, "usp_set_message_status") + .AddParameter(Database.GetParameterName("id"), DbType.String, (object)messageId) + .AddParameter(Database.GetParameterName("status"), DbType.Int32, (object)(int)status) + .AddParameter(Database.GetParameterName("note"), DbType.String, (object)note) + .AddParameter(Database.GetParameterName("result"), ParameterDirection.Output, DbType.Int32, 0, null) + .AddParameter(Database.GetParameterName("result_description"), ParameterDirection.Output, DbType.String, 1024, null); + +cmd.ExecuteNonQuery(); + +var result = cmd.Parameters[Database.GetParameterName("result")] as IDataParameter; +var resultDescription = cmd.Parameters[Database.GetParameterName("result_description")] as IDataParameter; + +if (result != null && result.Value != DBNull.Value && result.Value != null) +{ + if ((int)result.Value != 0) + { + var description = (resultDescription != null && + resultDescription.Value != DBNull.Value && + resultDescription.Value != null) + ? resultDescription.Value.ToString() + : "UNSPECIFIED"; + + throw new Exception($"{result.Value} - {description}"); + } +} +``` + +Extension methods used: + +- `SetCommand(CommandType, string)` +- `AddParameter(...)` overloads with `DbType` and `ParameterDirection` +- `DumpToString()` (optional diagnostic logging) + +## Sample 3: Parameterized `UPDATE` with Runtime SQL and ADO.NET Extensions + +```csharp +using var conn = Database.Open(); + +using var cmdUpdate = conn.CreateCommand() + .SetCommand($@"UPDATE {Database.DecorateName("transport_task")} +SET {Database.DecorateName("confirmed")} = {Database.GetParameterName("confirmed")} +WHERE {Database.DecorateName("id")} = {Database.GetParameterName("id")}") + .AddParameter(Database.GetParameterName("confirmed"), DbType.Int32, (object)1) + .AddParameter(Database.GetParameterName("id"), DbType.Guid, (object)taskId); + +if (cmdUpdate.ExecuteNonQuery() > 0) +{ + // updated +} +``` + +Extension methods used: + +- `SetCommand(string, params object[])` +- `AddParameter(string, DbType, object)` + +## Sample 4: Parameterized `SELECT` + Reader Mapping Method + +```csharp +using var conn = Database.Open(); + +using var cmd = conn.CreateCommand() + .SetCommand($@"SELECT * FROM {Database.DecorateName("transport_task")} +WHERE {Database.DecorateName("id")} = {Database.GetParameterName("id")}") + .AddParameter(Database.GetParameterName("id"), DbType.Guid, (object)id); + +using var r = cmd.ExecuteReader(); +if (r.Read()) + return ReadTask(r); + +return null; + +protected virtual MoveTask ReadTask(IDataReader r) +{ + var source = r.GetStringIfNotNull("Source"); + var destination = r.GetStringIfNotNull("Destination"); + + return new MoveTask + { + Id = r.GetGuid(r.GetOrdinal("Id")), + Created = r.GetDateTime(r.GetOrdinal("Created")), + StartDate = r.GetDateTimeIfNotNull("StartDate"), + EndDate = r.GetDateTimeIfNotNull("EndDate"), + ExternalId = r.GetStringIfNotNull("ExternalId"), + TaskType = (TransportTaskType)(r.GetInt32IfNotNull("Type") ?? 0), + Source = string.IsNullOrEmpty(source) ? null : Deserialize
(source), + Destination = string.IsNullOrEmpty(destination) ? null : Deserialize
(destination), + Priority = r.GetInt32IfNotNull("Priority") ?? 0, + }; +} +``` + +Extension methods used: + +- `SetCommand(...)` +- `AddParameter(...)` +- `GetStringIfNotNull` +- `GetDateTimeIfNotNull` +- `GetInt32IfNotNull`