diff --git a/AmalgamationTool/DynamORM.Amalgamation.cs b/AmalgamationTool/DynamORM.Amalgamation.cs index 3915a0c..b4d33f3 100644 --- a/AmalgamationTool/DynamORM.Amalgamation.cs +++ b/AmalgamationTool/DynamORM.Amalgamation.cs @@ -96,6 +96,95 @@ namespace DynamORM #region Helpers + /// Create data reader from dynamic enumerable. + /// List of objects. + /// Instance of containing objects data. + public static DynamicCachedReader FromDynamicEnumerable(IEnumerable objects) + { + var first = (objects as IEnumerable).FirstOrDefault(); + + if (first == null) + return null; + + var firstDict = first as IDictionary; + var r = new DynamicCachedReader(); + r.Init(firstDict.Keys.Count); + + for (int i = 0; i < firstDict.Keys.Count; i++) + r._types.Add(null); + + foreach (dynamic elem in (objects as IEnumerable)) + { + int c = 0; + var dict = elem as IDictionary; + + foreach (var k in firstDict.Keys) + { + object val = dict[k]; + + r._cache.Add(val); + + if (r._types[c] == null && val != null) + r._types[c] = val.GetType(); + + c++; + } + + r._rows++; + } + + for (int i = 0; i < firstDict.Keys.Count; i++) + if (r._types[i] == null) + r._types[i] = typeof(string); + + r._schema = new DataTable("DYNAMIC"); + r._schema.Columns.Add(new DataColumn("ColumnName", typeof(string))); + r._schema.Columns.Add(new DataColumn("ColumnOrdinal", typeof(int))); + r._schema.Columns.Add(new DataColumn("ColumnSize", typeof(int))); + r._schema.Columns.Add(new DataColumn("NumericPrecision", typeof(short))); + r._schema.Columns.Add(new DataColumn("NumericScale", typeof(short))); + r._schema.Columns.Add(new DataColumn("DataType", typeof(Type))); + r._schema.Columns.Add(new DataColumn("ProviderType", typeof(int))); + r._schema.Columns.Add(new DataColumn("NativeType", typeof(int))); + r._schema.Columns.Add(new DataColumn("AllowDBNull", typeof(bool))); + r._schema.Columns.Add(new DataColumn("IsUnique", typeof(bool))); + r._schema.Columns.Add(new DataColumn("IsKey", typeof(bool))); + r._schema.Columns.Add(new DataColumn("IsAutoIncrement", typeof(bool))); + + int ordinal = 0; + DataRow dr = null; + + foreach (var column in firstDict.Keys) + { + dr = r._schema.NewRow(); + + dr[0] = column; + dr[1] = ordinal; + dr[2] = 0; + dr[3] = 0; + dr[4] = 0; + dr[5] = r._types[ordinal]; + dr[6] = r._types[ordinal].ToDbType(); + dr[7] = r._types[ordinal].ToDbType(); + dr[8] = true; + dr[9] = false; + dr[10] = false; + dr[11] = false; + + r._schema.Rows.Add(dr); + + r._names.Add(dr[0].ToString()); + r._ordinals.Add(dr[0].ToString().ToUpper(), ordinal++); + r._types.Add((Type)dr[5]); + + dr.AcceptChanges(); + } + + dr.AcceptChanges(); + + return r; + } + /// Create data reader from enumerable. /// Type of enumerated objects. /// List of objects. @@ -2773,6 +2862,44 @@ namespace DynamORM #endregion Query + #region CachedQuery + + /// Enumerate the reader and yield the result. + /// SQL query containing numbered parameters in format provided by + /// methods. Also names should be formatted with + /// method. + /// Arguments (parameters). + /// Enumerator of objects expanded from query. + public virtual DynamicCachedReader CachedQuery(string sql, params object[] args) + { + using (IDbConnection con = Open()) + using (IDbCommand cmd = con.CreateCommand()) + { + using (IDataReader rdr = cmd + .SetCommand(sql) + .AddParameters(this, args) + .ExecuteReader()) + return new DynamicCachedReader(rdr); + } + } + + /// Enumerate the reader and yield the result. + /// Command builder. + /// Enumerator of objects expanded from query. + public virtual DynamicCachedReader CachedQuery(IDynamicQueryBuilder builder) + { + using (IDbConnection con = Open()) + using (IDbCommand cmd = con.CreateCommand()) + { + using (IDataReader rdr = cmd + .SetCommand(builder) + .ExecuteReader()) + return new DynamicCachedReader(rdr); + } + } + + #endregion Query + #region Schema /// Builds query cache if necessary and returns it. @@ -10855,6 +10982,45 @@ namespace DynamORM } } + /// Extensions for data reader handling. + public static class DataReaderExtensions + { + /// Gets the data table from data reader. + /// The data reader. + /// The name to give the table. If tableName is null or an empty string, a default name is given when added to the System.Data.DataTableCollection. + /// The namespace for the XML representation of the data stored in the DataTable. + /// + public static DataTable GetDataTableFromDataReader(this IDataReader r, string name = null, string nameSpace = null) + { + DataTable schemaTable = r.GetSchemaTable(); + DataTable resultTable = new DataTable(name, nameSpace); + + foreach (DataRow col in schemaTable.Rows) + { + dynamic c = col.RowToDynamicUpper(); + + DataColumn dataColumn = new DataColumn(); + dataColumn.ColumnName = c.COLUMNNAME; + dataColumn.DataType = (Type)c.DATATYPE; + dataColumn.ReadOnly = true; + dataColumn.Unique = c.ISUNIQUE; + + resultTable.Columns.Add(dataColumn); + } + + while (r.Read()) + { + DataRow row = resultTable.NewRow(); + for (int i = 0; i < resultTable.Columns.Count - 1; i++) + row[i] = r[i]; + + resultTable.Rows.Add(row); + } + + return resultTable; + } + } + /// Framework detection and specific implementations. public static class FrameworkTools { diff --git a/DynamORM/DynamORM.csproj b/DynamORM/DynamORM.csproj index 0aab04a..189cbda 100644 --- a/DynamORM/DynamORM.csproj +++ b/DynamORM/DynamORM.csproj @@ -3,10 +3,10 @@ netstandard2.0;net472;net5.0;net6.0 Dynamic Object-Relational Mapping library. - Copyright © RUSSEK Software 2012-2022 + Copyright © RUSSEK Software 2012-2023 RUSSEK Software Grzegorz Russek - 1.2.4 + 1.2.5 https://svn.dr4cul4.pl/svn/DynamORM/ https://dr4cul4.pl DynamORM diff --git a/DynamORM/DynamicCachedReader.cs b/DynamORM/DynamicCachedReader.cs index 3099f68..d39bbbb 100644 --- a/DynamORM/DynamicCachedReader.cs +++ b/DynamORM/DynamicCachedReader.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Data; using System.Dynamic; using System.IO; +using System.Linq; using DynamORM.Helpers; using DynamORM.Mapper; @@ -43,6 +44,95 @@ namespace DynamORM #region Helpers + /// Create data reader from dynamic enumerable. + /// List of objects. + /// Instance of containing objects data. + public static DynamicCachedReader FromDynamicEnumerable(IEnumerable objects) + { + var first = (objects as IEnumerable).FirstOrDefault(); + + if (first == null) + return null; + + var firstDict = first as IDictionary; + var r = new DynamicCachedReader(); + r.Init(firstDict.Keys.Count); + + for (int i = 0; i < firstDict.Keys.Count; i++) + r._types.Add(null); + + foreach (dynamic elem in (objects as IEnumerable)) + { + int c = 0; + var dict = elem as IDictionary; + + foreach (var k in firstDict.Keys) + { + object val = dict[k]; + + r._cache.Add(val); + + if (r._types[c] == null && val != null) + r._types[c] = val.GetType(); + + c++; + } + + r._rows++; + } + + for (int i = 0; i < firstDict.Keys.Count; i++) + if (r._types[i] == null) + r._types[i] = typeof(string); + + r._schema = new DataTable("DYNAMIC"); + r._schema.Columns.Add(new DataColumn("ColumnName", typeof(string))); + r._schema.Columns.Add(new DataColumn("ColumnOrdinal", typeof(int))); + r._schema.Columns.Add(new DataColumn("ColumnSize", typeof(int))); + r._schema.Columns.Add(new DataColumn("NumericPrecision", typeof(short))); + r._schema.Columns.Add(new DataColumn("NumericScale", typeof(short))); + r._schema.Columns.Add(new DataColumn("DataType", typeof(Type))); + r._schema.Columns.Add(new DataColumn("ProviderType", typeof(int))); + r._schema.Columns.Add(new DataColumn("NativeType", typeof(int))); + r._schema.Columns.Add(new DataColumn("AllowDBNull", typeof(bool))); + r._schema.Columns.Add(new DataColumn("IsUnique", typeof(bool))); + r._schema.Columns.Add(new DataColumn("IsKey", typeof(bool))); + r._schema.Columns.Add(new DataColumn("IsAutoIncrement", typeof(bool))); + + int ordinal = 0; + DataRow dr = null; + + foreach (var column in firstDict.Keys) + { + dr = r._schema.NewRow(); + + dr[0] = column; + dr[1] = ordinal; + dr[2] = 0; + dr[3] = 0; + dr[4] = 0; + dr[5] = r._types[ordinal]; + dr[6] = r._types[ordinal].ToDbType(); + dr[7] = r._types[ordinal].ToDbType(); + dr[8] = true; + dr[9] = false; + dr[10] = false; + dr[11] = false; + + r._schema.Rows.Add(dr); + + r._names.Add(dr[0].ToString()); + r._ordinals.Add(dr[0].ToString().ToUpper(), ordinal++); + r._types.Add((Type)dr[5]); + + dr.AcceptChanges(); + } + + dr.AcceptChanges(); + + return r; + } + /// Create data reader from enumerable. /// Type of enumerated objects. /// List of objects. diff --git a/DynamORM/DynamicDatabase.cs b/DynamORM/DynamicDatabase.cs index 010fb85..639bc92 100644 --- a/DynamORM/DynamicDatabase.cs +++ b/DynamORM/DynamicDatabase.cs @@ -1310,6 +1310,44 @@ namespace DynamORM #endregion Query + #region CachedQuery + + /// Enumerate the reader and yield the result. + /// SQL query containing numbered parameters in format provided by + /// methods. Also names should be formatted with + /// method. + /// Arguments (parameters). + /// Enumerator of objects expanded from query. + public virtual DynamicCachedReader CachedQuery(string sql, params object[] args) + { + using (IDbConnection con = Open()) + using (IDbCommand cmd = con.CreateCommand()) + { + using (IDataReader rdr = cmd + .SetCommand(sql) + .AddParameters(this, args) + .ExecuteReader()) + return new DynamicCachedReader(rdr); + } + } + + /// Enumerate the reader and yield the result. + /// Command builder. + /// Enumerator of objects expanded from query. + public virtual DynamicCachedReader CachedQuery(IDynamicQueryBuilder builder) + { + using (IDbConnection con = Open()) + using (IDbCommand cmd = con.CreateCommand()) + { + using (IDataReader rdr = cmd + .SetCommand(builder) + .ExecuteReader()) + return new DynamicCachedReader(rdr); + } + } + + #endregion Query + #region Schema /// Builds query cache if necessary and returns it. diff --git a/DynamORM/Helpers/DataReaderExtensions.cs b/DynamORM/Helpers/DataReaderExtensions.cs new file mode 100644 index 0000000..dd8bd95 --- /dev/null +++ b/DynamORM/Helpers/DataReaderExtensions.cs @@ -0,0 +1,44 @@ +using System; +using System.Data; + +namespace DynamORM.Helpers +{ + /// Extensions for data reader handling. + public static class DataReaderExtensions + { + /// Gets the data table from data reader. + /// The data reader. + /// The name to give the table. If tableName is null or an empty string, a default name is given when added to the System.Data.DataTableCollection. + /// The namespace for the XML representation of the data stored in the DataTable. + /// + public static DataTable GetDataTableFromDataReader(this IDataReader r, string name = null, string nameSpace = null) + { + DataTable schemaTable = r.GetSchemaTable(); + DataTable resultTable = new DataTable(name, nameSpace); + + foreach (DataRow col in schemaTable.Rows) + { + dynamic c = col.RowToDynamicUpper(); + + DataColumn dataColumn = new DataColumn(); + dataColumn.ColumnName = c.COLUMNNAME; + dataColumn.DataType = (Type)c.DATATYPE; + dataColumn.ReadOnly = true; + dataColumn.Unique = c.ISUNIQUE; + + resultTable.Columns.Add(dataColumn); + } + + while (r.Read()) + { + DataRow row = resultTable.NewRow(); + for (int i = 0; i < resultTable.Columns.Count - 1; i++) + row[i] = r[i]; + + resultTable.Rows.Add(row); + } + + return resultTable; + } + } +}