Add strongly typed procedure execution helpers

This commit is contained in:
2026-02-27 16:43:21 +01:00
parent f8353e7488
commit 7c084490d8
6 changed files with 351 additions and 4 deletions

View File

@@ -2699,6 +2699,51 @@ namespace DynamORM
return new DynamicProcedureInvoker(this).Exec<TProcedure>(args);
}
/// <summary>Execute typed stored procedure descriptor with strong result type.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
/// <typeparam name="TResult">Procedure result type.</typeparam>
/// <returns>Procedure result.</returns>
public virtual TResult Procedure<TProcedure, TResult>()
where TProcedure : IProcedureDescriptor<TResult>
{
return Procedure<TProcedure, TResult>(null);
}
/// <summary>Execute typed stored procedure descriptor with strong result type.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
/// <typeparam name="TResult">Procedure result type.</typeparam>
/// <param name="args">Procedure arguments contract.</param>
/// <returns>Procedure result.</returns>
public virtual TResult Procedure<TProcedure, TResult>(object args)
where TProcedure : IProcedureDescriptor<TResult>
{
if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures)
throw new InvalidOperationException("Database connection desn't support stored procedures.");
return new DynamicProcedureInvoker(this).Exec<TProcedure, TResult>(args);
}
/// <summary>Create typed stored procedure execution handle.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
/// <returns>Typed execution handle.</returns>
public virtual TypedProcedureCall<TProcedure> TypedProcedure<TProcedure>()
where TProcedure : IProcedureDescriptor
{
if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures)
throw new InvalidOperationException("Database connection desn't support stored procedures.");
return new TypedProcedureCall<TProcedure>(new DynamicProcedureInvoker(this));
}
/// <summary>Create typed stored procedure execution handle.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
/// <typeparam name="TResult">Procedure result type.</typeparam>
/// <returns>Typed execution handle.</returns>
public virtual TypedProcedureCall<TProcedure, TResult> TypedProcedure<TProcedure, TResult>()
where TProcedure : IProcedureDescriptor<TResult>
{
if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures)
throw new InvalidOperationException("Database connection desn't support stored procedures.");
return new TypedProcedureCall<TProcedure, TResult>(new DynamicProcedureInvoker(this));
}
#endregion Procedure
#region Execute
@@ -5366,6 +5411,33 @@ namespace DynamORM
descriptor.ArgumentsType,
descriptor.ProcedureType);
}
/// <summary>Execute typed stored procedure descriptor with strong result type.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
/// <typeparam name="TResult">Procedure result type.</typeparam>
/// <param name="args">Optional procedure arguments contract.</param>
/// <returns>Procedure result.</returns>
public virtual TResult Exec<TProcedure, TResult>(object args = null)
where TProcedure : IProcedureDescriptor<TResult>
{
return ConvertProcedureResult<TResult>(Exec<TProcedure>(args));
}
/// <summary>Create typed stored procedure execution handle.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
/// <returns>Typed execution handle.</returns>
public virtual TypedProcedureCall<TProcedure> Typed<TProcedure>()
where TProcedure : IProcedureDescriptor
{
return new TypedProcedureCall<TProcedure>(this);
}
/// <summary>Create typed stored procedure execution handle.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
/// <typeparam name="TResult">Procedure result type.</typeparam>
/// <returns>Typed execution handle.</returns>
public virtual TypedProcedureCall<TProcedure, TResult> Typed<TProcedure, TResult>()
where TProcedure : IProcedureDescriptor<TResult>
{
return new TypedProcedureCall<TProcedure, TResult>(this);
}
/// <summary>This is where the magic begins.</summary>
/// <param name="binder">Binder to create owner.</param>
/// <param name="result">Binder invoke result.</param>
@@ -5769,6 +5841,20 @@ namespace DynamORM
}
return result;
}
private static TResult ConvertProcedureResult<TResult>(object result)
{
if (result == null || result == DBNull.Value)
return default(TResult);
if (result is TResult)
return (TResult)result;
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(typeof(TResult));
if (mapper != null)
return (TResult)DynamicExtensions.Map(result, typeof(TResult));
return (TResult)typeof(TResult).CastObject(result);
}
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
@@ -6899,6 +6985,43 @@ namespace DynamORM
#endregion IExtendedDisposable Members
}
/// <summary>Typed stored procedure execution handle.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
public class TypedProcedureCall<TProcedure>
where TProcedure : IProcedureDescriptor
{
protected readonly DynamicProcedureInvoker Invoker;
internal TypedProcedureCall(DynamicProcedureInvoker invoker)
{
Invoker = invoker;
}
/// <summary>Execute stored procedure descriptor.</summary>
/// <param name="args">Optional procedure arguments contract.</param>
/// <returns>Procedure result.</returns>
public virtual object Exec(object args = null)
{
return Invoker.Exec<TProcedure>(args);
}
}
/// <summary>Typed stored procedure execution handle with strong result type.</summary>
/// <typeparam name="TProcedure">Procedure descriptor type.</typeparam>
/// <typeparam name="TResult">Procedure result type.</typeparam>
public class TypedProcedureCall<TProcedure, TResult> : TypedProcedureCall<TProcedure>
where TProcedure : IProcedureDescriptor<TResult>
{
internal TypedProcedureCall(DynamicProcedureInvoker invoker)
: base(invoker)
{
}
/// <summary>Execute stored procedure descriptor.</summary>
/// <param name="args">Optional procedure arguments contract.</param>
/// <returns>Procedure result.</returns>
public new virtual TResult Exec(object args = null)
{
return Invoker.Exec<TProcedure, TResult>(args);
}
}
namespace Builders
{
/// <summary>Typed join kind used by typed fluent builder APIs.</summary>
@@ -18579,16 +18702,26 @@ namespace DynamORM
_database = null;
}
}
/// <summary>Exposes typed stored procedure descriptor metadata.</summary>
public interface IProcedureDescriptor
{
}
/// <summary>Exposes typed stored procedure descriptor metadata with explicit result type.</summary>
/// <typeparam name="TResult">Procedure result type.</typeparam>
public interface IProcedureDescriptor<TResult> : IProcedureDescriptor
{
}
/// <summary>Base class for typed stored procedure descriptors.</summary>
/// <typeparam name="TArgs">Procedure arguments contract.</typeparam>
public abstract class Procedure<TArgs>
: IProcedureDescriptor
where TArgs : IProcedureParameters
{
}
/// <summary>Base class for typed stored procedure descriptors with explicit result model.</summary>
/// <typeparam name="TArgs">Procedure arguments contract.</typeparam>
/// <typeparam name="TResult">Procedure result model.</typeparam>
public abstract class Procedure<TArgs, TResult> : Procedure<TArgs>
public abstract class Procedure<TArgs, TResult> : Procedure<TArgs>, IProcedureDescriptor<TResult>
where TArgs : IProcedureParameters
{
}