Add typed procedure descriptors and Exec invoker
This commit is contained in:
@@ -5361,22 +5361,44 @@ namespace DynamORM
|
||||
// Get generic types
|
||||
IList<Type> types = binder.GetGenericTypeArguments() ?? new List<Type>();
|
||||
Type declaredResultType = null;
|
||||
string procedureName = binder.Name;
|
||||
string resultName = binder.Name;
|
||||
Type execArgumentsType = null;
|
||||
|
||||
if (binder.Name == "Exec")
|
||||
{
|
||||
if (types.Count != 1)
|
||||
throw new InvalidOperationException("Exec<TProcedure>(args) requires exactly one generic procedure descriptor type.");
|
||||
|
||||
DynamicProcedureDescriptor descriptor = DynamicProcedureDescriptor.Resolve(types[0]);
|
||||
procedureName = descriptor.ProcedureName;
|
||||
resultName = descriptor.ResultName;
|
||||
execArgumentsType = descriptor.ArgumentsType;
|
||||
declaredResultType = descriptor.ResultType;
|
||||
types = new List<Type>();
|
||||
|
||||
if (args.Length > 1)
|
||||
throw new InvalidOperationException("Exec<TProcedure>(args) accepts at most one arguments contract instance.");
|
||||
|
||||
if (args.Length == 1 && args[0] != null && !execArgumentsType.IsAssignableFrom(args[0].GetType()))
|
||||
throw new InvalidOperationException(string.Format("Exec<{0}>(args) expects argument of type '{1}', received '{2}'.", descriptor.ProcedureType.FullName, execArgumentsType.FullName, args[0].GetType().FullName));
|
||||
}
|
||||
Dictionary<string, int> retParams = null;
|
||||
|
||||
using (IDbConnection con = _db.Open())
|
||||
using (IDbCommand cmd = con.CreateCommand())
|
||||
{
|
||||
if (_prefixes == null || _prefixes.Count == 0)
|
||||
cmd.SetCommand(CommandType.StoredProcedure, binder.Name);
|
||||
cmd.SetCommand(CommandType.StoredProcedure, procedureName);
|
||||
else
|
||||
cmd.SetCommand(CommandType.StoredProcedure, string.Format("{0}.{1}", string.Join(".", _prefixes), binder.Name));
|
||||
cmd.SetCommand(CommandType.StoredProcedure, string.Format("{0}.{1}", string.Join(".", _prefixes), procedureName));
|
||||
|
||||
#region Prepare arguments
|
||||
|
||||
int alen = args.Length;
|
||||
bool retIsAdded = false;
|
||||
declaredResultType = alen == 1 ? DynamicProcedureResultBinder.GetDeclaredResultType(args[0]) : null;
|
||||
if (declaredResultType == null)
|
||||
declaredResultType = alen == 1 ? DynamicProcedureResultBinder.GetDeclaredResultType(args[0]) : null;
|
||||
|
||||
if (alen > 0)
|
||||
{
|
||||
@@ -5561,7 +5583,7 @@ namespace DynamORM
|
||||
{
|
||||
using (IDataReader rdr = cmd.ExecuteReader())
|
||||
using (IDataReader cache = rdr.CachedReader())
|
||||
mainResult = cache.ToDataTable(binder.Name);
|
||||
mainResult = cache.ToDataTable(resultName);
|
||||
}
|
||||
else if (types[0].IsGenericEnumerable())
|
||||
{
|
||||
@@ -5688,9 +5710,9 @@ namespace DynamORM
|
||||
if (mainResult != null)
|
||||
{
|
||||
if (mainResult == DBNull.Value)
|
||||
res.Add(binder.Name, null);
|
||||
res.Add(resultName, null);
|
||||
else
|
||||
res.Add(binder.Name, mainResult);
|
||||
res.Add(resultName, mainResult);
|
||||
}
|
||||
foreach (KeyValuePair<string, int> pos in retParams)
|
||||
res.Add(pos.Key, ((IDbDataParameter)cmd.Parameters[pos.Value]).Value);
|
||||
@@ -5705,14 +5727,14 @@ namespace DynamORM
|
||||
result = res.ToDynamic();
|
||||
}
|
||||
else if (declaredResultType != null)
|
||||
result = DynamicProcedureResultBinder.BindPayload(declaredResultType, binder.Name, mainResult, res.Where(x => x.Key != binder.Name).ToDictionary(x => x.Key, x => x.Value), mainResult != null && declaredResultType.IsInstanceOfType(mainResult) ? mainResult : null);
|
||||
result = DynamicProcedureResultBinder.BindPayload(declaredResultType, resultName, mainResult, res.Where(x => x.Key != resultName).ToDictionary(x => x.Key, x => x.Value), mainResult != null && declaredResultType.IsInstanceOfType(mainResult) ? mainResult : null);
|
||||
else
|
||||
result = res.ToDynamic();
|
||||
}
|
||||
else if (declaredResultType != null && mainResult != null && declaredResultType.IsInstanceOfType(mainResult))
|
||||
result = mainResult;
|
||||
else if (declaredResultType != null)
|
||||
result = DynamicProcedureResultBinder.BindPayload(declaredResultType, binder.Name, mainResult, null);
|
||||
result = DynamicProcedureResultBinder.BindPayload(declaredResultType, resultName, mainResult, null);
|
||||
else
|
||||
result = mainResult;
|
||||
|
||||
@@ -14440,6 +14462,67 @@ namespace DynamORM
|
||||
return resultTable;
|
||||
}
|
||||
}
|
||||
internal sealed class DynamicProcedureDescriptor
|
||||
{
|
||||
public Type ProcedureType { get; set; }
|
||||
public Type ArgumentsType { get; set; }
|
||||
public Type ResultType { get; set; }
|
||||
public string ProcedureName { get; set; }
|
||||
public string ResultName { get; set; }
|
||||
|
||||
internal static DynamicProcedureDescriptor Resolve(Type procedureType)
|
||||
{
|
||||
if (procedureType == null)
|
||||
throw new ArgumentNullException("procedureType");
|
||||
|
||||
Type current = procedureType;
|
||||
Type argumentsType = null;
|
||||
Type resultType = null;
|
||||
|
||||
while (current != null && current != typeof(object))
|
||||
{
|
||||
if (current.IsGenericType)
|
||||
{
|
||||
Type genericDefinition = current.GetGenericTypeDefinition();
|
||||
Type[] genericArguments = current.GetGenericArguments();
|
||||
|
||||
if (genericDefinition == typeof(Procedure<>) && genericArguments.Length == 1)
|
||||
{
|
||||
argumentsType = genericArguments[0];
|
||||
break;
|
||||
}
|
||||
if (genericDefinition == typeof(Procedure<,>) && genericArguments.Length == 2)
|
||||
{
|
||||
argumentsType = genericArguments[0];
|
||||
resultType = genericArguments[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
current = current.BaseType;
|
||||
}
|
||||
if (argumentsType == null)
|
||||
throw new InvalidOperationException(string.Format("Type '{0}' is not a typed procedure descriptor.", procedureType.FullName));
|
||||
|
||||
if (!typeof(IProcedureParameters).IsAssignableFrom(argumentsType))
|
||||
throw new InvalidOperationException(string.Format("Procedure descriptor '{0}' declares argument type '{1}' that does not implement IProcedureParameters.", procedureType.FullName, argumentsType.FullName));
|
||||
|
||||
ProcedureAttribute attr = procedureType.GetCustomAttributes(typeof(ProcedureAttribute), true)
|
||||
.Cast<ProcedureAttribute>()
|
||||
.FirstOrDefault();
|
||||
|
||||
string name = attr != null && !string.IsNullOrEmpty(attr.Name) ? attr.Name : procedureType.Name;
|
||||
string owner = attr != null ? attr.Owner : null;
|
||||
|
||||
return new DynamicProcedureDescriptor
|
||||
{
|
||||
ProcedureType = procedureType,
|
||||
ArgumentsType = argumentsType,
|
||||
ResultType = resultType,
|
||||
ProcedureName = string.IsNullOrEmpty(owner) ? name : string.Format("{0}.{1}", owner, name),
|
||||
ResultName = name
|
||||
};
|
||||
}
|
||||
}
|
||||
internal static class DynamicProcedureParameterBinder
|
||||
{
|
||||
internal sealed class BindingResult
|
||||
@@ -17935,6 +18018,19 @@ namespace DynamORM
|
||||
public class IgnoreAttribute : Attribute
|
||||
{
|
||||
}
|
||||
/// <summary>Allows to add stored procedure metadata to class.</summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ProcedureAttribute : Attribute
|
||||
{
|
||||
/// <summary>Gets or sets procedure owner name.</summary>
|
||||
public string Owner { get; set; }
|
||||
|
||||
/// <summary>Gets or sets procedure name.</summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether metadata overrides other defaults.</summary>
|
||||
public bool Override { get; set; }
|
||||
}
|
||||
/// <summary>Declares metadata for object-based stored procedure parameters.</summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ProcedureParameterAttribute : ColumnAttribute
|
||||
@@ -18456,6 +18552,19 @@ namespace DynamORM
|
||||
_database = null;
|
||||
}
|
||||
}
|
||||
/// <summary>Base class for typed stored procedure descriptors.</summary>
|
||||
/// <typeparam name="TArgs">Procedure arguments contract.</typeparam>
|
||||
public abstract class Procedure<TArgs>
|
||||
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>
|
||||
where TArgs : IProcedureParameters
|
||||
{
|
||||
}
|
||||
/// <summary>Marks an object as an explicit stored procedure parameter contract.</summary>
|
||||
public interface IProcedureParameters
|
||||
{
|
||||
|
||||
@@ -139,4 +139,18 @@ namespace DynamORM.Tests.Helpers
|
||||
[ProcedureParameter("status", Direction = ParameterDirection.Output, Order = 1, DbType = DbType.Int32)]
|
||||
public int Status { get; set; }
|
||||
}
|
||||
|
||||
[Procedure(Name = "sp_exec_test", Owner = "dbo")]
|
||||
public class ExecProcedureDescriptor : Procedure<ProcedureParameterObject>
|
||||
{
|
||||
}
|
||||
|
||||
public class ExecProcedureDefaultDescriptor : Procedure<ProcedureParameterObject>
|
||||
{
|
||||
}
|
||||
|
||||
[Procedure(Name = "sp_exec_result")]
|
||||
public class ExecProcedureDescriptorWithExplicitResult : Procedure<ProcedureParameterColumnFallbackObject, ProcedureAttributedResult>
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
using System.Data;
|
||||
using System.Dynamic;
|
||||
using DynamORM.Helpers;
|
||||
using DynamORM.Tests.Helpers;
|
||||
using NUnit.Framework;
|
||||
@@ -122,6 +123,55 @@ namespace DynamORM.Tests.Procedure
|
||||
Assert.IsNull(DynamicProcedureResultBinder.GetDeclaredResultType(new object()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestProcedureDescriptorResolvesAttributeNameAndArguments()
|
||||
{
|
||||
var descriptor = DynamicProcedureDescriptor.Resolve(typeof(ExecProcedureDescriptor));
|
||||
|
||||
Assert.AreEqual(typeof(ExecProcedureDescriptor), descriptor.ProcedureType);
|
||||
Assert.AreEqual(typeof(ProcedureParameterObject), descriptor.ArgumentsType);
|
||||
Assert.IsNull(descriptor.ResultType);
|
||||
Assert.AreEqual("dbo.sp_exec_test", descriptor.ProcedureName);
|
||||
Assert.AreEqual("sp_exec_test", descriptor.ResultName);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestProcedureDescriptorResolvesDefaultNameAndExplicitResult()
|
||||
{
|
||||
var defaultDescriptor = DynamicProcedureDescriptor.Resolve(typeof(ExecProcedureDefaultDescriptor));
|
||||
var explicitDescriptor = DynamicProcedureDescriptor.Resolve(typeof(ExecProcedureDescriptorWithExplicitResult));
|
||||
|
||||
Assert.AreEqual("ExecProcedureDefaultDescriptor", defaultDescriptor.ProcedureName);
|
||||
Assert.AreEqual(typeof(ProcedureParameterObject), defaultDescriptor.ArgumentsType);
|
||||
Assert.IsNull(defaultDescriptor.ResultType);
|
||||
|
||||
Assert.AreEqual("sp_exec_result", explicitDescriptor.ProcedureName);
|
||||
Assert.AreEqual(typeof(ProcedureParameterColumnFallbackObject), explicitDescriptor.ArgumentsType);
|
||||
Assert.AreEqual(typeof(ProcedureAttributedResult), explicitDescriptor.ResultType);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExecRejectsWrongArgumentsType()
|
||||
{
|
||||
dynamic procedures = new DynamicProcedureInvoker(null);
|
||||
|
||||
Assert.Throws<System.InvalidOperationException>(() =>
|
||||
{
|
||||
var ignored = procedures.Exec<ExecProcedureDescriptor>(new ProcedureParameterColumnFallbackObject());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExecRejectsMultipleArguments()
|
||||
{
|
||||
dynamic procedures = new DynamicProcedureInvoker(null);
|
||||
|
||||
Assert.Throws<System.InvalidOperationException>(() =>
|
||||
{
|
||||
var ignored = procedures.Exec<ExecProcedureDescriptor>(new ProcedureParameterObject(), new ProcedureParameterObject());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestDeclaredResultPayloadBindingMapsMainAndOutValues()
|
||||
{
|
||||
|
||||
@@ -86,30 +86,53 @@ namespace DynamORM
|
||||
/// <param name="args">Binder arguments.</param>
|
||||
/// <param name="result">Binder invoke result.</param>
|
||||
/// <returns>Returns <c>true</c> if invoke was performed.</returns>
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
// parse the method
|
||||
public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
|
||||
{
|
||||
// parse the method
|
||||
CallInfo info = binder.CallInfo;
|
||||
|
||||
// Get generic types
|
||||
IList<Type> types = binder.GetGenericTypeArguments() ?? new List<Type>();
|
||||
Type declaredResultType = null;
|
||||
string procedureName = binder.Name;
|
||||
string resultName = binder.Name;
|
||||
Type execArgumentsType = null;
|
||||
|
||||
if (binder.Name == "Exec")
|
||||
{
|
||||
if (types.Count != 1)
|
||||
throw new InvalidOperationException("Exec<TProcedure>(args) requires exactly one generic procedure descriptor type.");
|
||||
|
||||
DynamicProcedureDescriptor descriptor = DynamicProcedureDescriptor.Resolve(types[0]);
|
||||
procedureName = descriptor.ProcedureName;
|
||||
resultName = descriptor.ResultName;
|
||||
execArgumentsType = descriptor.ArgumentsType;
|
||||
declaredResultType = descriptor.ResultType;
|
||||
types = new List<Type>();
|
||||
|
||||
if (args.Length > 1)
|
||||
throw new InvalidOperationException("Exec<TProcedure>(args) accepts at most one arguments contract instance.");
|
||||
|
||||
if (args.Length == 1 && args[0] != null && !execArgumentsType.IsAssignableFrom(args[0].GetType()))
|
||||
throw new InvalidOperationException(string.Format("Exec<{0}>(args) expects argument of type '{1}', received '{2}'.", descriptor.ProcedureType.FullName, execArgumentsType.FullName, args[0].GetType().FullName));
|
||||
}
|
||||
|
||||
Dictionary<string, int> retParams = null;
|
||||
|
||||
using (IDbConnection con = _db.Open())
|
||||
using (IDbCommand cmd = con.CreateCommand())
|
||||
{
|
||||
if (_prefixes == null || _prefixes.Count == 0)
|
||||
cmd.SetCommand(CommandType.StoredProcedure, binder.Name);
|
||||
else
|
||||
cmd.SetCommand(CommandType.StoredProcedure, string.Format("{0}.{1}", string.Join(".", _prefixes), binder.Name));
|
||||
if (_prefixes == null || _prefixes.Count == 0)
|
||||
cmd.SetCommand(CommandType.StoredProcedure, procedureName);
|
||||
else
|
||||
cmd.SetCommand(CommandType.StoredProcedure, string.Format("{0}.{1}", string.Join(".", _prefixes), procedureName));
|
||||
|
||||
#region Prepare arguments
|
||||
|
||||
int alen = args.Length;
|
||||
bool retIsAdded = false;
|
||||
declaredResultType = alen == 1 ? DynamicProcedureResultBinder.GetDeclaredResultType(args[0]) : null;
|
||||
if (declaredResultType == null)
|
||||
declaredResultType = alen == 1 ? DynamicProcedureResultBinder.GetDeclaredResultType(args[0]) : null;
|
||||
|
||||
if (alen > 0)
|
||||
{
|
||||
@@ -301,7 +324,7 @@ namespace DynamORM
|
||||
{
|
||||
using (IDataReader rdr = cmd.ExecuteReader())
|
||||
using (IDataReader cache = rdr.CachedReader())
|
||||
mainResult = cache.ToDataTable(binder.Name);
|
||||
mainResult = cache.ToDataTable(resultName);
|
||||
}
|
||||
else if (types[0].IsGenericEnumerable())
|
||||
{
|
||||
@@ -433,10 +456,10 @@ namespace DynamORM
|
||||
if (mainResult != null)
|
||||
{
|
||||
if (mainResult == DBNull.Value)
|
||||
res.Add(binder.Name, null);
|
||||
else
|
||||
res.Add(binder.Name, mainResult);
|
||||
}
|
||||
res.Add(resultName, null);
|
||||
else
|
||||
res.Add(resultName, mainResult);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, int> pos in retParams)
|
||||
res.Add(pos.Key, ((IDbDataParameter)cmd.Parameters[pos.Value]).Value);
|
||||
@@ -451,14 +474,14 @@ namespace DynamORM
|
||||
result = res.ToDynamic();
|
||||
}
|
||||
else if (declaredResultType != null)
|
||||
result = DynamicProcedureResultBinder.BindPayload(declaredResultType, binder.Name, mainResult, res.Where(x => x.Key != binder.Name).ToDictionary(x => x.Key, x => x.Value), mainResult != null && declaredResultType.IsInstanceOfType(mainResult) ? mainResult : null);
|
||||
result = DynamicProcedureResultBinder.BindPayload(declaredResultType, resultName, mainResult, res.Where(x => x.Key != resultName).ToDictionary(x => x.Key, x => x.Value), mainResult != null && declaredResultType.IsInstanceOfType(mainResult) ? mainResult : null);
|
||||
else
|
||||
result = res.ToDynamic();
|
||||
}
|
||||
else if (declaredResultType != null && mainResult != null && declaredResultType.IsInstanceOfType(mainResult))
|
||||
result = mainResult;
|
||||
else if (declaredResultType != null)
|
||||
result = DynamicProcedureResultBinder.BindPayload(declaredResultType, binder.Name, mainResult, null);
|
||||
result = DynamicProcedureResultBinder.BindPayload(declaredResultType, resultName, mainResult, null);
|
||||
else
|
||||
result = mainResult;
|
||||
|
||||
|
||||
100
DynamORM/Helpers/DynamicProcedureDescriptor.cs
Normal file
100
DynamORM/Helpers/DynamicProcedureDescriptor.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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 System;
|
||||
using System.Linq;
|
||||
using DynamORM.Mapper;
|
||||
using DynamORM.Objects;
|
||||
|
||||
namespace DynamORM.Helpers
|
||||
{
|
||||
internal sealed class DynamicProcedureDescriptor
|
||||
{
|
||||
public Type ProcedureType { get; set; }
|
||||
public Type ArgumentsType { get; set; }
|
||||
public Type ResultType { get; set; }
|
||||
public string ProcedureName { get; set; }
|
||||
public string ResultName { get; set; }
|
||||
|
||||
internal static DynamicProcedureDescriptor Resolve(Type procedureType)
|
||||
{
|
||||
if (procedureType == null)
|
||||
throw new ArgumentNullException("procedureType");
|
||||
|
||||
Type current = procedureType;
|
||||
Type argumentsType = null;
|
||||
Type resultType = null;
|
||||
|
||||
while (current != null && current != typeof(object))
|
||||
{
|
||||
if (current.IsGenericType)
|
||||
{
|
||||
Type genericDefinition = current.GetGenericTypeDefinition();
|
||||
Type[] genericArguments = current.GetGenericArguments();
|
||||
|
||||
if (genericDefinition == typeof(Procedure<>) && genericArguments.Length == 1)
|
||||
{
|
||||
argumentsType = genericArguments[0];
|
||||
break;
|
||||
}
|
||||
|
||||
if (genericDefinition == typeof(Procedure<,>) && genericArguments.Length == 2)
|
||||
{
|
||||
argumentsType = genericArguments[0];
|
||||
resultType = genericArguments[1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current = current.BaseType;
|
||||
}
|
||||
|
||||
if (argumentsType == null)
|
||||
throw new InvalidOperationException(string.Format("Type '{0}' is not a typed procedure descriptor.", procedureType.FullName));
|
||||
|
||||
if (!typeof(IProcedureParameters).IsAssignableFrom(argumentsType))
|
||||
throw new InvalidOperationException(string.Format("Procedure descriptor '{0}' declares argument type '{1}' that does not implement IProcedureParameters.", procedureType.FullName, argumentsType.FullName));
|
||||
|
||||
ProcedureAttribute attr = procedureType.GetCustomAttributes(typeof(ProcedureAttribute), true)
|
||||
.Cast<ProcedureAttribute>()
|
||||
.FirstOrDefault();
|
||||
|
||||
string name = attr != null && !string.IsNullOrEmpty(attr.Name) ? attr.Name : procedureType.Name;
|
||||
string owner = attr != null ? attr.Owner : null;
|
||||
|
||||
return new DynamicProcedureDescriptor
|
||||
{
|
||||
ProcedureType = procedureType,
|
||||
ArgumentsType = argumentsType,
|
||||
ResultType = resultType,
|
||||
ProcedureName = string.IsNullOrEmpty(owner) ? name : string.Format("{0}.{1}", owner, name),
|
||||
ResultName = name
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
46
DynamORM/Mapper/ProcedureAttribute.cs
Normal file
46
DynamORM/Mapper/ProcedureAttribute.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 System;
|
||||
|
||||
namespace DynamORM.Mapper
|
||||
{
|
||||
/// <summary>Allows to add stored procedure metadata to class.</summary>
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ProcedureAttribute : Attribute
|
||||
{
|
||||
/// <summary>Gets or sets procedure owner name.</summary>
|
||||
public string Owner { get; set; }
|
||||
|
||||
/// <summary>Gets or sets procedure name.</summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>Gets or sets a value indicating whether metadata overrides other defaults.</summary>
|
||||
public bool Override { get; set; }
|
||||
}
|
||||
}
|
||||
45
DynamORM/Objects/Procedure.cs
Normal file
45
DynamORM/Objects/Procedure.cs
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
namespace DynamORM.Objects
|
||||
{
|
||||
/// <summary>Base class for typed stored procedure descriptors.</summary>
|
||||
/// <typeparam name="TArgs">Procedure arguments contract.</typeparam>
|
||||
public abstract class Procedure<TArgs>
|
||||
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>
|
||||
where TArgs : IProcedureParameters
|
||||
{
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user