Add strongly typed procedure execution helpers
This commit is contained in:
@@ -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
|
||||
{
|
||||
}
|
||||
|
||||
@@ -170,6 +170,39 @@ namespace DynamORM.Tests.Procedure
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExecTypedOverloadRejectsWrongArgumentsType()
|
||||
{
|
||||
var procedures = new DynamicProcedureInvoker(null);
|
||||
|
||||
Assert.Throws<System.InvalidOperationException>(() =>
|
||||
{
|
||||
var ignored = procedures.Exec<ExecProcedureDescriptorWithExplicitResult, ProcedureAttributedResult>(new ProcedureParameterObject());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestTypedProcedureHandleRejectsWrongArgumentsType()
|
||||
{
|
||||
var procedures = new DynamicProcedureInvoker(null);
|
||||
|
||||
Assert.Throws<System.InvalidOperationException>(() =>
|
||||
{
|
||||
var ignored = procedures.Typed<ExecProcedureDescriptorWithExplicitResult, ProcedureAttributedResult>()
|
||||
.Exec(new ProcedureParameterObject());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDynamicDatabaseTypedProcedureHandleRejectsWrongArgumentsType()
|
||||
{
|
||||
Assert.Throws<System.InvalidOperationException>(() =>
|
||||
{
|
||||
var ignored = Database.TypedProcedure<ExecProcedureDescriptorWithExplicitResult, ProcedureAttributedResult>()
|
||||
.Exec(new ProcedureParameterObject());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeclaredResultPayloadBindingMapsMainAndOutValues()
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ using DynamORM.Builders.Extensions;
|
||||
using DynamORM.Builders.Implementation;
|
||||
using DynamORM.Helpers;
|
||||
using DynamORM.Mapper;
|
||||
using DynamORM.Objects;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
@@ -1267,6 +1268,55 @@ 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
|
||||
|
||||
@@ -35,6 +35,7 @@ using System.Dynamic;
|
||||
using System.Linq;
|
||||
using DynamORM.Helpers;
|
||||
using DynamORM.Mapper;
|
||||
using DynamORM.Objects;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
@@ -81,6 +82,36 @@ namespace DynamORM
|
||||
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>
|
||||
@@ -502,6 +533,21 @@ 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()
|
||||
|
||||
@@ -28,9 +28,21 @@
|
||||
|
||||
namespace DynamORM.Objects
|
||||
{
|
||||
/// <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
|
||||
{
|
||||
}
|
||||
@@ -38,7 +50,7 @@ namespace DynamORM.Objects
|
||||
/// <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
|
||||
{
|
||||
}
|
||||
|
||||
73
DynamORM/TypedProcedureCall.cs
Normal file
73
DynamORM/TypedProcedureCall.cs
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* DynamORM - Dynamic Object-Relational Mapping library.
|
||||
* Copyright (c) 2012-2026, Grzegorz Russek (grzegorz.russek@gmail.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using DynamORM.Objects;
|
||||
|
||||
namespace DynamORM
|
||||
{
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user