Add generic real-world extension method samples
This commit is contained in:
@@ -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<string, GenericMessage>();
|
||||
|
||||
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<Address>(source),
|
||||
Destination = string.IsNullOrEmpty(destination) ? null : Deserialize<Address>(destination),
|
||||
Priority = r.GetInt32IfNotNull("Priority") ?? 0,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Extension methods used:
|
||||
|
||||
- `SetCommand(...)`
|
||||
- `AddParameter(...)`
|
||||
- `GetStringIfNotNull`
|
||||
- `GetDateTimeIfNotNull`
|
||||
- `GetInt32IfNotNull`
|
||||
|
||||
Reference in New Issue
Block a user