This commit is contained in:
grzegorz.russek
2015-05-15 23:11:59 +00:00
parent 8c10309946
commit 31dd69dfc5
64 changed files with 794 additions and 263 deletions

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,7 @@
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Data; using System.Data;
@@ -935,6 +936,7 @@ namespace DynamORM
#region Internal fields and properties #region Internal fields and properties
private DbProviderFactory _provider; private DbProviderFactory _provider;
private DynamicProcedureInvoker _proc;
private string _connectionString; private string _connectionString;
private bool _singleConnection; private bool _singleConnection;
private bool _singleTransaction; private bool _singleTransaction;
@@ -1006,6 +1008,23 @@ namespace DynamORM
/// <summary>Gets the database provider.</summary> /// <summary>Gets the database provider.</summary>
public DbProviderFactory Provider { get { return _provider; } } public DbProviderFactory Provider { get { return _provider; } }
/// <summary>Gets the procedures invoker.</summary>
public dynamic Procedures
{
get
{
if (_proc == null)
{
if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures)
throw new InvalidOperationException("Database connection desn't support stored procedures.");
_proc = new DynamicProcedureInvoker(this);
}
return _proc;
}
}
/// <summary>Gets or sets a value indicating whether /// <summary>Gets or sets a value indicating whether
/// dump commands to console or not.</summary> /// dump commands to console or not.</summary>
public bool DumpCommands { get; set; } public bool DumpCommands { get; set; }
@@ -2636,6 +2655,8 @@ namespace DynamORM
} }
ClearSchema(); ClearSchema();
if (_proc != null)
_proc.Dispose();
IsDisposed = true; IsDisposed = true;
} }
@@ -3007,7 +3028,14 @@ namespace DynamORM
{ {
if (args != null && args.Count() > 0) if (args != null && args.Count() > 0)
foreach (object item in args) foreach (object item in args)
cmd.AddParameter(database, item); {
if (item is DynamicExpando)
cmd.AddParameters(database, (DynamicExpando)item);
else if (item is ExpandoObject)
cmd.AddParameters(database, (ExpandoObject)item);
else
cmd.AddParameter(database, item);
}
return cmd; return cmd;
} }
@@ -4210,6 +4238,12 @@ namespace DynamORM
return TypeMap.TryGetNullable(r.GetFieldType(i)) ?? DbType.String; return TypeMap.TryGetNullable(r.GetFieldType(i)) ?? DbType.String;
} }
internal static IEnumerable<dynamic> EnumerateReader(this IDataReader r)
{
while (r.Read())
yield return r.RowToDynamic();
}
#endregion IDataReader extensions #endregion IDataReader extensions
#region Mapper extensions #region Mapper extensions
@@ -4383,6 +4417,203 @@ namespace DynamORM
#endregion Coalesce - besicaly not an extensions #endregion Coalesce - besicaly not an extensions
} }
/// <summary>Dynamic procedure invoker.</summary>
/// <remarks>Unfortunately I can use <c>out</c> and <c>ref</c> to
/// return parameters, <see href="http://stackoverflow.com/questions/2475310/c-sharp-4-0-dynamic-doesnt-set-ref-out-arguments"/>.
/// But see example for workaround. If there aren't any return parameters execution will return scalar value.
/// Scalar result is not converted to provided generic type (if any). For output results there is possibility to map to provided class.
/// </remarks><example>You still can use out, return and both way parameters by providing variable prefix:<code>
/// dynamic res = db.Procedures.sp_Test_Scalar_In_Out(inp: Guid.NewGuid(), out_outp: Guid.Empty);
/// Console.Out.WriteLine(res.outp);</code>
/// Prefixes: <c>out_</c>, <c>ret_</c>, <c>both_</c>. Result will contain field without prefix.
/// Here is an example with result class:<code>
/// public class ProcResult { [Column("outp")] public Guid Output { get; set; } }
/// ProcResult res4 = db.Procedures.sp_Test_Scalar_In_Out&lt;ProcResult&gt;(inp: Guid.NewGuid(), out_outp: Guid.Empty) as ProcResult;
/// </code>As you can se, you can use mapper to do job for you.</example>
public class DynamicProcedureInvoker : DynamicObject, IDisposable
{
private DynamicDatabase _db;
internal DynamicProcedureInvoker(DynamicDatabase db)
{
_db = db;
}
/// <summary>This is where the magic begins.</summary>
/// <param name="binder">Binder to invoke.</param>
/// <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
CallInfo info = binder.CallInfo;
// Get generic types
IList<Type> types = binder.GetGenericTypeArguments();
Dictionary<string, int> retParams = null;
using (IDbConnection con = _db.Open())
using (IDbCommand cmd = con.CreateCommand())
{
cmd.SetCommand(CommandType.StoredProcedure, binder.Name);
#region Prepare arguments
int alen = args.Length;
if (alen > 0)
{
for (int i = 0; i < alen; i++)
{
object arg = args[i];
if (arg is DynamicExpando)
cmd.AddParameters(_db, (DynamicExpando)arg);
else if (arg is ExpandoObject)
cmd.AddParameters(_db, (ExpandoObject)arg);
else
{
if (info.ArgumentNames.Count > i && !string.IsNullOrEmpty(info.ArgumentNames[i]))
{
bool isOut = info.ArgumentNames[i].StartsWith("out_");
bool isRet = info.ArgumentNames[i].StartsWith("ret_");
bool isBoth = info.ArgumentNames[i].StartsWith("both_");
string paramName = isOut || isRet ?
info.ArgumentNames[i].Substring(4) :
isBoth ? info.ArgumentNames[i].Substring(5) :
info.ArgumentNames[i];
if (isOut || isBoth || isRet)
{
if (retParams == null)
retParams = new Dictionary<string, int>();
retParams.Add(paramName, cmd.Parameters.Count);
}
cmd.AddParameter(
_db.GetParameterName(paramName),
isOut ? ParameterDirection.Output :
isRet ? ParameterDirection.ReturnValue :
isBoth ? ParameterDirection.InputOutput : ParameterDirection.Input,
arg == null ? DbType.String : arg.GetType().ToDbType(), 0, isOut ? DBNull.Value : arg);
}
else
cmd.AddParameter(_db, arg);
}
}
}
#endregion Prepare arguments
#region Get main result
object mainResult = null;
if (types.Count > 0)
{
mainResult = types[0].GetDefaultValue();
if (types[0] == typeof(IDataReader))
mainResult = cmd.ExecuteReader();
else if (types[0].IsGenericEnumerable())
{
Type argType = types[0].GetGenericArguments().First();
if (argType == typeof(object))
using (IDataReader rdr = cmd.ExecuteReader())
mainResult = rdr.EnumerateReader().ToList();
else if (argType.IsValueType)
{
Type listType = typeof(List<>).MakeGenericType(new Type[] { argType });
IList listInstance = (IList)Activator.CreateInstance(listType);
object defVal = listType.GetDefaultValue();
using (IDataReader rdr = cmd.ExecuteReader())
while (rdr.Read())
listInstance.Add(rdr[0] == DBNull.Value ? defVal : argType.CastObject(rdr[0]));
mainResult = listInstance;
}
else
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(argType);
if (mapper == null)
throw new InvalidCastException(string.Format("Don't konw what to do with this type: '{0}'.", argType.ToString()));
using (IDataReader rdr = cmd.ExecuteReader())
mainResult = rdr.EnumerateReader().MapEnumerable(argType).ToList();
}
}
else if (types[0].IsValueType)
{
mainResult = cmd.ExecuteScalar();
if (mainResult != DBNull.Value)
mainResult = types[0].CastObject(mainResult);
}
else
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(types[0]);
if (mapper == null)
throw new InvalidCastException(string.Format("Don't konw what to do with this type: '{0}'.", types[0].ToString()));
using (IDataReader rdr = cmd.ExecuteReader())
if (rdr.Read())
mainResult = (rdr.ToDynamic() as object).Map(types[0]);
else
mainResult = null;
}
}
else
mainResult = cmd.ExecuteNonQuery();
#endregion Get main result
#region Handle out params
if (retParams != null)
{
Dictionary<string, object> res = new Dictionary<string, object>();
if (mainResult != null)
{
if (mainResult == DBNull.Value)
res.Add(binder.Name, null);
else
res.Add(binder.Name, mainResult);
}
foreach (KeyValuePair<string, int> pos in retParams)
res.Add(pos.Key, ((IDbDataParameter)cmd.Parameters[pos.Value]).Value);
if (types.Count > 1)
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(types[1]);
if (mapper != null)
result = mapper.Create(res.ToDynamic());
else
result = res.ToDynamic();
}
else
result = res.ToDynamic();
}
else
result = mainResult;
#endregion Handle out params
}
return true;
}
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
}
}
/// <summary>Dynamic query exception.</summary> /// <summary>Dynamic query exception.</summary>
[Serializable] [Serializable]
public class DynamicQueryException : Exception, ISerializable public class DynamicQueryException : Exception, ISerializable
@@ -11307,6 +11538,91 @@ namespace DynamORM
#endregion Constructors #endregion Constructors
} }
/// <summary>Type cast helper.</summary>
public static class DynamicCast
{
/// <summary>Gets the default value.</summary>
/// <param name="type">The type.</param>
/// <returns>Default instance.</returns>
public static object GetDefaultValue(this Type type)
{
return type.IsValueType ? TypeDefaults.GetOrAdd(type, t => Activator.CreateInstance(t)) : null;
}
/// <summary>Casts the object to this type.</summary>
/// <param name="type">The type to which cast value.</param>
/// <param name="val">The value to cast.</param>
/// <returns>Value casted to new type.</returns>
public static object CastObject(this Type type, object val)
{
return GetConverter(type, val)(val);
}
private static readonly ConcurrentDictionary<Type, object> TypeDefaults = new ConcurrentDictionary<Type, object>();
private static readonly ConcurrentDictionary<Type, Func<object, object>> TypeAsCasts = new ConcurrentDictionary<Type, Func<object, object>>();
private static readonly ConcurrentDictionary<PairOfTypes, Func<object, object>> TypeConvert = new ConcurrentDictionary<PairOfTypes, Func<object, object>>();
private static readonly ParameterExpression ConvParameter = Expression.Parameter(typeof(object), "val");
[MethodImpl(MethodImplOptions.Synchronized)]
private static Func<object, object> GetConverter(Type targetType, object val)
{
Func<object, object> fn;
if (!targetType.IsValueType && !val.GetType().IsValueType)
{
if (!TypeAsCasts.TryGetValue(targetType, out fn))
{
UnaryExpression instanceCast = Expression.TypeAs(ConvParameter, targetType);
fn = Expression.Lambda<Func<object, object>>(Expression.TypeAs(instanceCast, typeof(object)), ConvParameter).Compile();
TypeAsCasts.AddOrUpdate(targetType, fn, (t, f) => fn);
}
}
else
{
var fromType = val != null ? val.GetType() : typeof(object);
var key = new PairOfTypes(fromType, targetType);
if (TypeConvert.TryGetValue(key, out fn))
return fn;
fn = (Func<object, object>)Expression.Lambda(Expression.Convert(Expression.Convert(Expression.Convert(ConvParameter, fromType), targetType), typeof(object)), ConvParameter).Compile();
TypeConvert.AddOrUpdate(key, fn, (t, f) => fn);
}
return fn;
}
private class PairOfTypes
{
private readonly Type _first;
private readonly Type _second;
public PairOfTypes(Type first, Type second)
{
this._first = first;
this._second = second;
}
public override int GetHashCode()
{
return (31 * _first.GetHashCode()) + _second.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj == this)
return true;
var other = obj as PairOfTypes;
if (other == null)
return false;
return _first.Equals(other._first)
&& _second.Equals(other._second);
}
}
}
/// <summary>Class with mapper cache.</summary> /// <summary>Class with mapper cache.</summary>
public static class DynamicMapperCache public static class DynamicMapperCache
{ {

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Some of methods in this code file is based on Kerosene ORM solution * Some of methods in this code file is based on Kerosene ORM solution

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Some of methods in this code file is based on Kerosene ORM solution * Some of methods in this code file is based on Kerosene ORM solution

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Some of methods in this code file is based on Kerosene ORM solution * Some of methods in this code file is based on Kerosene ORM solution

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Some of methods in this code file is based on Kerosene ORM solution * Some of methods in this code file is based on Kerosene ORM solution

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Some of methods in this code file is based on Kerosene ORM solution * Some of methods in this code file is based on Kerosene ORM solution

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Some of methods in this code file is based on Kerosene ORM solution * Some of methods in this code file is based on Kerosene ORM solution

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Some of methods in this code file is based on Kerosene ORM solution * Some of methods in this code file is based on Kerosene ORM solution

View File

@@ -85,6 +85,7 @@
<Compile Include="DynamicDatabase.cs" /> <Compile Include="DynamicDatabase.cs" />
<Compile Include="DynamicDatabaseOptions.cs" /> <Compile Include="DynamicDatabaseOptions.cs" />
<Compile Include="DynamicExtensions.cs" /> <Compile Include="DynamicExtensions.cs" />
<Compile Include="DynamicProcedureInvoker.cs" />
<Compile Include="DynamicQueryException.cs" /> <Compile Include="DynamicQueryException.cs" />
<Compile Include="DynamicSchemaColumn.cs" /> <Compile Include="DynamicSchemaColumn.cs" />
<Compile Include="DynamicTable.cs" /> <Compile Include="DynamicTable.cs" />
@@ -102,6 +103,7 @@
<Compile Include="Mapper\DynamicTypeMap.cs" /> <Compile Include="Mapper\DynamicTypeMap.cs" />
<Compile Include="Mapper\IgnoreAttribute.cs" /> <Compile Include="Mapper\IgnoreAttribute.cs" />
<Compile Include="Mapper\TableAttribute.cs" /> <Compile Include="Mapper\TableAttribute.cs" />
<Compile Include="Mapper\DynamicCast.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="DynamicExpando.cs" /> <Compile Include="DynamicExpando.cs" />
<Compile Include="Helpers\IFinalizerDisposable.cs" /> <Compile Include="Helpers\IFinalizerDisposable.cs" />

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -47,6 +47,7 @@ namespace DynamORM
#region Internal fields and properties #region Internal fields and properties
private DbProviderFactory _provider; private DbProviderFactory _provider;
private DynamicProcedureInvoker _proc;
private string _connectionString; private string _connectionString;
private bool _singleConnection; private bool _singleConnection;
private bool _singleTransaction; private bool _singleTransaction;
@@ -118,6 +119,23 @@ namespace DynamORM
/// <summary>Gets the database provider.</summary> /// <summary>Gets the database provider.</summary>
public DbProviderFactory Provider { get { return _provider; } } public DbProviderFactory Provider { get { return _provider; } }
/// <summary>Gets the procedures invoker.</summary>
public dynamic Procedures
{
get
{
if (_proc == null)
{
if ((Options & DynamicDatabaseOptions.SupportStoredProcedures) != DynamicDatabaseOptions.SupportStoredProcedures)
throw new InvalidOperationException("Database connection desn't support stored procedures.");
_proc = new DynamicProcedureInvoker(this);
}
return _proc;
}
}
/// <summary>Gets or sets a value indicating whether /// <summary>Gets or sets a value indicating whether
/// dump commands to console or not.</summary> /// dump commands to console or not.</summary>
public bool DumpCommands { get; set; } public bool DumpCommands { get; set; }
@@ -1748,6 +1766,8 @@ namespace DynamORM
} }
ClearSchema(); ClearSchema();
if (_proc != null)
_proc.Dispose();
IsDisposed = true; IsDisposed = true;
} }

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
@@ -210,7 +210,14 @@ namespace DynamORM
{ {
if (args != null && args.Count() > 0) if (args != null && args.Count() > 0)
foreach (object item in args) foreach (object item in args)
cmd.AddParameter(database, item); {
if (item is DynamicExpando)
cmd.AddParameters(database, (DynamicExpando)item);
else if (item is ExpandoObject)
cmd.AddParameters(database, (ExpandoObject)item);
else
cmd.AddParameter(database, item);
}
return cmd; return cmd;
} }
@@ -1413,6 +1420,12 @@ namespace DynamORM
return TypeMap.TryGetNullable(r.GetFieldType(i)) ?? DbType.String; return TypeMap.TryGetNullable(r.GetFieldType(i)) ?? DbType.String;
} }
internal static IEnumerable<dynamic> EnumerateReader(this IDataReader r)
{
while (r.Read())
yield return r.RowToDynamic();
}
#endregion IDataReader extensions #endregion IDataReader extensions
#region Mapper extensions #region Mapper extensions

View File

@@ -0,0 +1,236 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Collections;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using System.Linq;
using DynamORM.Helpers;
using DynamORM.Mapper;
namespace DynamORM
{
/// <summary>Dynamic procedure invoker.</summary>
/// <remarks>Unfortunately I can use <c>out</c> and <c>ref</c> to
/// return parameters, <see href="http://stackoverflow.com/questions/2475310/c-sharp-4-0-dynamic-doesnt-set-ref-out-arguments"/>.
/// But see example for workaround. If there aren't any return parameters execution will return scalar value.
/// Scalar result is not converted to provided generic type (if any). For output results there is possibility to map to provided class.
/// </remarks><example>You still can use out, return and both way parameters by providing variable prefix:<code>
/// dynamic res = db.Procedures.sp_Test_Scalar_In_Out(inp: Guid.NewGuid(), out_outp: Guid.Empty);
/// Console.Out.WriteLine(res.outp);</code>
/// Prefixes: <c>out_</c>, <c>ret_</c>, <c>both_</c>. Result will contain field without prefix.
/// Here is an example with result class:<code>
/// public class ProcResult { [Column("outp")] public Guid Output { get; set; } }
/// ProcResult res4 = db.Procedures.sp_Test_Scalar_In_Out&lt;ProcResult&gt;(inp: Guid.NewGuid(), out_outp: Guid.Empty) as ProcResult;
/// </code>As you can se, you can use mapper to do job for you.</example>
public class DynamicProcedureInvoker : DynamicObject, IDisposable
{
private DynamicDatabase _db;
internal DynamicProcedureInvoker(DynamicDatabase db)
{
_db = db;
}
/// <summary>This is where the magic begins.</summary>
/// <param name="binder">Binder to invoke.</param>
/// <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
CallInfo info = binder.CallInfo;
// Get generic types
IList<Type> types = binder.GetGenericTypeArguments();
Dictionary<string, int> retParams = null;
using (IDbConnection con = _db.Open())
using (IDbCommand cmd = con.CreateCommand())
{
cmd.SetCommand(CommandType.StoredProcedure, binder.Name);
#region Prepare arguments
int alen = args.Length;
if (alen > 0)
{
for (int i = 0; i < alen; i++)
{
object arg = args[i];
if (arg is DynamicExpando)
cmd.AddParameters(_db, (DynamicExpando)arg);
else if (arg is ExpandoObject)
cmd.AddParameters(_db, (ExpandoObject)arg);
else
{
if (info.ArgumentNames.Count > i && !string.IsNullOrEmpty(info.ArgumentNames[i]))
{
bool isOut = info.ArgumentNames[i].StartsWith("out_");
bool isRet = info.ArgumentNames[i].StartsWith("ret_");
bool isBoth = info.ArgumentNames[i].StartsWith("both_");
string paramName = isOut || isRet ?
info.ArgumentNames[i].Substring(4) :
isBoth ? info.ArgumentNames[i].Substring(5) :
info.ArgumentNames[i];
if (isOut || isBoth || isRet)
{
if (retParams == null)
retParams = new Dictionary<string, int>();
retParams.Add(paramName, cmd.Parameters.Count);
}
cmd.AddParameter(
_db.GetParameterName(paramName),
isOut ? ParameterDirection.Output :
isRet ? ParameterDirection.ReturnValue :
isBoth ? ParameterDirection.InputOutput : ParameterDirection.Input,
arg == null ? DbType.String : arg.GetType().ToDbType(), 0, isOut ? DBNull.Value : arg);
}
else
cmd.AddParameter(_db, arg);
}
}
}
#endregion Prepare arguments
#region Get main result
object mainResult = null;
if (types.Count > 0)
{
mainResult = types[0].GetDefaultValue();
if (types[0] == typeof(IDataReader))
mainResult = cmd.ExecuteReader();
else if (types[0].IsGenericEnumerable())
{
Type argType = types[0].GetGenericArguments().First();
if (argType == typeof(object))
using (IDataReader rdr = cmd.ExecuteReader())
mainResult = rdr.EnumerateReader().ToList();
else if (argType.IsValueType)
{
Type listType = typeof(List<>).MakeGenericType(new Type[] { argType });
IList listInstance = (IList)Activator.CreateInstance(listType);
object defVal = listType.GetDefaultValue();
using (IDataReader rdr = cmd.ExecuteReader())
while (rdr.Read())
listInstance.Add(rdr[0] == DBNull.Value ? defVal : argType.CastObject(rdr[0]));
mainResult = listInstance;
}
else
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(argType);
if (mapper == null)
throw new InvalidCastException(string.Format("Don't konw what to do with this type: '{0}'.", argType.ToString()));
using (IDataReader rdr = cmd.ExecuteReader())
mainResult = rdr.EnumerateReader().MapEnumerable(argType).ToList();
}
}
else if (types[0].IsValueType)
{
mainResult = cmd.ExecuteScalar();
if (mainResult != DBNull.Value)
mainResult = types[0].CastObject(mainResult);
}
else
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(types[0]);
if (mapper == null)
throw new InvalidCastException(string.Format("Don't konw what to do with this type: '{0}'.", types[0].ToString()));
using (IDataReader rdr = cmd.ExecuteReader())
if (rdr.Read())
mainResult = (rdr.ToDynamic() as object).Map(types[0]);
else
mainResult = null;
}
}
else
mainResult = cmd.ExecuteNonQuery();
#endregion Get main result
#region Handle out params
if (retParams != null)
{
Dictionary<string, object> res = new Dictionary<string, object>();
if (mainResult != null)
{
if (mainResult == DBNull.Value)
res.Add(binder.Name, null);
else
res.Add(binder.Name, mainResult);
}
foreach (KeyValuePair<string, int> pos in retParams)
res.Add(pos.Key, ((IDbDataParameter)cmd.Parameters[pos.Value]).Value);
if (types.Count > 1)
{
DynamicTypeMap mapper = DynamicMapperCache.GetMapper(types[1]);
if (mapper != null)
result = mapper.Create(res.ToDynamic());
else
result = res.ToDynamic();
}
else
result = res.ToDynamic();
}
else
result = mainResult;
#endregion Handle out params
}
return true;
}
/// <summary>Performs application-defined tasks associated with
/// freeing, releasing, or resetting unmanaged resources.</summary>
public void Dispose()
{
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* This code file is based on Kerosene ORM solution for parsing dynamic * This code file is based on Kerosene ORM solution for parsing dynamic

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -0,0 +1,120 @@
/*
* DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012-2015, 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.Collections.Concurrent;
using System.Linq.Expressions;
using System.Runtime.CompilerServices;
namespace DynamORM.Mapper
{
/// <summary>Type cast helper.</summary>
public static class DynamicCast
{
/// <summary>Gets the default value.</summary>
/// <param name="type">The type.</param>
/// <returns>Default instance.</returns>
public static object GetDefaultValue(this Type type)
{
return type.IsValueType ? TypeDefaults.GetOrAdd(type, t => Activator.CreateInstance(t)) : null;
}
/// <summary>Casts the object to this type.</summary>
/// <param name="type">The type to which cast value.</param>
/// <param name="val">The value to cast.</param>
/// <returns>Value casted to new type.</returns>
public static object CastObject(this Type type, object val)
{
return GetConverter(type, val)(val);
}
private static readonly ConcurrentDictionary<Type, object> TypeDefaults = new ConcurrentDictionary<Type, object>();
private static readonly ConcurrentDictionary<Type, Func<object, object>> TypeAsCasts = new ConcurrentDictionary<Type, Func<object, object>>();
private static readonly ConcurrentDictionary<PairOfTypes, Func<object, object>> TypeConvert = new ConcurrentDictionary<PairOfTypes, Func<object, object>>();
private static readonly ParameterExpression ConvParameter = Expression.Parameter(typeof(object), "val");
[MethodImpl(MethodImplOptions.Synchronized)]
private static Func<object, object> GetConverter(Type targetType, object val)
{
Func<object, object> fn;
if (!targetType.IsValueType && !val.GetType().IsValueType)
{
if (!TypeAsCasts.TryGetValue(targetType, out fn))
{
UnaryExpression instanceCast = Expression.TypeAs(ConvParameter, targetType);
fn = Expression.Lambda<Func<object, object>>(Expression.TypeAs(instanceCast, typeof(object)), ConvParameter).Compile();
TypeAsCasts.AddOrUpdate(targetType, fn, (t, f) => fn);
}
}
else
{
var fromType = val != null ? val.GetType() : typeof(object);
var key = new PairOfTypes(fromType, targetType);
if (TypeConvert.TryGetValue(key, out fn))
return fn;
fn = (Func<object, object>)Expression.Lambda(Expression.Convert(Expression.Convert(Expression.Convert(ConvParameter, fromType), targetType), typeof(object)), ConvParameter).Compile();
TypeConvert.AddOrUpdate(key, fn, (t, f) => fn);
}
return fn;
}
private class PairOfTypes
{
private readonly Type _first;
private readonly Type _second;
public PairOfTypes(Type first, Type second)
{
this._first = first;
this._second = second;
}
public override int GetHashCode()
{
return (31 * _first.GetHashCode()) + _second.GetHashCode();
}
public override bool Equals(object obj)
{
if (obj == this)
return true;
var other = obj as PairOfTypes;
if (other == null)
return false;
return _first.Equals(other._first)
&& _second.Equals(other._second);
}
}
}
}

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,6 +1,6 @@
/* /*
* DynamORM - Dynamic Object-Relational Mapping library. * DynamORM - Dynamic Object-Relational Mapping library.
* Copyright (c) 2012, Grzegorz Russek (grzegorz.russek@gmail.com) * Copyright (c) 2012-2015, Grzegorz Russek (grzegorz.russek@gmail.com)
* All rights reserved. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without

View File

@@ -1,222 +1,46 @@
using System; using System;
using System.Linq;
using DynamORM;
using DynamORM.Mapper; using DynamORM.Mapper;
using System.Collections.Generic;
using System.Dynamic;
namespace Tester namespace Tester
{ {
internal class Program internal class Program
{ {
[Table(Name = "mom_Sessions")]
internal class Session
{
[Column(IsKey = true)]
public virtual Guid ms_id { get; set; }
[Column]
public virtual Guid ms_mus_id { get; set; }
[Column]
public virtual long ms_last_activity { get; set; }
[Column]
public virtual int ms_type { get; set; }
[Column]
public virtual string ms_desc { get; set; }
[Ignore]
public virtual string ms_did { get; set; }
}
private static DynamORM.DynamicDatabase GetORM() private static DynamORM.DynamicDatabase GetORM()
{ {
//return new DynamORM.DynamicDatabase(System.Data.SqlClient.SqlClientFactory.Instance, return new DynamORM.DynamicDatabase(System.Data.SqlClient.SqlClientFactory.Instance,
// "packet size=4096;User Id=sa;Password=sa123;data source=192.168.1.9,1433;initial catalog=MOM_SIERPC_WMS_TEST;", "packet size=4096;User Id=sa;Password=Sa123;data source=192.168.1.9,1434;initial catalog=MAH_Melle-GAGARIN;",
DynamORM.DynamicDatabaseOptions.SingleConnection | DynamORM.DynamicDatabaseOptions.SingleTransaction | DynamORM.DynamicDatabaseOptions.SupportStoredProcedures |
DynamORM.DynamicDatabaseOptions.SupportSchema | DynamORM.DynamicDatabaseOptions.SupportTop);
//return new DynamORM.DynamicDatabase(System.Data.SQLite.SQLiteFactory.Instance,
// "Data Source=test.db3;",
// DynamORM.DynamicDatabaseOptions.SingleConnection | DynamORM.DynamicDatabaseOptions.SingleTransaction | // DynamORM.DynamicDatabaseOptions.SingleConnection | DynamORM.DynamicDatabaseOptions.SingleTransaction |
// DynamORM.DynamicDatabaseOptions.SupportSchema | DynamORM.DynamicDatabaseOptions.SupportTop); // DynamORM.DynamicDatabaseOptions.SupportSchema | DynamORM.DynamicDatabaseOptions.SupportLimitOffset);
return new DynamORM.DynamicDatabase(System.Data.SQLite.SQLiteFactory.Instance, }
"Data Source=test.db3;",
DynamORM.DynamicDatabaseOptions.SingleConnection | DynamORM.DynamicDatabaseOptions.SingleTransaction | public class ProcResult
DynamORM.DynamicDatabaseOptions.SupportSchema | DynamORM.DynamicDatabaseOptions.SupportLimitOffset); {
[Column("sp_Test_Scalar_In_Out")]
public Guid Result { get; set; }
[Column("outp")]
public Guid Output { get; set; }
} }
private static void Main(string[] args) private static void Main(string[] args)
{ {
using (var db = GetORM()) using (var db = GetORM())
using (var con = db.Open())
using (var cmd = con.CreateCommand())
new List<string>()
{
@"CREATE TABLE IF NOT EXISTS Test(id int NOT NULL PRIMARY KEY, val text);",
@"DELETE FROM Test;",
@"INSERT INTO Test VALUES(1, 'Test');",
}.ForEach(x =>
cmd.SetCommand(x)
.ExecuteNonQuery());
Console.Out.WriteLine("Press ENTER to launch bombardment... or q and ENTER to quit.");
while (Console.In.ReadLine() != "q")
{ {
Console.Out.WriteLine("Bombardment..."); Guid res1 = db.Procedures.sp_Test_Scalar<Guid>();
object res2 = db.Procedures.sp_Test_NonScalar();
object res3 = db.Procedures.sp_Test_Scalar_In_Out<Guid>(inp: Guid.NewGuid(), out_outp: Guid.Empty);
ProcResult res4 = db.Procedures.sp_Test_Scalar_In_Out<Guid, ProcResult>(inp: Guid.NewGuid(), out_outp: Guid.Empty);
long membefore = GC.GetTotalMemory(true); Console.Out.WriteLine(res1);
Console.Out.WriteLine(res2);
BombsAway(); Console.Out.WriteLine(res3);
Console.Out.WriteLine(res4.Output);
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Mem Before: {0}, Mem After: {1}. Done.", membefore, GC.GetTotalMemory(true));
} }
} }
private static void BombsAway()
{
string test_str = string.Empty;
/*for (int y = 0; y < 10; y++)
{
string val = null;
for (int i = 0; i < 1000; i++)
{
dynamic o = new ExpandoObject();
o.Test = "123";
o.Test2 = 123;
o.Test3 = true;
o.Test4 = (object)null;
val = o.Test;
val = o.Test2.ToString();
}
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Expr: [ExpandoObject only], Mem: {0}", GC.GetTotalMemory(true));
}
for (int y = 0; y < 10; y++)
{
string val = null;
for (int i = 0; i < 1000; i++)
{
dynamic o = new ExpandoObject();
var d = o as IDictionary<string, object>;
d.Add("Test", "123");
d.Add("Test2", 123);
d.Add("Test3", true);
d.Add("Test4", null);
val = o.Test;
val = o.Test2.ToString();
}
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Expr: [ExpandoObject as Dict], Mem: {0}", GC.GetTotalMemory(true));
}*/
/*for (int y = 0; y < 10; y++)
{
Func<dynamic, object> f = x => x.To == 0;
for (int i = 0; i < 1000; i++)
using (var p = DynamORM.Helpers.Dynamics.DynamicParser.Parse(f))
test_str = p.ToString();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Expr: {0}, Mem: {1}", test_str, GC.GetTotalMemory(true));
}*/
for (int y = 0; y < 10; y++)
{
using (var dbt = GetORM())
using (dbt.Table("Test"))
;
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Expr: [Create and destroy ORM], Mem: {0}", GC.GetTotalMemory(true));
}
//using (var db = GetORM())
{
for (int y = 0; y < 5; y++)
{
using (var db = GetORM())
for (int i = 0; i < 1000; i++)
test_str = ((int)db.Table("Test").Scalar("SELECT id FROM Test;")).ToString();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Expr: [db.Table(\"Test\").Scalar(\"SELECT id FROM Test;\")] = {0}, Mem: {1}", test_str, GC.GetTotalMemory(true));
}
for (int y = 0; y < 5; y++)
{
using (var db = GetORM())
for (int i = 0; i < 1000; i++)
test_str = ((int)db.Table("Test").Scalar(columns: "id")).ToString();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Expr: [db.Table(\"Test\").Scalar(columns: \"id\")] = {0}, Mem: {1}", test_str, GC.GetTotalMemory(true));
}
for (int y = 0; y < 5; y++)
{
using (var db = GetORM())
for (int i = 0; i < 1000; i++)
test_str = db.From(x => x.Test.As(x.t)).Where(t => t.id == 1).ToList().First().val;
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Expr: [db.From(x => x.Test.As(x.t)).Where(t => t.id == 1).ToList().First().val] = {0}, Mem: {1}", test_str, GC.GetTotalMemory(true));
}
for (int y = 0; y < 5; y++)
{
using (var db = GetORM())
for (int i = 0; i < 1000; i++)
test_str = ((int)db.From(x => x.Test.As(x.t)).Where(t => t.id == 1).Select(t => t.id).Scalar()).ToString();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.Out.WriteLine("Expr: [db.From(x => x.Test.As(x.t)).Where(t => t.id == 1).Select(t => t.id).Scalar()] = {0}, Mem: {1}", test_str, GC.GetTotalMemory(true));
}
}
/*for (int i = 0; i < 1000; i++)
using (var db = GetORM())
{
//var session = db.From(x => x.mom_Sessions.As(x.s))
// .Where(s => s.ms_id == Guid.Empty && s.ms_mus_id == Guid.Empty)
// .Execute<Session>()
// .FirstOrDefault();
var session = db.From(x => x.mom_Sessions.As(x.s))
.Where(s => s.ms_id == Guid.Empty && s.ms_mus_id == Guid.Empty)
.Execute()
.FirstOrDefault();
//db.Table("mom_Sessions").Delete()
// .Where("ms_id", Guid.Empty)
// .Where("ms_mus_id", Guid.Empty)
// .Execute();
//var session = (db.Table().Query("SELECT * FROM mom_Sessions WHERE ms_id = @0 AND ms_mus_id = @1", Guid.Empty, Guid.Empty)
// as IEnumerable<dynamic>).FirstOrDefault();
}*/
}
} }
} }