From 7a545224de76693daad25d94eb4365d126047cdb Mon Sep 17 00:00:00 2001 From: "grzegorz.russek" Date: Wed, 13 May 2015 22:36:30 +0000 Subject: [PATCH] --- AmalgamationTool/DynamORM.Amalgamation.cs | 251 +++++++++++++----- DynamORM.Tests/Select/ParserTests.cs | 39 ++- .../Builders/IDynamicSelectQueryBuilder.cs | 10 + .../DynamicSelectQueryBuilder.cs | 135 ++++++---- DynamORM/DynamicDatabase.cs | 38 +++ DynamORM/DynamicExtensions.cs | 42 +-- DynamORM/DynamicTable.cs | 26 ++ 7 files changed, 393 insertions(+), 148 deletions(-) diff --git a/AmalgamationTool/DynamORM.Amalgamation.cs b/AmalgamationTool/DynamORM.Amalgamation.cs index e3d0fe6..b6883a4 100644 --- a/AmalgamationTool/DynamORM.Amalgamation.cs +++ b/AmalgamationTool/DynamORM.Amalgamation.cs @@ -1932,6 +1932,44 @@ namespace DynamORM } } +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + + /// Returns a single result. + /// What kind of result is expected. + /// SQL query containing numbered parameters in format provided by + /// methods. Also names should be formatted with + /// method. + /// Arguments (parameters). + /// Result of a query. + public virtual T ScalarAs(string sql, params object[] args) + { + using (var con = Open()) + using (var cmd = con.CreateCommand()) + { + return cmd + .SetCommand(sql).AddParameters(this, args) + .ExecuteScalarAs(); + } + } + + /// Returns a single result. + /// What kind of result is expected. + /// Command builder. + /// Default value. + /// Result of a query. + public virtual T ScalarAs(IDynamicQueryBuilder builder, T defaultValue = default(T)) + { + using (var con = Open()) + using (var cmd = con.CreateCommand()) + { + return cmd + .SetCommand(builder) + .ExecuteScalarAs(defaultValue); + } + } + +#endif + #endregion Scalar #region Query @@ -3418,28 +3456,40 @@ namespace DynamORM return (T)o; else if (o != DBNull.Value && o != null) { - var method = typeof(T).GetMethod( - "TryParse", - new[] - { - typeof(string), - Type.GetType(string.Format("{0}&", typeof(T).FullName)) - }); - if (handler != null) ret = o.ToString().TryParseDefault(defaultValue, handler); - else if (method != null) - ret = o.ToString().TryParseDefault(defaultValue, delegate(string v, out T r) - { - r = defaultValue; - return (bool)method.Invoke(null, new object[] { v, r }); - }); + else if (o is IConvertible && typeof(T).GetInterfaces().Any(i => i == typeof(IConvertible))) + ret = (T)Convert.ChangeType(o, typeof(T)); + else if (typeof(T) == typeof(Guid)) + { + if (o.GetType() == typeof(byte[])) + ret = (T)(object)new Guid((byte[])o); + else + ret = (T)(object)Guid.Parse(o.ToString()); + } else if (typeof(T) == typeof(string)) ret = (T)(o.ToString() as object); else if (typeof(T) == typeof(object)) ret = (T)o; else - throw new InvalidOperationException("Provided type can't be parsed using generic approach."); + { + var method = typeof(T).GetMethod( + "TryParse", + new Type[] + { + typeof(string), + Type.GetType(string.Format("{0}&", typeof(T).FullName)) + }); + + if (method != null) + ret = o.ToString().TryParseDefault(defaultValue, delegate(string v, out T r) + { + r = defaultValue; + return (bool)method.Invoke(null, new object[] { v, r }); + }); + else + throw new InvalidOperationException("Provided type can't be parsed using generic approach."); + } } return ret; @@ -4764,6 +4814,32 @@ namespace DynamORM return Database.Scalar(builder); } +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + + /// Returns a single result. + /// What kind of result is expected. + /// SQL query containing numbered parameters in format provided by + /// methods. Also names should be formatted with + /// method. + /// Arguments (parameters). + /// Result of a query. + public virtual T ScalarAs(string sql, params object[] args) + { + return Database.ScalarAs(sql, args); + } + + /// Returns a single result. + /// What kind of result is expected. + /// Command builder. + /// Default value. + /// Result of a query. + public virtual T ScalarAs(IDynamicQueryBuilder builder, T defaultValue = default(T)) + { + return Database.ScalarAs(builder, defaultValue); + } + +#endif + /// Execute stored procedure. /// Name of stored procedure to execute. /// Number of affected rows. @@ -5612,6 +5688,16 @@ namespace DynamORM /// Result of a query. object Scalar(); +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + + /// Returns a single result. + /// Type to parse to. + /// Default value. + /// Result of a query. + T ScalarAs(T defaultValue = default(T)); + +#endif + #region From/Join /// @@ -7530,9 +7616,9 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() { - using (var con = Database.Open()) - using (var cmd = con.CreateCommand()) - using (var rdr = cmd + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) + using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) while (rdr.Read()) @@ -7547,7 +7633,7 @@ namespace DynamORM } catch (ArgumentException argex) { - var sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); cmd.Dump(sb); throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), @@ -7563,15 +7649,15 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() where T : class { - var mapper = DynamicMapperCache.GetMapper(); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(); if (mapper == null) throw new InvalidOperationException("Type can't be mapped for unknown reason."); - using (var con = Database.Open()) - using (var cmd = con.CreateCommand()) + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) { - using (var rdr = cmd + using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) while (rdr.Read()) @@ -7586,7 +7672,7 @@ namespace DynamORM } catch (ArgumentException argex) { - var sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); cmd.Dump(sb); throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), @@ -7602,9 +7688,9 @@ namespace DynamORM /// Action containing reader. public virtual void ExecuteDataReader(Action reader) { - using (var con = Database.Open()) - using (var cmd = con.CreateCommand()) - using (var rdr = cmd + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) + using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) reader(rdr); @@ -7614,8 +7700,8 @@ namespace DynamORM /// Result of a query. public virtual object Scalar() { - using (var con = Database.Open()) - using (var cmd = con.CreateCommand()) + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) { return cmd .SetCommand(this) @@ -7623,6 +7709,25 @@ namespace DynamORM } } +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + + /// Returns a single result. + /// Type to parse to. + /// Default value. + /// Result of a query. + public virtual T ScalarAs(T defaultValue = default(T)) + { + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) + { + return cmd + .SetCommand(this) + .ExecuteScalarAs(defaultValue); + } + } + +#endif + #endregion Execution #region From/Join @@ -7644,7 +7749,7 @@ namespace DynamORM throw new ArgumentNullException("Array of functions cannot be or contain null."); int index = FromFunc(-1, fn); - foreach (var f in func) + foreach (Func f in func) index = FromFunc(index, f); return this; @@ -7657,16 +7762,16 @@ namespace DynamORM index++; ITableInfo tableInfo = null; - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; // If the expression result is string. if (result is string) { - var node = (string)result; - var tuple = node.SplitSomethingAndAlias(); - var parts = tuple.Item1.Split('.'); + string node = (string)result; + Tuple tuple = node.SplitSomethingAndAlias(); + string[] parts = tuple.Item1.Split('.'); tableInfo = new TableInfo(Database, Database.StripName(parts.Last()).Validated("Table"), tuple.Item2.Validated("Alias", canbeNull: true), @@ -7678,7 +7783,7 @@ namespace DynamORM if (type.IsAnonymous()) throw new InvalidOperationException(string.Format("Cant assign anonymous type as a table ({0}). Parsing {1}", type.FullName, result)); - var mapper = DynamicMapperCache.GetMapper(type); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); if (mapper == null) throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}). Parsing {1}", type.FullName, result)); @@ -7688,7 +7793,7 @@ namespace DynamORM else if (result is DynamicParser.Node) { // Or if it resolves to a dynamic node - var node = (DynamicParser.Node)result; + DynamicParser.Node node = (DynamicParser.Node)result; string owner = null; string main = null; @@ -7748,14 +7853,14 @@ namespace DynamORM owner = string.Format("{0}", Parse(node, rawstr: true, pars: Parameters)); else { - var invoke = (DynamicParser.Node.Invoke)node; + DynamicParser.Node.Invoke invoke = (DynamicParser.Node.Invoke)node; if (invoke.Arguments.Length == 1 && invoke.Arguments[0] is Type) { type = (Type)invoke.Arguments[0]; if (type.IsAnonymous()) throw new InvalidOperationException(string.Format("Cant assign anonymous type as a table ({0}). Parsing {1}", type.FullName, result)); - var mapper = DynamicMapperCache.GetMapper(type); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); if (mapper == null) throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}). Parsing {1}", type.FullName, result)); @@ -7859,7 +7964,7 @@ namespace DynamORM int index = -1; - foreach (var f in func) + foreach (Func f in func) { index++; ITableInfo tableInfo = null; @@ -7867,9 +7972,9 @@ namespace DynamORM if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); string type = null; @@ -7882,7 +7987,7 @@ namespace DynamORM // If the expression resolves to a string... if (result is string) { - var node = (string)result; + string node = (string)result; int n = node.ToUpper().IndexOf("JOIN "); @@ -7903,8 +8008,8 @@ namespace DynamORM main = main.Substring(0, n).Trim(); } - var tuple = main.SplitSomethingAndAlias(); // In this case we split on the remaining 'main' - var parts = tuple.Item1.Split('.'); + Tuple tuple = main.SplitSomethingAndAlias(); // In this case we split on the remaining 'main' + string[] parts = tuple.Item1.Split('.'); main = Database.StripName(parts.Last()).Validated("Table"); owner = parts.Length == 2 ? Database.StripName(parts.First()).Validated("Owner", canbeNull: true) : null; alias = tuple.Item2.Validated("Alias", canbeNull: true); @@ -7912,7 +8017,7 @@ namespace DynamORM else if (result is DynamicParser.Node) { // Or if it resolves to a dynamic node... - var node = (DynamicParser.Node)result; + DynamicParser.Node node = (DynamicParser.Node)result; while (true) { // Support for the ON() virtual method... @@ -7981,7 +8086,7 @@ namespace DynamORM if (args != null && args.Length > 0) { avoid = args[0] is bool && !((bool)args[0]); - var proposedType = args.FirstOrDefault(a => a is string) as string; + string proposedType = args.FirstOrDefault(a => a is string) as string; if (!string.IsNullOrEmpty(proposedType)) type = proposedType; } @@ -8026,11 +8131,11 @@ namespace DynamORM owner = string.Format("{0}", Parse(node, rawstr: true, pars: justAddTables ? null : Parameters)); else { - var invoke = (DynamicParser.Node.Invoke)node; + DynamicParser.Node.Invoke invoke = (DynamicParser.Node.Invoke)node; if (invoke.Arguments.Length == 1 && invoke.Arguments[0] is Type) { tableType = (Type)invoke.Arguments[0]; - var mapper = DynamicMapperCache.GetMapper(tableType); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(tableType); if (mapper == null) throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", tableType.FullName)); @@ -8183,7 +8288,7 @@ namespace DynamORM int index = SelectFunc(-1, fn); if (func != null) - foreach (var f in func) + foreach (Func f in func) index = SelectFunc(index, f); return this; @@ -8195,9 +8300,9 @@ namespace DynamORM if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); @@ -8209,8 +8314,8 @@ namespace DynamORM // If the expression resolves to a string... if (result is string) { - var node = (string)result; - var tuple = node.SplitSomethingAndAlias(); + string node = (string)result; + Tuple tuple = node.SplitSomethingAndAlias(); main = tuple.Item1.Validated("Table and/or Column"); main = FixObjectName(main); @@ -8226,12 +8331,12 @@ namespace DynamORM { anon = true; - foreach (var prop in result.ToDictionary()) + foreach (KeyValuePair prop in result.ToDictionary()) { if (prop.Value is string) { - var node = (string)prop.Value; - var tuple = node.SplitSomethingAndAlias(); + string node = (string)prop.Value; + Tuple tuple = node.SplitSomethingAndAlias(); main = FixObjectName(tuple.Item1.Validated("Table and/or Column")); ////alias = tuple.Item2.Validated("Alias", canbeNull: true); @@ -8269,7 +8374,7 @@ namespace DynamORM /// Builder instance. public virtual IDynamicSelectQueryBuilder SelectColumn(params DynamicColumn[] columns) { - foreach (var col in columns) + foreach (DynamicColumn col in columns) Select(x => col.ToSQLSelectColumn(Database)); return this; @@ -8282,7 +8387,7 @@ namespace DynamORM /// Builder instance. public virtual IDynamicSelectQueryBuilder SelectColumn(params string[] columns) { - var cols = new DynamicColumn[columns.Length]; + DynamicColumn[] cols = new DynamicColumn[columns.Length]; for (int i = 0; i < columns.Length; i++) cols[i] = DynamicColumn.ParseSelectColumn(columns[i]); @@ -8309,7 +8414,7 @@ namespace DynamORM if (func != null) for (int i = 0; i < func.Length; i++) { - var f = func[i]; + Func f = func[i]; index = GroupByFunc(index, f); } @@ -8321,9 +8426,9 @@ namespace DynamORM index++; if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); @@ -8351,7 +8456,7 @@ namespace DynamORM { for (int i = 0; i < columns.Length; i++) { - var col = columns[i]; + DynamicColumn col = columns[i]; GroupBy(x => col.ToSQLGroupByColumn(Database)); } @@ -8391,7 +8496,7 @@ namespace DynamORM if (func != null) for (int i = 0; i < func.Length; i++) { - var f = func[i]; + Func f = func[i]; index = OrderByFunc(index, f); } @@ -8404,9 +8509,9 @@ namespace DynamORM if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); string main = null; @@ -8416,7 +8521,7 @@ namespace DynamORM main = result.ToString(); else if (result is string) { - var parts = ((string)result).Split(' '); + string[] parts = ((string)result).Split(' '); main = Database.StripName(parts.First()); int colNo; @@ -8430,8 +8535,8 @@ namespace DynamORM // Intercepting trailing 'Ascending' or 'Descending' virtual methods... if (result is DynamicParser.Node.Method) { - var node = (DynamicParser.Node.Method)result; - var name = node.Name.ToUpper(); + DynamicParser.Node.Method node = (DynamicParser.Node.Method)result; + string name = node.Name.ToUpper(); if (name == "ASCENDING" || name == "ASC" || name == "DESCENDING" || name == "DESC") { object[] args = node.Arguments; @@ -8486,7 +8591,7 @@ namespace DynamORM { for (int i = 0; i < columns.Length; i++) { - var col = columns[i]; + DynamicColumn col = columns[i]; OrderBy(x => col.ToSQLOrderByColumn(Database)); } @@ -8576,7 +8681,7 @@ namespace DynamORM { string main = null; - var node = (DynamicParser.Node)result; + DynamicParser.Node node = (DynamicParser.Node)result; while (true) { // Support for the AS() virtual method... @@ -8634,7 +8739,7 @@ namespace DynamORM node = node.Host; // Get table/alias name - var table = ((DynamicParser.Node.GetMember)node).Name; + string table = ((DynamicParser.Node.GetMember)node).Name; bool isAlias = node.Host is DynamicParser.Node.Argument && IsTableAlias(table); if (isAlias) @@ -8651,7 +8756,7 @@ namespace DynamORM } else if (node.Host is DynamicParser.Node.Argument) { - var table = ((DynamicParser.Node.Argument)node.Host).Name; + string table = ((DynamicParser.Node.Argument)node.Host).Name; if (IsTableAlias(table)) main = string.Format("{0}.{1}", table, Database.DecorateName(main)); diff --git a/DynamORM.Tests/Select/ParserTests.cs b/DynamORM.Tests/Select/ParserTests.cs index ccfc856..9f59eac 100644 --- a/DynamORM.Tests/Select/ParserTests.cs +++ b/DynamORM.Tests/Select/ParserTests.cs @@ -54,8 +54,12 @@ namespace DynamORM.Tests.Select [TestFixtureTearDown] public virtual void TearDown() { - DestroyDynamicDatabase(); - DestroyTestDatabase(); + try + { + DestroyDynamicDatabase(); + DestroyTestDatabase(); + } + catch { } } /// @@ -688,6 +692,37 @@ namespace DynamORM.Tests.Select cmd.Parameters.Keys.ToArray()[0]), cmd.CommandText()); } + /// + /// Tests select escaped case. + /// + [Test] + public void TestCoalesce() + { + IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database); + + cmd.From(u => u.dbo.Users.As(u.c)) + .Select(u => u.Coalesce(u.c.ServerHash, new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }).As(u.Hash)); + + Assert.AreEqual(string.Format("SELECT Coalesce(c.\"ServerHash\", [${0}]) AS \"Hash\" FROM \"dbo\".\"Users\" AS c", + cmd.Parameters.Keys.ToArray()[0]), cmd.CommandText()); + } + + /// + /// Tests select escaped case. + /// + [Test] + public void TestCoalesceInWhere() + { + IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database); + + cmd.From(u => u.dbo.Users.As(u.c)) + .Select(u => u.ServerHash.As(u.Hash)) + .Where(u => u.Coalesce(u.c.ServerHash, new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }) == new byte[16] { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }); + + Assert.AreEqual(string.Format("SELECT \"ServerHash\" AS \"Hash\" FROM \"dbo\".\"Users\" AS c WHERE (Coalesce(c.\"ServerHash\", [${0}]) = [${1}])", + cmd.Parameters.Keys.ToArray()[0], cmd.Parameters.Keys.ToArray()[1]), cmd.CommandText()); + } + /// /// Tests select escaped case with sub query. /// diff --git a/DynamORM/Builders/IDynamicSelectQueryBuilder.cs b/DynamORM/Builders/IDynamicSelectQueryBuilder.cs index 3381c3b..9b3fd29 100644 --- a/DynamORM/Builders/IDynamicSelectQueryBuilder.cs +++ b/DynamORM/Builders/IDynamicSelectQueryBuilder.cs @@ -53,6 +53,16 @@ namespace DynamORM.Builders /// Result of a query. object Scalar(); +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + + /// Returns a single result. + /// Type to parse to. + /// Default value. + /// Result of a query. + T ScalarAs(T defaultValue = default(T)); + +#endif + #region From/Join /// diff --git a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs index 12eb8d5..f5991e3 100644 --- a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs @@ -146,9 +146,9 @@ namespace DynamORM.Builders.Implementation /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() { - using (var con = Database.Open()) - using (var cmd = con.CreateCommand()) - using (var rdr = cmd + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) + using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) while (rdr.Read()) @@ -163,7 +163,7 @@ namespace DynamORM.Builders.Implementation } catch (ArgumentException argex) { - var sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); cmd.Dump(sb); throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), @@ -179,15 +179,15 @@ namespace DynamORM.Builders.Implementation /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() where T : class { - var mapper = DynamicMapperCache.GetMapper(); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(); if (mapper == null) throw new InvalidOperationException("Type can't be mapped for unknown reason."); - using (var con = Database.Open()) - using (var cmd = con.CreateCommand()) + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) { - using (var rdr = cmd + using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) while (rdr.Read()) @@ -202,7 +202,7 @@ namespace DynamORM.Builders.Implementation } catch (ArgumentException argex) { - var sb = new StringBuilder(); + StringBuilder sb = new StringBuilder(); cmd.Dump(sb); throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), @@ -218,9 +218,9 @@ namespace DynamORM.Builders.Implementation /// Action containing reader. public virtual void ExecuteDataReader(Action reader) { - using (var con = Database.Open()) - using (var cmd = con.CreateCommand()) - using (var rdr = cmd + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) + using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) reader(rdr); @@ -230,8 +230,8 @@ namespace DynamORM.Builders.Implementation /// Result of a query. public virtual object Scalar() { - using (var con = Database.Open()) - using (var cmd = con.CreateCommand()) + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) { return cmd .SetCommand(this) @@ -239,6 +239,25 @@ namespace DynamORM.Builders.Implementation } } +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + + /// Returns a single result. + /// Type to parse to. + /// Default value. + /// Result of a query. + public virtual T ScalarAs(T defaultValue = default(T)) + { + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) + { + return cmd + .SetCommand(this) + .ExecuteScalarAs(defaultValue); + } + } + +#endif + #endregion Execution #region From/Join @@ -260,7 +279,7 @@ namespace DynamORM.Builders.Implementation throw new ArgumentNullException("Array of functions cannot be or contain null."); int index = FromFunc(-1, fn); - foreach (var f in func) + foreach (Func f in func) index = FromFunc(index, f); return this; @@ -273,16 +292,16 @@ namespace DynamORM.Builders.Implementation index++; ITableInfo tableInfo = null; - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; // If the expression result is string. if (result is string) { - var node = (string)result; - var tuple = node.SplitSomethingAndAlias(); - var parts = tuple.Item1.Split('.'); + string node = (string)result; + Tuple tuple = node.SplitSomethingAndAlias(); + string[] parts = tuple.Item1.Split('.'); tableInfo = new TableInfo(Database, Database.StripName(parts.Last()).Validated("Table"), tuple.Item2.Validated("Alias", canbeNull: true), @@ -294,7 +313,7 @@ namespace DynamORM.Builders.Implementation if (type.IsAnonymous()) throw new InvalidOperationException(string.Format("Cant assign anonymous type as a table ({0}). Parsing {1}", type.FullName, result)); - var mapper = DynamicMapperCache.GetMapper(type); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); if (mapper == null) throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}). Parsing {1}", type.FullName, result)); @@ -304,7 +323,7 @@ namespace DynamORM.Builders.Implementation else if (result is DynamicParser.Node) { // Or if it resolves to a dynamic node - var node = (DynamicParser.Node)result; + DynamicParser.Node node = (DynamicParser.Node)result; string owner = null; string main = null; @@ -364,14 +383,14 @@ namespace DynamORM.Builders.Implementation owner = string.Format("{0}", Parse(node, rawstr: true, pars: Parameters)); else { - var invoke = (DynamicParser.Node.Invoke)node; + DynamicParser.Node.Invoke invoke = (DynamicParser.Node.Invoke)node; if (invoke.Arguments.Length == 1 && invoke.Arguments[0] is Type) { type = (Type)invoke.Arguments[0]; if (type.IsAnonymous()) throw new InvalidOperationException(string.Format("Cant assign anonymous type as a table ({0}). Parsing {1}", type.FullName, result)); - var mapper = DynamicMapperCache.GetMapper(type); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(type); if (mapper == null) throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}). Parsing {1}", type.FullName, result)); @@ -475,7 +494,7 @@ namespace DynamORM.Builders.Implementation int index = -1; - foreach (var f in func) + foreach (Func f in func) { index++; ITableInfo tableInfo = null; @@ -483,9 +502,9 @@ namespace DynamORM.Builders.Implementation if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); string type = null; @@ -498,7 +517,7 @@ namespace DynamORM.Builders.Implementation // If the expression resolves to a string... if (result is string) { - var node = (string)result; + string node = (string)result; int n = node.ToUpper().IndexOf("JOIN "); @@ -519,8 +538,8 @@ namespace DynamORM.Builders.Implementation main = main.Substring(0, n).Trim(); } - var tuple = main.SplitSomethingAndAlias(); // In this case we split on the remaining 'main' - var parts = tuple.Item1.Split('.'); + Tuple tuple = main.SplitSomethingAndAlias(); // In this case we split on the remaining 'main' + string[] parts = tuple.Item1.Split('.'); main = Database.StripName(parts.Last()).Validated("Table"); owner = parts.Length == 2 ? Database.StripName(parts.First()).Validated("Owner", canbeNull: true) : null; alias = tuple.Item2.Validated("Alias", canbeNull: true); @@ -528,7 +547,7 @@ namespace DynamORM.Builders.Implementation else if (result is DynamicParser.Node) { // Or if it resolves to a dynamic node... - var node = (DynamicParser.Node)result; + DynamicParser.Node node = (DynamicParser.Node)result; while (true) { // Support for the ON() virtual method... @@ -597,7 +616,7 @@ namespace DynamORM.Builders.Implementation if (args != null && args.Length > 0) { avoid = args[0] is bool && !((bool)args[0]); - var proposedType = args.FirstOrDefault(a => a is string) as string; + string proposedType = args.FirstOrDefault(a => a is string) as string; if (!string.IsNullOrEmpty(proposedType)) type = proposedType; } @@ -642,11 +661,11 @@ namespace DynamORM.Builders.Implementation owner = string.Format("{0}", Parse(node, rawstr: true, pars: justAddTables ? null : Parameters)); else { - var invoke = (DynamicParser.Node.Invoke)node; + DynamicParser.Node.Invoke invoke = (DynamicParser.Node.Invoke)node; if (invoke.Arguments.Length == 1 && invoke.Arguments[0] is Type) { tableType = (Type)invoke.Arguments[0]; - var mapper = DynamicMapperCache.GetMapper(tableType); + DynamicTypeMap mapper = DynamicMapperCache.GetMapper(tableType); if (mapper == null) throw new InvalidOperationException(string.Format("Cant assign unmapable type as a table ({0}).", tableType.FullName)); @@ -799,7 +818,7 @@ namespace DynamORM.Builders.Implementation int index = SelectFunc(-1, fn); if (func != null) - foreach (var f in func) + foreach (Func f in func) index = SelectFunc(index, f); return this; @@ -811,9 +830,9 @@ namespace DynamORM.Builders.Implementation if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); @@ -825,8 +844,8 @@ namespace DynamORM.Builders.Implementation // If the expression resolves to a string... if (result is string) { - var node = (string)result; - var tuple = node.SplitSomethingAndAlias(); + string node = (string)result; + Tuple tuple = node.SplitSomethingAndAlias(); main = tuple.Item1.Validated("Table and/or Column"); main = FixObjectName(main); @@ -842,12 +861,12 @@ namespace DynamORM.Builders.Implementation { anon = true; - foreach (var prop in result.ToDictionary()) + foreach (KeyValuePair prop in result.ToDictionary()) { if (prop.Value is string) { - var node = (string)prop.Value; - var tuple = node.SplitSomethingAndAlias(); + string node = (string)prop.Value; + Tuple tuple = node.SplitSomethingAndAlias(); main = FixObjectName(tuple.Item1.Validated("Table and/or Column")); ////alias = tuple.Item2.Validated("Alias", canbeNull: true); @@ -885,7 +904,7 @@ namespace DynamORM.Builders.Implementation /// Builder instance. public virtual IDynamicSelectQueryBuilder SelectColumn(params DynamicColumn[] columns) { - foreach (var col in columns) + foreach (DynamicColumn col in columns) Select(x => col.ToSQLSelectColumn(Database)); return this; @@ -898,7 +917,7 @@ namespace DynamORM.Builders.Implementation /// Builder instance. public virtual IDynamicSelectQueryBuilder SelectColumn(params string[] columns) { - var cols = new DynamicColumn[columns.Length]; + DynamicColumn[] cols = new DynamicColumn[columns.Length]; for (int i = 0; i < columns.Length; i++) cols[i] = DynamicColumn.ParseSelectColumn(columns[i]); @@ -925,7 +944,7 @@ namespace DynamORM.Builders.Implementation if (func != null) for (int i = 0; i < func.Length; i++) { - var f = func[i]; + Func f = func[i]; index = GroupByFunc(index, f); } @@ -937,9 +956,9 @@ namespace DynamORM.Builders.Implementation index++; if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); @@ -967,7 +986,7 @@ namespace DynamORM.Builders.Implementation { for (int i = 0; i < columns.Length; i++) { - var col = columns[i]; + DynamicColumn col = columns[i]; GroupBy(x => col.ToSQLGroupByColumn(Database)); } @@ -1007,7 +1026,7 @@ namespace DynamORM.Builders.Implementation if (func != null) for (int i = 0; i < func.Length; i++) { - var f = func[i]; + Func f = func[i]; index = OrderByFunc(index, f); } @@ -1020,9 +1039,9 @@ namespace DynamORM.Builders.Implementation if (f == null) throw new ArgumentNullException(string.Format("Specification #{0} cannot be null.", index)); - using (var parser = DynamicParser.Parse(f)) + using (DynamicParser parser = DynamicParser.Parse(f)) { - var result = parser.Result; + object result = parser.Result; if (result == null) throw new ArgumentException(string.Format("Specification #{0} resolves to null.", index)); string main = null; @@ -1032,7 +1051,7 @@ namespace DynamORM.Builders.Implementation main = result.ToString(); else if (result is string) { - var parts = ((string)result).Split(' '); + string[] parts = ((string)result).Split(' '); main = Database.StripName(parts.First()); int colNo; @@ -1046,8 +1065,8 @@ namespace DynamORM.Builders.Implementation // Intercepting trailing 'Ascending' or 'Descending' virtual methods... if (result is DynamicParser.Node.Method) { - var node = (DynamicParser.Node.Method)result; - var name = node.Name.ToUpper(); + DynamicParser.Node.Method node = (DynamicParser.Node.Method)result; + string name = node.Name.ToUpper(); if (name == "ASCENDING" || name == "ASC" || name == "DESCENDING" || name == "DESC") { object[] args = node.Arguments; @@ -1102,7 +1121,7 @@ namespace DynamORM.Builders.Implementation { for (int i = 0; i < columns.Length; i++) { - var col = columns[i]; + DynamicColumn col = columns[i]; OrderBy(x => col.ToSQLOrderByColumn(Database)); } @@ -1192,7 +1211,7 @@ namespace DynamORM.Builders.Implementation { string main = null; - var node = (DynamicParser.Node)result; + DynamicParser.Node node = (DynamicParser.Node)result; while (true) { // Support for the AS() virtual method... @@ -1250,7 +1269,7 @@ namespace DynamORM.Builders.Implementation node = node.Host; // Get table/alias name - var table = ((DynamicParser.Node.GetMember)node).Name; + string table = ((DynamicParser.Node.GetMember)node).Name; bool isAlias = node.Host is DynamicParser.Node.Argument && IsTableAlias(table); if (isAlias) @@ -1267,7 +1286,7 @@ namespace DynamORM.Builders.Implementation } else if (node.Host is DynamicParser.Node.Argument) { - var table = ((DynamicParser.Node.Argument)node.Host).Name; + string table = ((DynamicParser.Node.Argument)node.Host).Name; if (IsTableAlias(table)) main = string.Format("{0}.{1}", table, Database.DecorateName(main)); diff --git a/DynamORM/DynamicDatabase.cs b/DynamORM/DynamicDatabase.cs index 751f14f..73ea4bb 100644 --- a/DynamORM/DynamicDatabase.cs +++ b/DynamORM/DynamicDatabase.cs @@ -1044,6 +1044,44 @@ namespace DynamORM } } +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + + /// Returns a single result. + /// What kind of result is expected. + /// SQL query containing numbered parameters in format provided by + /// methods. Also names should be formatted with + /// method. + /// Arguments (parameters). + /// Result of a query. + public virtual T ScalarAs(string sql, params object[] args) + { + using (var con = Open()) + using (var cmd = con.CreateCommand()) + { + return cmd + .SetCommand(sql).AddParameters(this, args) + .ExecuteScalarAs(); + } + } + + /// Returns a single result. + /// What kind of result is expected. + /// Command builder. + /// Default value. + /// Result of a query. + public virtual T ScalarAs(IDynamicQueryBuilder builder, T defaultValue = default(T)) + { + using (var con = Open()) + using (var cmd = con.CreateCommand()) + { + return cmd + .SetCommand(builder) + .ExecuteScalarAs(defaultValue); + } + } + +#endif + #endregion Scalar #region Query diff --git a/DynamORM/DynamicExtensions.cs b/DynamORM/DynamicExtensions.cs index 357096d..86a44fa 100644 --- a/DynamORM/DynamicExtensions.cs +++ b/DynamORM/DynamicExtensions.cs @@ -662,28 +662,40 @@ namespace DynamORM return (T)o; else if (o != DBNull.Value && o != null) { - var method = typeof(T).GetMethod( - "TryParse", - new[] - { - typeof(string), - Type.GetType(string.Format("{0}&", typeof(T).FullName)) - }); - if (handler != null) ret = o.ToString().TryParseDefault(defaultValue, handler); - else if (method != null) - ret = o.ToString().TryParseDefault(defaultValue, delegate(string v, out T r) - { - r = defaultValue; - return (bool)method.Invoke(null, new object[] { v, r }); - }); + else if (o is IConvertible && typeof(T).GetInterfaces().Any(i => i == typeof(IConvertible))) + ret = (T)Convert.ChangeType(o, typeof(T)); + else if (typeof(T) == typeof(Guid)) + { + if (o.GetType() == typeof(byte[])) + ret = (T)(object)new Guid((byte[])o); + else + ret = (T)(object)Guid.Parse(o.ToString()); + } else if (typeof(T) == typeof(string)) ret = (T)(o.ToString() as object); else if (typeof(T) == typeof(object)) ret = (T)o; else - throw new InvalidOperationException("Provided type can't be parsed using generic approach."); + { + var method = typeof(T).GetMethod( + "TryParse", + new Type[] + { + typeof(string), + Type.GetType(string.Format("{0}&", typeof(T).FullName)) + }); + + if (method != null) + ret = o.ToString().TryParseDefault(defaultValue, delegate(string v, out T r) + { + r = defaultValue; + return (bool)method.Invoke(null, new object[] { v, r }); + }); + else + throw new InvalidOperationException("Provided type can't be parsed using generic approach."); + } } return ret; diff --git a/DynamORM/DynamicTable.cs b/DynamORM/DynamicTable.cs index afcc320..6726ab3 100644 --- a/DynamORM/DynamicTable.cs +++ b/DynamORM/DynamicTable.cs @@ -389,6 +389,32 @@ namespace DynamORM return Database.Scalar(builder); } +#if !DYNAMORM_OMMIT_GENERICEXECUTION && !DYNAMORM_OMMIT_TRYPARSE + + /// Returns a single result. + /// What kind of result is expected. + /// SQL query containing numbered parameters in format provided by + /// methods. Also names should be formatted with + /// method. + /// Arguments (parameters). + /// Result of a query. + public virtual T ScalarAs(string sql, params object[] args) + { + return Database.ScalarAs(sql, args); + } + + /// Returns a single result. + /// What kind of result is expected. + /// Command builder. + /// Default value. + /// Result of a query. + public virtual T ScalarAs(IDynamicQueryBuilder builder, T defaultValue = default(T)) + { + return Database.ScalarAs(builder, defaultValue); + } + +#endif + /// Execute stored procedure. /// Name of stored procedure to execute. /// Number of affected rows.