From d8b6c8f4882a812061d4698a4e7ba8eedc15d59c Mon Sep 17 00:00:00 2001 From: "grzegorz.russek" Date: Thu, 29 Sep 2016 10:14:34 +0000 Subject: [PATCH] --- AmalgamationTool/DynamORM.Amalgamation.cs | 719 ++++++++++++++++-- DynamORM.Tests/Select/ParserTests.cs | 15 + .../Implementation/DynamicQueryBuilder.cs | 7 +- .../DynamicSelectQueryBuilder.cs | 73 +- DynamORM/DynamORM.csproj | 1 + DynamORM/DynamicDatabase.cs | 82 +- DynamORM/DynamicExtensions.cs | 45 +- DynamORM/DynamicProcedureInvoker.cs | 25 +- Tester/Program.cs | 206 +---- 9 files changed, 883 insertions(+), 290 deletions(-) diff --git a/AmalgamationTool/DynamORM.Amalgamation.cs b/AmalgamationTool/DynamORM.Amalgamation.cs index f7968c9..5878c32 100644 --- a/AmalgamationTool/DynamORM.Amalgamation.cs +++ b/AmalgamationTool/DynamORM.Amalgamation.cs @@ -60,6 +60,492 @@ using DynamORM.Mapper; namespace DynamORM { + /// Cache data reader in memory. + internal class DynamicCachedReader : DynamicObject, IDataReader + { + #region Constructor and Data + + private DataTable _schema; + private int _fields; + private int _rows; + private int _position; + private int _cachePos; + + private IList _names; + private IDictionary _ordinals; + private IList _types; + private IList _cache; + + private DynamicCachedReader() + { + } + + /// Initializes a new instance of the class. + /// Reader to cache. + public DynamicCachedReader(IDataReader reader) + { + InitDataReader(reader); + } + + #endregion Constructor and Data + + #region Helpers + + /// Create data reader from enumerable. + /// Type of enumerated objects. + /// List of objects. + /// Instance of containing objects data. + public static DynamicCachedReader FromEnumerable(IEnumerable objects) + { + var mapper = DynamicMapperCache.GetMapper(); + + if (mapper == null) + throw new InvalidCastException(string.Format("Object type '{0}' can't be mapped.", typeof(T).FullName)); + + var r = new DynamicCachedReader(); + r.Init(mapper.ColumnsMap.Count + 1); + r.CreateSchemaTable(mapper); + r.FillFromEnumerable(objects, mapper); + + return r; + } + + private void InitDataReader(IDataReader reader) + { + _schema = reader.GetSchemaTable(); + + Init(reader.FieldCount); + + int i = 0; + + for (i = 0; i < _fields; i++) + { + _names.Add(reader.GetName(i)); + _types.Add(reader.GetFieldType(i)); + + if (!_ordinals.ContainsKey(reader.GetName(i).ToUpper())) + _ordinals.Add(reader.GetName(i).ToUpper(), i); + } + + while (reader.Read()) + { + for (i = 0; i < _fields; i++) + _cache.Add(reader[i]); + + _rows++; + } + + IsClosed = false; + _position = -1; + _cachePos = -1; + + reader.Close(); + } + + private void FillFromEnumerable(IEnumerable objects, DynamicTypeMap mapper) + { + foreach (var elem in objects) + { + foreach (var col in mapper.ColumnsMap) + { + object val = null; + + if (col.Value.Get != null) + val = col.Value.Get(elem); + + _cache.Add(val); + } + + _cache.Add(elem); + + _rows++; + } + } + + private void CreateSchemaTable(DynamicTypeMap mapper) + { + _schema = new DataTable("DYNAMIC"); + _schema.Columns.Add(new DataColumn("ColumnName", typeof(string))); + _schema.Columns.Add(new DataColumn("ColumnOrdinal", typeof(int))); + _schema.Columns.Add(new DataColumn("ColumnSize", typeof(int))); + _schema.Columns.Add(new DataColumn("NumericPrecision", typeof(short))); + _schema.Columns.Add(new DataColumn("NumericScale", typeof(short))); + _schema.Columns.Add(new DataColumn("DataType", typeof(Type))); + _schema.Columns.Add(new DataColumn("ProviderType", typeof(int))); + _schema.Columns.Add(new DataColumn("NativeType", typeof(int))); + _schema.Columns.Add(new DataColumn("AllowDBNull", typeof(bool))); + _schema.Columns.Add(new DataColumn("IsUnique", typeof(bool))); + _schema.Columns.Add(new DataColumn("IsKey", typeof(bool))); + _schema.Columns.Add(new DataColumn("IsAutoIncrement", typeof(bool))); + + int ordinal = 0; + DataRow dr = null; + + foreach (var column in mapper.ColumnsMap) + { + dr = _schema.NewRow(); + + dr[0] = column.Value.Column.NullOr(x => x.Name ?? column.Value.Name, column.Value.Name); + dr[1] = ordinal; + dr[2] = column.Value.Column.NullOr(x => x.Size ?? int.MaxValue, int.MaxValue); + dr[3] = column.Value.Column.NullOr(x => x.Precision ?? 0, 0); + dr[4] = column.Value.Column.NullOr(x => x.Scale ?? 0, 0); + dr[5] = column.Value.Column.NullOr(x => x.Type.HasValue ? x.Type.Value.ToType() : column.Value.Type, column.Value.Type); + dr[6] = column.Value.Column.NullOr(x => x.Type ?? column.Value.Type.ToDbType(), column.Value.Type.ToDbType()); + dr[7] = column.Value.Column.NullOr(x => x.Type ?? column.Value.Type.ToDbType(), column.Value.Type.ToDbType()); + dr[8] = !column.Value.Column.NullOr(x => x.IsKey, false); + dr[9] = false; + dr[10] = column.Value.Column.NullOr(x => x.IsKey, false); + dr[11] = false; + + _schema.Rows.Add(dr); + + _names.Add(dr[0].ToString()); + _ordinals.Add(dr[0].ToString().ToUpper(), ordinal++); + _types.Add((Type)dr[5]); + + dr.AcceptChanges(); + } + + dr = _schema.NewRow(); + + dr[0] = "#O"; + dr[1] = ordinal; + dr[2] = int.MaxValue; + dr[3] = 0; + dr[4] = 0; + dr[5] = mapper.Type; + dr[6] = DbType.Object; + dr[7] = DbType.Object; + dr[8] = true; + dr[9] = false; + dr[10] = false; + dr[11] = false; + + _schema.Rows.Add(dr); + + _names.Add("#O"); + _ordinals.Add("#O".ToUpper(), ordinal++); + _types.Add(mapper.Type); + + dr.AcceptChanges(); + } + + private void Init(int fieldCount) + { + _rows = 0; + _fields = fieldCount; + _names = new List(_fields); + _ordinals = new Dictionary(_fields); + _types = new List(_fields); + _cache = new List(_fields * 100); + } + + #endregion Helpers + + #region IDataReader Members + + /// Closes the System.Data.IDataReader Object. + public void Close() + { + IsClosed = true; + _position = _rows; + _cachePos = -1; + } + + /// Gets a value indicating the depth of nesting for the current row. + /// This implementation use this field to indicate row count. + public int Depth + { + get { return _rows; } + } + + /// Returns a System.Data.DataTable that describes the column metadata of the + /// System.Data.IDataReader.A System.Data.DataTable that describes + /// the column metadata. + /// The System.Data.IDataReader is closed. + public DataTable GetSchemaTable() + { + return _schema; + } + + /// Gets a value indicating whether the data reader is closed. + public bool IsClosed { get; private set; } + + /// Advances the data reader to the next result, when reading the results of batch SQL statements. + /// Returns true if there are more rows; otherwise, false. + public bool NextResult() + { + _cachePos = (++_position) * _fields; + + return _position < _rows; + } + + /// Advances the System.Data.IDataReader to the next record. + /// Returns true if there are more rows; otherwise, false. + public bool Read() + { + _cachePos = (++_position) * _fields; + + return _position < _rows; + } + + /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement. + /// The number of rows changed, inserted, or deleted; 0 if no rows were affected or the statement + /// failed; and -1 for SELECT statements. + public int RecordsAffected { get { return 0; } } + + #endregion IDataReader Members + + #region IDisposable Members + + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. + public void Dispose() + { + _names.Clear(); + _types.Clear(); + _cache.Clear(); + _schema.Dispose(); + } + + #endregion IDisposable Members + + #region IDataRecord Members + + /// Gets the number of columns in the current row. + /// When not positioned in a valid record set, 0; otherwise, the number of columns in the current record. The default is -1. + public int FieldCount { get { return _fields; } } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public bool GetBoolean(int i) + { + return (bool)_cache[_cachePos + i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public byte GetByte(int i) + { + return (byte)_cache[_cachePos + i]; + } + + /// Reads a stream of bytes from the specified column offset into the buffer + /// as an array, starting at the given buffer offset. + /// The index of the field to find. + /// The index within the field from which to start the read operation. + /// The buffer into which to read the stream of bytes. + /// The index for buffer to start the read operation. + /// The number of bytes to read. + /// The actual number of bytes read. + public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) + { + using (MemoryStream ms = new MemoryStream((byte[])_cache[_cachePos + i])) + return ms.Read(buffer, bufferoffset, length); + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public char GetChar(int i) + { + return (char)_cache[_cachePos + i]; + } + + /// Reads a stream of characters from the specified column offset into the buffer + /// as an array, starting at the given buffer offset. + /// The zero-based column ordinal. + /// The index within the row from which to start the read operation. + /// The buffer into which to read the stream of bytes. + /// The index for buffer to start the read operation. + /// The number of bytes to read. + /// The actual number of characters read. + public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) + { + using (MemoryStream ms = new MemoryStream((byte[])_cache[_cachePos + i])) + { + byte[] buff = new byte[buffer.Length]; + long ret = ms.Read(buff, bufferoffset, length); + + for (int n = bufferoffset; n < ret; n++) + buffer[n] = (char)buff[n]; + + return ret; + } + } + + /// Returns an System.Data.IDataReader for the specified column ordinal. + /// The index of the field to find. + /// An System.Data.IDataReader. + public IDataReader GetData(int i) + { + return null; + } + + /// Gets the data type information for the specified field. + /// The index of the field to find. + /// The data type information for the specified field. + public string GetDataTypeName(int i) + { + return _types[i].Name; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public DateTime GetDateTime(int i) + { + return (DateTime)_cache[_cachePos + i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public decimal GetDecimal(int i) + { + return (decimal)_cache[_cachePos + i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public double GetDouble(int i) + { + return (double)_cache[_cachePos + i]; + } + + /// Gets the System.Type information corresponding to the type of System.Object + /// that would be returned from System.Data.IDataRecord.GetValue(System.Int32). + /// The index of the field to find. + /// The System.Type information corresponding to the type of System.Object that + /// would be returned from System.Data.IDataRecord.GetValue(System.Int32). + public Type GetFieldType(int i) + { + return _types[i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public float GetFloat(int i) + { + return (float)_cache[_cachePos + i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public Guid GetGuid(int i) + { + return (Guid)_cache[_cachePos + i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public short GetInt16(int i) + { + return (short)_cache[_cachePos + i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public int GetInt32(int i) + { + return (int)_cache[_cachePos + i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public long GetInt64(int i) + { + return (long)_cache[_cachePos + i]; + } + + /// Gets the name for the field to find. + /// The index of the field to find. + /// The name of the field or the empty string (""), if there is no value to return. + public string GetName(int i) + { + return _names[i]; + } + + /// Return the index of the named field. + /// The name of the field to find. + /// The index of the named field. + public int GetOrdinal(string name) + { + if (_ordinals.ContainsKey(name.ToUpper())) + return _ordinals[name.ToUpper()]; + + return -1; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public string GetString(int i) + { + return (string)_cache[_cachePos + i]; + } + + /// Return the value of the specified field. + /// The index of the field to find. + /// Field value upon return. + public object GetValue(int i) + { + return _cache[_cachePos + i]; + } + + /// Gets all the attribute fields in the collection for the current record. + /// An array of System.Object to copy the attribute fields into. + /// The number of instances of System.Object in the array. + public int GetValues(object[] values) + { + for (int i = 0; i < _fields; i++) + values[i] = _cache[_cachePos + i]; + + return _fields; + } + + /// Return whether the specified field is set to null. + /// The index of the field to find. + /// Returns true if the specified field is set to null; otherwise, false. + public bool IsDBNull(int i) + { + return _cache[_cachePos + i] == null || _cache[_cachePos + i] == DBNull.Value; + } + + /// Gets or sets specified value in current record. + /// Name of column. + /// Value of specified column. + public object this[string name] + { + get + { + if (_ordinals.ContainsKey(name.ToUpper())) + return _cache[_cachePos + _ordinals[name.ToUpper()]]; + + throw new IndexOutOfRangeException(String.Format("Field '{0}' not found.", name)); + } + } + + /// Gets or sets specified value in current record. + /// The index of the field to find. + /// Value of specified column. + public object this[int i] + { + get { return _cache[_cachePos + i]; } + } + + #endregion IDataRecord Members + } + /// Small utility class to manage single columns. public class DynamicColumn { @@ -1059,6 +1545,15 @@ namespace DynamORM /// Connection options. required. public DynamicDatabase(IDbConnection connection, DynamicDatabaseOptions options) { + // Try to find correct provider if possible + Type t = connection.GetType(); + if (t == typeof(System.Data.SqlClient.SqlConnection)) + _provider = System.Data.SqlClient.SqlClientFactory.Instance; + else if (t == typeof(System.Data.Odbc.OdbcConnection)) + _provider = System.Data.Odbc.OdbcFactory.Instance; + else if (t == typeof(System.Data.OleDb.OleDbConnection)) + _provider = System.Data.OleDb.OleDbFactory.Instance; + IsDisposed = false; InitCommon(connection.ConnectionString, options); TransactionPool.Add(connection, new Stack()); @@ -1205,6 +1700,15 @@ namespace DynamORM return new DynamicSelectQueryBuilder(this).From(x => x(typeof(T))); } + /// Adds to the FROM clause using . + /// Type which can be represented in database. + /// Table alias. + /// This instance to permit chaining. + public virtual IDynamicSelectQueryBuilder From(string alias) + { + return new DynamicSelectQueryBuilder(this).From(x => x(typeof(T)).As(alias)); + } + /// Adds to the FROM clause using . /// Type which can be represented in database. /// This instance to permit chaining. @@ -2001,13 +2505,17 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Query(string sql, params object[] args) { + DynamicCachedReader cache = null; using (IDbConnection con = Open()) using (IDbCommand cmd = con.CreateCommand()) - using (IDataReader rdr = cmd - .SetCommand(sql) - .AddParameters(this, args) - .ExecuteReader()) - while (rdr.Read()) + { + using (IDataReader rdr = cmd + .SetCommand(sql) + .AddParameters(this, args) + .ExecuteReader()) + cache = new DynamicCachedReader(rdr); + + while (cache.Read()) { dynamic val = null; @@ -2015,7 +2523,7 @@ namespace DynamORM // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch try { - val = rdr.RowToDynamic(); + val = cache.RowToDynamic(); } catch (ArgumentException argex) { @@ -2028,6 +2536,7 @@ namespace DynamORM yield return val; } + } } /// Enumerate the reader and yield the result. @@ -2035,12 +2544,16 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Query(IDynamicQueryBuilder builder) { + DynamicCachedReader cache = null; using (IDbConnection con = Open()) using (IDbCommand cmd = con.CreateCommand()) - using (IDataReader rdr = cmd - .SetCommand(builder) - .ExecuteReader()) - while (rdr.Read()) + { + using (IDataReader rdr = cmd + .SetCommand(builder) + .ExecuteReader()) + cache = new DynamicCachedReader(rdr); + + while (cache.Read()) { dynamic val = null; @@ -2048,7 +2561,7 @@ namespace DynamORM // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch try { - val = rdr.RowToDynamic(); + val = cache.RowToDynamic(); } catch (ArgumentException argex) { @@ -2061,6 +2574,7 @@ namespace DynamORM yield return val; } + } } #endregion Query @@ -2210,8 +2724,12 @@ namespace DynamORM /// If your database doesn't get those values in upper case (like most of the databases) you should override this method. protected virtual IEnumerable ReadSchema(IDbCommand cmd) { + DataTable st = null; + using (IDataReader rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo)) - using (DataTable st = rdr.GetSchemaTable()) + st = rdr.GetSchemaTable(); + + using (st) foreach (DataRow col in st.Rows) { dynamic c = col.RowToDynamicUpper(); @@ -2219,7 +2737,7 @@ namespace DynamORM yield return new DynamicSchemaColumn { Name = c.COLUMNNAME, - Type = DynamicExtensions.TypeMap.TryGetNullable((Type)c.DATATYPE) ?? DbType.String, + Type = ReadSchemaType(c), IsKey = c.ISKEY ?? false, IsUnique = c.ISUNIQUE ?? false, Size = (int)(c.COLUMNSIZE ?? 0), @@ -2229,6 +2747,31 @@ namespace DynamORM } } + /// Reads the type of column from the schema. + /// The schema. + /// GEneric parameter type. + protected virtual DbType ReadSchemaType(dynamic schema) + { + Type type = (Type)schema.DATATYPE; + + // Small hack for SQL Server Provider + if (type == typeof(string) && Provider != null && Provider.GetType() == typeof(System.Data.SqlClient.SqlClientFactory)) + { + var map = (schema as IDictionary); + string typeName = (map.TryGetValue("DATATYPENAME") ?? string.Empty).ToString(); + + switch (typeName) + { + case "varchar": + return DbType.AnsiString; + case "nvarchar": + return DbType.String; + } + } + + return DynamicExtensions.TypeMap.TryGetNullable(type) ?? DbType.String; + } + private Dictionary BuildAndCacheSchema(string tableName, DynamicTypeMap mapper, string owner = null) { Dictionary schema = null; @@ -3107,6 +3650,8 @@ namespace DynamORM if (p.DbType == DbType.String) p.Size = item.ToString().Length > 4000 ? -1 : 4000; + else if (p.DbType == DbType.AnsiString) + p.Size = item.ToString().Length > 8000 ? -1 : 8000; } cmd.Parameters.Add(p); @@ -3149,7 +3694,9 @@ namespace DynamORM { p.DbType = TypeMap.TryGetNullable(value.GetType()) ?? DbType.String; - if (p.DbType == DbType.String) + if (p.DbType == DbType.AnsiString) + p.Size = value.ToString().Length > 8000 ? -1 : 8000; + else if (p.DbType == DbType.String) p.Size = value.ToString().Length > 4000 ? -1 : 4000; p.Value = value; @@ -3200,7 +3747,9 @@ namespace DynamORM { p.DbType = TypeMap.TryGetNullable(item.Value.GetType()) ?? DbType.String; - if (p.DbType == DbType.String) + if (p.DbType == DbType.AnsiString) + p.Size = item.Value.ToString().Length > 8000 ? -1 : 8000; + else if (p.DbType == DbType.String) p.Size = item.Value.ToString().Length > 4000 ? -1 : 4000; p.Value = item.Value; @@ -3337,7 +3886,7 @@ namespace DynamORM param.Direction = parameterDirection; param.DbType = databaseType; param.Size = size; - param.Value = value; + param.Value = value ?? DBNull.Value; command.Parameters.Add(param); return command; @@ -3356,7 +3905,7 @@ namespace DynamORM param.ParameterName = parameterName; param.DbType = databaseType; param.Size = size; - param.Value = value; + param.Value = value ?? DBNull.Value; command.Parameters.Add(param); return command; @@ -3373,7 +3922,7 @@ namespace DynamORM IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; param.DbType = databaseType; - param.Value = value; + param.Value = value ?? DBNull.Value; command.Parameters.Add(param); return command; @@ -3768,8 +4317,14 @@ namespace DynamORM IDynamicSelectQueryBuilder sub = b.SubQuery(); subquery(b, sub); - - (b as DynamicQueryBuilder).ParseCommand(sub as DynamicQueryBuilder, b.Parameters); + try + { + (b as DynamicQueryBuilder).ParseCommand(sub as DynamicQueryBuilder, b.Parameters); + } + catch (ArgumentException) + { + // This might occur if join was made to subquery + } return b; } @@ -4164,6 +4719,9 @@ namespace DynamORM /// provided . public static Type ToType(this DbType dbt) { + if (dbt == DbType.String) + return typeof(string); + foreach (KeyValuePair tdbt in TypeMap) if (tdbt.Value == dbt) return tdbt.Key; @@ -4171,6 +4729,14 @@ namespace DynamORM return typeof(object); } + /// Determines whether the specified value is has only ASCII chars. + /// The value to check. + /// Returns true if the specified value has only ASCII cars; otherwise, false. + public static bool IsASCII(this string value) + { + return Encoding.UTF8.GetByteCount(value) == value.Length; + } + #endregion Type extensions #region IDictionary extensions @@ -4243,6 +4809,14 @@ namespace DynamORM yield return r.RowToDynamic(); } + internal static IDataReader CachedReader(this IDataReader r) + { + if (r is DynamicCachedReader) + return r; + + return new DynamicCachedReader(r); + } + #endregion IDataReader extensions #region Mapper extensions @@ -4501,6 +5075,7 @@ namespace DynamORM 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) : @@ -4537,13 +5112,21 @@ namespace DynamORM mainResult = types[0].GetDefaultValue(); if (types[0] == typeof(IDataReader)) - mainResult = cmd.ExecuteReader(); + { + using (IDataReader rdr = cmd.ExecuteReader()) + mainResult = rdr.CachedReader(); + } else if (types[0].IsGenericEnumerable()) { Type argType = types[0].GetGenericArguments().First(); if (argType == typeof(object)) + { + IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - mainResult = rdr.EnumerateReader().ToList(); + cache = rdr.CachedReader(); + + mainResult = cache.EnumerateReader().ToList(); + } else if (argType.IsValueType) { Type listType = typeof(List<>).MakeGenericType(new Type[] { argType }); @@ -4551,9 +5134,12 @@ namespace DynamORM object defVal = listType.GetDefaultValue(); + IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - while (rdr.Read()) - listInstance.Add(rdr[0] == DBNull.Value ? defVal : argType.CastObject(rdr[0])); + cache = rdr.CachedReader(); + + while (cache.Read()) + listInstance.Add(cache[0] == DBNull.Value ? defVal : argType.CastObject(cache[0])); mainResult = listInstance; } @@ -4563,8 +5149,11 @@ namespace DynamORM if (mapper == null) throw new InvalidCastException(string.Format("Don't konw what to do with this type: '{0}'.", argType.ToString())); + IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - mainResult = rdr.EnumerateReader().MapEnumerable(argType).ToList(); + cache = rdr.CachedReader(); + + mainResult = cache.EnumerateReader().MapEnumerable(argType).ToList(); } } else if (types[0].IsValueType) @@ -7282,7 +7871,10 @@ namespace DynamORM // If there are parameters to transform, but cannot store them, it is an error if (node.Parameters.Count != 0 && pars == null) - throw new InvalidOperationException(string.Format("The parameters in this command '{0}' cannot be added to a null collection.", node.Parameters)); + return string.Format("({0})", str); + + // TODO: Make special condiion + //throw new InvalidOperationException(string.Format("The parameters in this command '{0}' cannot be added to a null collection.", node.Parameters)); // Copy parameters to new comand foreach (KeyValuePair parameter in node.Parameters) @@ -7762,7 +8354,7 @@ namespace DynamORM ITableInfo tableInfo = !string.IsNullOrEmpty(tableName) ? Tables.FirstOrDefault(x => !string.IsNullOrEmpty(x.Alias) && x.Alias.ToLower() == tableName) ?? Tables.FirstOrDefault(x => x.Name.ToLower() == tableName.ToLower()) ?? Tables.FirstOrDefault() : - this is DynamicModifyBuilder ? Tables.FirstOrDefault() : null; + this is DynamicModifyBuilder || Tables.Count == 1 ? Tables.FirstOrDefault() : null; // Try to get column from schema if (tableInfo != null && tableInfo.Schema != null) @@ -7901,12 +8493,16 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() { + DynamicCachedReader cache = null; using (IDbConnection con = Database.Open()) using (IDbCommand cmd = con.CreateCommand()) - using (IDataReader rdr = cmd - .SetCommand(this) - .ExecuteReader()) - while (rdr.Read()) + { + using (IDataReader rdr = cmd + .SetCommand(this) + .ExecuteReader()) + cache = new DynamicCachedReader(rdr); + + while (cache.Read()) { dynamic val = null; @@ -7914,7 +8510,7 @@ namespace DynamORM // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch try { - val = rdr.RowToDynamic(); + val = cache.RowToDynamic(); } catch (ArgumentException argex) { @@ -7927,6 +8523,7 @@ namespace DynamORM yield return val; } + } } /// Execute this builder and map to given type. @@ -7934,6 +8531,7 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() where T : class { + DynamicCachedReader cache = null; DynamicTypeMap mapper = DynamicMapperCache.GetMapper(); if (mapper == null) @@ -7945,27 +8543,29 @@ namespace DynamORM using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) - while (rdr.Read()) + cache = new DynamicCachedReader(rdr); + + while (cache.Read()) + { + dynamic val = null; + + // Work around to avoid yield being in try...catchblock: + // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch + try { - dynamic val = null; - - // Work around to avoid yield being in try...catchblock: - // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch - try - { - val = rdr.RowToDynamic(); - } - catch (ArgumentException argex) - { - StringBuilder sb = new StringBuilder(); - cmd.Dump(sb); - - throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), - argex.InnerException.NullOr(a => a, argex)); - } - - yield return mapper.Create(val) as T; + val = cache.RowToDynamic(); } + catch (ArgumentException argex) + { + StringBuilder sb = new StringBuilder(); + cmd.Dump(sb); + + throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), + argex.InnerException.NullOr(a => a, argex)); + } + + yield return mapper.Create(val) as T; + } } } @@ -7981,6 +8581,23 @@ namespace DynamORM reader(rdr); } + /// Execute this builder as a data reader, but + /// first makes a full reader copy in memory. + /// Action containing reader. + public virtual void ExecuteCachedDataReader(Action reader) + { + DynamicCachedReader cache = null; + + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) + using (IDataReader rdr = cmd + .SetCommand(this) + .ExecuteReader()) + cache = new DynamicCachedReader(rdr); + + reader(cache); + } + /// Returns a single result. /// Result of a query. public virtual object Scalar() diff --git a/DynamORM.Tests/Select/ParserTests.cs b/DynamORM.Tests/Select/ParserTests.cs index 36950d6..198010c 100644 --- a/DynamORM.Tests/Select/ParserTests.cs +++ b/DynamORM.Tests/Select/ParserTests.cs @@ -387,6 +387,21 @@ namespace DynamORM.Tests.Select Assert.AreEqual(string.Format("SELECT usr.*, uc.\"Users\" FROM \"dbo\".\"Users\" AS usr INNER JOIN (SELECT * FROM \"dbo\".\"UserClients\") AS uc ON ((usr.\"Id_User\" = uc.\"User_Id\") AND (uc.\"Users\" IS NOT NULL))"), cmd.CommandText()); } + /// + /// Tests from method using invoke with sub query. + /// + [Test] + public void TestInnerJoin4() + { + IDynamicSelectQueryBuilder cmd = new DynamicSelectQueryBuilder(Database); + + cmd.From(u => u.dbo.Users.As(u.usr)) + .SubQuery((b, s) => b.Join(usr => usr(s.From(x => x.dbo.UserClients).Where(x => x.Deleted == 0)).Inner().As(usr.uc).On(usr.Id_User == usr.uc.User_Id && usr.uc.Users != null))) + .Select(usr => usr.All(), uc => uc.Users); + + Assert.AreEqual(string.Format("SELECT usr.*, uc.\"Users\" FROM \"dbo\".\"Users\" AS usr INNER JOIN (SELECT * FROM \"dbo\".\"UserClients\" WHERE (\"Deleted\" = [${0}])) AS uc ON ((usr.\"Id_User\" = uc.\"User_Id\") AND (uc.\"Users\" IS NOT NULL))", cmd.Parameters.Keys.First()), cmd.CommandText()); + } + /// /// Tests left outer join method. /// diff --git a/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs index 102e41f..75bad9c 100644 --- a/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicQueryBuilder.cs @@ -410,7 +410,10 @@ namespace DynamORM.Builders.Implementation // If there are parameters to transform, but cannot store them, it is an error if (node.Parameters.Count != 0 && pars == null) - throw new InvalidOperationException(string.Format("The parameters in this command '{0}' cannot be added to a null collection.", node.Parameters)); + return string.Format("({0})", str); + + // TODO: Make special condiion + //throw new InvalidOperationException(string.Format("The parameters in this command '{0}' cannot be added to a null collection.", node.Parameters)); // Copy parameters to new comand foreach (KeyValuePair parameter in node.Parameters) @@ -890,7 +893,7 @@ namespace DynamORM.Builders.Implementation ITableInfo tableInfo = !string.IsNullOrEmpty(tableName) ? Tables.FirstOrDefault(x => !string.IsNullOrEmpty(x.Alias) && x.Alias.ToLower() == tableName) ?? Tables.FirstOrDefault(x => x.Name.ToLower() == tableName.ToLower()) ?? Tables.FirstOrDefault() : - this is DynamicModifyBuilder ? Tables.FirstOrDefault() : null; + this is DynamicModifyBuilder || Tables.Count == 1 ? Tables.FirstOrDefault() : null; // Try to get column from schema if (tableInfo != null && tableInfo.Schema != null) diff --git a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs index a5c14cc..28af8ba 100644 --- a/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs +++ b/DynamORM/Builders/Implementation/DynamicSelectQueryBuilder.cs @@ -128,12 +128,16 @@ namespace DynamORM.Builders.Implementation /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() { + DynamicCachedReader cache = null; using (IDbConnection con = Database.Open()) using (IDbCommand cmd = con.CreateCommand()) - using (IDataReader rdr = cmd - .SetCommand(this) - .ExecuteReader()) - while (rdr.Read()) + { + using (IDataReader rdr = cmd + .SetCommand(this) + .ExecuteReader()) + cache = new DynamicCachedReader(rdr); + + while (cache.Read()) { dynamic val = null; @@ -141,7 +145,7 @@ namespace DynamORM.Builders.Implementation // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch try { - val = rdr.RowToDynamic(); + val = cache.RowToDynamic(); } catch (ArgumentException argex) { @@ -154,6 +158,7 @@ namespace DynamORM.Builders.Implementation yield return val; } + } } /// Execute this builder and map to given type. @@ -161,6 +166,7 @@ namespace DynamORM.Builders.Implementation /// Enumerator of objects expanded from query. public virtual IEnumerable Execute() where T : class { + DynamicCachedReader cache = null; DynamicTypeMap mapper = DynamicMapperCache.GetMapper(); if (mapper == null) @@ -172,27 +178,29 @@ namespace DynamORM.Builders.Implementation using (IDataReader rdr = cmd .SetCommand(this) .ExecuteReader()) - while (rdr.Read()) + cache = new DynamicCachedReader(rdr); + + while (cache.Read()) + { + dynamic val = null; + + // Work around to avoid yield being in try...catchblock: + // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch + try { - dynamic val = null; - - // Work around to avoid yield being in try...catchblock: - // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch - try - { - val = rdr.RowToDynamic(); - } - catch (ArgumentException argex) - { - StringBuilder sb = new StringBuilder(); - cmd.Dump(sb); - - throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), - argex.InnerException.NullOr(a => a, argex)); - } - - yield return mapper.Create(val) as T; + val = cache.RowToDynamic(); } + catch (ArgumentException argex) + { + StringBuilder sb = new StringBuilder(); + cmd.Dump(sb); + + throw new ArgumentException(string.Format("{0}{1}{2}", argex.Message, Environment.NewLine, sb), + argex.InnerException.NullOr(a => a, argex)); + } + + yield return mapper.Create(val) as T; + } } } @@ -208,6 +216,23 @@ namespace DynamORM.Builders.Implementation reader(rdr); } + /// Execute this builder as a data reader, but + /// first makes a full reader copy in memory. + /// Action containing reader. + public virtual void ExecuteCachedDataReader(Action reader) + { + DynamicCachedReader cache = null; + + using (IDbConnection con = Database.Open()) + using (IDbCommand cmd = con.CreateCommand()) + using (IDataReader rdr = cmd + .SetCommand(this) + .ExecuteReader()) + cache = new DynamicCachedReader(rdr); + + reader(cache); + } + /// Returns a single result. /// Result of a query. public virtual object Scalar() diff --git a/DynamORM/DynamORM.csproj b/DynamORM/DynamORM.csproj index c7c72bd..c91f9d0 100644 --- a/DynamORM/DynamORM.csproj +++ b/DynamORM/DynamORM.csproj @@ -79,6 +79,7 @@ + diff --git a/DynamORM/DynamicDatabase.cs b/DynamORM/DynamicDatabase.cs index 7da2e19..c207000 100644 --- a/DynamORM/DynamicDatabase.cs +++ b/DynamORM/DynamicDatabase.cs @@ -170,6 +170,15 @@ namespace DynamORM /// Connection options. required. public DynamicDatabase(IDbConnection connection, DynamicDatabaseOptions options) { + // Try to find correct provider if possible + Type t = connection.GetType(); + if (t == typeof(System.Data.SqlClient.SqlConnection)) + _provider = System.Data.SqlClient.SqlClientFactory.Instance; + else if (t == typeof(System.Data.Odbc.OdbcConnection)) + _provider = System.Data.Odbc.OdbcFactory.Instance; + else if (t == typeof(System.Data.OleDb.OleDbConnection)) + _provider = System.Data.OleDb.OleDbFactory.Instance; + IsDisposed = false; InitCommon(connection.ConnectionString, options); TransactionPool.Add(connection, new Stack()); @@ -315,6 +324,15 @@ namespace DynamORM { return new DynamicSelectQueryBuilder(this).From(x => x(typeof(T))); } + + /// Adds to the FROM clause using . + /// Type which can be represented in database. + /// Table alias. + /// This instance to permit chaining. + public virtual IDynamicSelectQueryBuilder From(string alias) + { + return new DynamicSelectQueryBuilder(this).From(x => x(typeof(T)).As(alias)); + } /// Adds to the FROM clause using . /// Type which can be represented in database. @@ -1112,13 +1130,17 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Query(string sql, params object[] args) { + DynamicCachedReader cache = null; using (IDbConnection con = Open()) using (IDbCommand cmd = con.CreateCommand()) - using (IDataReader rdr = cmd - .SetCommand(sql) - .AddParameters(this, args) - .ExecuteReader()) - while (rdr.Read()) + { + using (IDataReader rdr = cmd + .SetCommand(sql) + .AddParameters(this, args) + .ExecuteReader()) + cache = new DynamicCachedReader(rdr); + + while (cache.Read()) { dynamic val = null; @@ -1126,7 +1148,7 @@ namespace DynamORM // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch try { - val = rdr.RowToDynamic(); + val = cache.RowToDynamic(); } catch (ArgumentException argex) { @@ -1139,6 +1161,7 @@ namespace DynamORM yield return val; } + } } /// Enumerate the reader and yield the result. @@ -1146,12 +1169,16 @@ namespace DynamORM /// Enumerator of objects expanded from query. public virtual IEnumerable Query(IDynamicQueryBuilder builder) { + DynamicCachedReader cache = null; using (IDbConnection con = Open()) using (IDbCommand cmd = con.CreateCommand()) - using (IDataReader rdr = cmd - .SetCommand(builder) - .ExecuteReader()) - while (rdr.Read()) + { + using (IDataReader rdr = cmd + .SetCommand(builder) + .ExecuteReader()) + cache = new DynamicCachedReader(rdr); + + while (cache.Read()) { dynamic val = null; @@ -1159,7 +1186,7 @@ namespace DynamORM // http://stackoverflow.com/questions/346365/why-cant-yield-return-appear-inside-a-try-block-with-a-catch try { - val = rdr.RowToDynamic(); + val = cache.RowToDynamic(); } catch (ArgumentException argex) { @@ -1172,6 +1199,7 @@ namespace DynamORM yield return val; } + } } #endregion Query @@ -1321,8 +1349,12 @@ namespace DynamORM /// If your database doesn't get those values in upper case (like most of the databases) you should override this method. protected virtual IEnumerable ReadSchema(IDbCommand cmd) { + DataTable st = null; + using (IDataReader rdr = cmd.ExecuteReader(CommandBehavior.SchemaOnly | CommandBehavior.KeyInfo)) - using (DataTable st = rdr.GetSchemaTable()) + st = rdr.GetSchemaTable(); + + using (st) foreach (DataRow col in st.Rows) { dynamic c = col.RowToDynamicUpper(); @@ -1330,7 +1362,7 @@ namespace DynamORM yield return new DynamicSchemaColumn { Name = c.COLUMNNAME, - Type = DynamicExtensions.TypeMap.TryGetNullable((Type)c.DATATYPE) ?? DbType.String, + Type = ReadSchemaType(c), IsKey = c.ISKEY ?? false, IsUnique = c.ISUNIQUE ?? false, Size = (int)(c.COLUMNSIZE ?? 0), @@ -1340,6 +1372,30 @@ namespace DynamORM } } + /// Reads the type of column from the schema. + /// The schema. + /// GEneric parameter type. + protected virtual DbType ReadSchemaType(dynamic schema) + { + Type type = (Type)schema.DATATYPE; + + // Small hack for SQL Server Provider + if (type == typeof(string) && Provider != null && Provider.GetType() == typeof(System.Data.SqlClient.SqlClientFactory)) + { + var map = (schema as IDictionary); + string typeName = (map.TryGetValue("DATATYPENAME") ?? string.Empty).ToString(); + + switch (typeName){ + case "varchar": + return DbType.AnsiString; + case "nvarchar": + return DbType.String; + } + } + + return DynamicExtensions.TypeMap.TryGetNullable(type) ?? DbType.String; + } + private Dictionary BuildAndCacheSchema(string tableName, DynamicTypeMap mapper, string owner = null) { Dictionary schema = null; diff --git a/DynamORM/DynamicExtensions.cs b/DynamORM/DynamicExtensions.cs index b151cce..80325cd 100644 --- a/DynamORM/DynamicExtensions.cs +++ b/DynamORM/DynamicExtensions.cs @@ -286,6 +286,8 @@ namespace DynamORM if (p.DbType == DbType.String) p.Size = item.ToString().Length > 4000 ? -1 : 4000; + else if (p.DbType == DbType.AnsiString) + p.Size = item.ToString().Length > 8000 ? -1 : 8000; } cmd.Parameters.Add(p); @@ -328,7 +330,9 @@ namespace DynamORM { p.DbType = TypeMap.TryGetNullable(value.GetType()) ?? DbType.String; - if (p.DbType == DbType.String) + if (p.DbType == DbType.AnsiString) + p.Size = value.ToString().Length > 8000 ? -1 : 8000; + else if (p.DbType == DbType.String) p.Size = value.ToString().Length > 4000 ? -1 : 4000; p.Value = value; @@ -379,7 +383,9 @@ namespace DynamORM { p.DbType = TypeMap.TryGetNullable(item.Value.GetType()) ?? DbType.String; - if (p.DbType == DbType.String) + if (p.DbType == DbType.AnsiString) + p.Size = item.Value.ToString().Length > 8000 ? -1 : 8000; + else if (p.DbType == DbType.String) p.Size = item.Value.ToString().Length > 4000 ? -1 : 4000; p.Value = item.Value; @@ -516,7 +522,7 @@ namespace DynamORM param.Direction = parameterDirection; param.DbType = databaseType; param.Size = size; - param.Value = value; + param.Value = value ?? DBNull.Value; command.Parameters.Add(param); return command; @@ -535,7 +541,7 @@ namespace DynamORM param.ParameterName = parameterName; param.DbType = databaseType; param.Size = size; - param.Value = value; + param.Value = value ?? DBNull.Value; command.Parameters.Add(param); return command; @@ -552,7 +558,7 @@ namespace DynamORM IDbDataParameter param = command.CreateParameter(); param.ParameterName = parameterName; param.DbType = databaseType; - param.Value = value; + param.Value = value ?? DBNull.Value; command.Parameters.Add(param); return command; @@ -947,8 +953,14 @@ namespace DynamORM IDynamicSelectQueryBuilder sub = b.SubQuery(); subquery(b, sub); - - (b as DynamicQueryBuilder).ParseCommand(sub as DynamicQueryBuilder, b.Parameters); + try + { + (b as DynamicQueryBuilder).ParseCommand(sub as DynamicQueryBuilder, b.Parameters); + } + catch (ArgumentException) + { + // This might occur if join was made to subquery + } return b; } @@ -1343,6 +1355,9 @@ namespace DynamORM /// provided . public static Type ToType(this DbType dbt) { + if (dbt == DbType.String) + return typeof(string); + foreach (KeyValuePair tdbt in TypeMap) if (tdbt.Value == dbt) return tdbt.Key; @@ -1350,6 +1365,14 @@ namespace DynamORM return typeof(object); } + /// Determines whether the specified value is has only ASCII chars. + /// The value to check. + /// Returns true if the specified value has only ASCII cars; otherwise, false. + public static bool IsASCII(this string value) + { + return Encoding.UTF8.GetByteCount(value) == value.Length; + } + #endregion Type extensions #region IDictionary extensions @@ -1422,6 +1445,14 @@ namespace DynamORM yield return r.RowToDynamic(); } + internal static IDataReader CachedReader(this IDataReader r) + { + if (r is DynamicCachedReader) + return r; + + return new DynamicCachedReader(r); + } + #endregion IDataReader extensions #region Mapper extensions diff --git a/DynamORM/DynamicProcedureInvoker.cs b/DynamORM/DynamicProcedureInvoker.cs index bbd33af..6cf6f6e 100644 --- a/DynamORM/DynamicProcedureInvoker.cs +++ b/DynamORM/DynamicProcedureInvoker.cs @@ -122,6 +122,7 @@ namespace DynamORM 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) : @@ -158,13 +159,21 @@ namespace DynamORM mainResult = types[0].GetDefaultValue(); if (types[0] == typeof(IDataReader)) - mainResult = cmd.ExecuteReader(); + { + using (IDataReader rdr = cmd.ExecuteReader()) + mainResult = rdr.CachedReader(); + } else if (types[0].IsGenericEnumerable()) { Type argType = types[0].GetGenericArguments().First(); if (argType == typeof(object)) + { + IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - mainResult = rdr.EnumerateReader().ToList(); + cache = rdr.CachedReader(); + + mainResult = cache.EnumerateReader().ToList(); + } else if (argType.IsValueType) { Type listType = typeof(List<>).MakeGenericType(new Type[] { argType }); @@ -172,9 +181,12 @@ namespace DynamORM object defVal = listType.GetDefaultValue(); + IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - while (rdr.Read()) - listInstance.Add(rdr[0] == DBNull.Value ? defVal : argType.CastObject(rdr[0])); + cache = rdr.CachedReader(); + + while (cache.Read()) + listInstance.Add(cache[0] == DBNull.Value ? defVal : argType.CastObject(cache[0])); mainResult = listInstance; } @@ -184,8 +196,11 @@ namespace DynamORM if (mapper == null) throw new InvalidCastException(string.Format("Don't konw what to do with this type: '{0}'.", argType.ToString())); + IDataReader cache = null; using (IDataReader rdr = cmd.ExecuteReader()) - mainResult = rdr.EnumerateReader().MapEnumerable(argType).ToList(); + cache = rdr.CachedReader(); + + mainResult = cache.EnumerateReader().MapEnumerable(argType).ToList(); } } else if (types[0].IsValueType) diff --git a/Tester/Program.cs b/Tester/Program.cs index e56e518..2ae5ef6 100644 --- a/Tester/Program.cs +++ b/Tester/Program.cs @@ -1,9 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Data.SqlClient; -using System.IO; -using System.Text; +using System.Linq; +using DynamORM; namespace Tester { @@ -25,194 +21,28 @@ namespace Tester private static void Main(string[] args) { - //StringBuilder code = new StringBuilder(); - //using (var db = GetORM()) - //{ - // List procs = db.From(x => x.INFORMATION_SCHEMA.ROUTINES).OrderBy(x => x.SPECIFIC_NAME).Where(x => x.ROUTINE_TYPE == "PROCEDURE").Execute().ToList(); + DynamicDatabase db = new DynamicDatabase(System.Data.SqlClient.SqlClientFactory.Instance, "packet size=4096;User Id=sa;Password=Sa123;data source=127.0.0.1,1434;initial catalog=MAH_Levant;", + DynamicDatabaseOptions.SingleConnection | DynamicDatabaseOptions.SingleTransaction | DynamicDatabaseOptions.SupportSchema | + DynamicDatabaseOptions.SupportStoredProcedures | DynamicDatabaseOptions.SupportTop | DynamicDatabaseOptions.DumpCommands); - // foreach (dynamic d in procs) - // PrintWhatYouKnow(d.SPECIFIC_NAME, code); - //} - - //Console.ReadLine(); - //Console.WriteLine(code.ToString()); - //File.WriteAllText("code.cs", code.ToString()); - //Console.ReadLine(); - - Dictionary times = new Dictionary() + try { - /*{ new DateTime(2015,03,07,13,00,00), new DateTime(2015,03,07,23,30,00) }, - { new DateTime(2015,03,08,14,00,00), new DateTime(2015,03,08,19,00,00) }, - { new DateTime(2015,03,14,13,00,00), new DateTime(2015,03,15,01,30,00) }, - { new DateTime(2015,03,15,14,00,00), new DateTime(2015,03,16,00,00,00) }, - { new DateTime(2015,03,28,13,00,00), new DateTime(2015,03,28,22,30,00) }, - { new DateTime(2015,03,29,14,00,00), new DateTime(2015,03,29,21,00,00) }, - { new DateTime(2015,04,02,20,30,00), new DateTime(2015,04,03,00,30,00) }, - { new DateTime(2015,04,04,12,00,00), new DateTime(2015,04,04,23,30,00) }, - { new DateTime(2015,04,05,15,00,00), new DateTime(2015,04,05,21,00,00) }, - { new DateTime(2015,04,06,18,00,00), new DateTime(2015,04,06,23,30,00) }, - { new DateTime(2015,04,07,20,00,00), new DateTime(2015,04,08,00,00,00) }, - { new DateTime(2015,04,08,20,00,00), new DateTime(2015,04,08,23,30,00) }, - { new DateTime(2015,04,09,22,30,00), new DateTime(2015,04,10,00,00,00) }, - { new DateTime(2015,04,10,21,00,00), new DateTime(2015,04,11,00,00,00) }, - { new DateTime(2015,04,11,13,00,00), new DateTime(2015,04,11,18,00,00) }, - { new DateTime(2015,04,11,20,30,00), new DateTime(2015,04,11,23,30,00) }, - { new DateTime(2015,04,12,10,00,00), new DateTime(2015,04,12,13,00,00) }, - { new DateTime(2015,04,12,16,00,00), new DateTime(2015,04,13,00,00,00) }, - { new DateTime(2015,04,13,21,30,00), new DateTime(2015,04,14,00,00,00) }, - { new DateTime(2015,04,14,21,00,00), new DateTime(2015,04,15,00,30,00) }, - { new DateTime(2015,04,17,20,30,00), new DateTime(2015,04,17,23,30,00) }, - { new DateTime(2015,04,18,14,00,00), new DateTime(2015,04,18,18,30,00) }, - { new DateTime(2015,04,18,20,30,00), new DateTime(2015,04,19,02,00,00) }, - { new DateTime(2015,04,19,13,30,00), new DateTime(2015,04,19,17,00,00) }, - { new DateTime(2015,04,19,19,00,00), new DateTime(2015,04,20,00,00,00) }, - { new DateTime(2015,04,20,21,00,00), new DateTime(2015,04,21,00,00,00) }, - { new DateTime(2015,04,21,21,30,00), new DateTime(2015,04,22,00,00,00) }, - { new DateTime(2015,04,22,21,00,00), new DateTime(2015,04,22,23,30,00) }, - { new DateTime(2015,04,23,20,30,00), new DateTime(2015,04,24,00,00,00) }, - { new DateTime(2015,04,25,09,30,00), new DateTime(2015,04,25,15,00,00) }, - { new DateTime(2015,04,25,15,30,00), new DateTime(2015,04,25,19,30,00) }, - { new DateTime(2015,04,25,21,00,00), new DateTime(2015,04,26,02,00,00) }, - { new DateTime(2015,04,26,10,00,00), new DateTime(2015,04,26,12,00,00) }, - { new DateTime(2015,04,26,18,00,00), new DateTime(2015,04,26,19,30,00) }, - { new DateTime(2015,04,26,20,00,00), new DateTime(2015,04,27,00,00,00) }, - { new DateTime(2015,04,27,20,30,00), new DateTime(2015,04,28,01,00,00) }, - { new DateTime(2015,04,28,20,00,00), new DateTime(2015,04,29,01,00,00) }, - { new DateTime(2015,04,29,20,30,00), new DateTime(2015,04,30,01,00,00) }, - { new DateTime(2015,04,30,21,00,00), new DateTime(2015,05,01,02,30,00) }, - { new DateTime(2015,05,01,10,00,00), new DateTime(2015,05,01,14,30,00) }, - { new DateTime(2015,05,02,11,00,00), new DateTime(2015,05,02,17,30,00) }, - { new DateTime(2015,05,03,10,00,00), new DateTime(2015,05,03,22,00,00) }, - { new DateTime(2015,05,04,20,30,00), new DateTime(2015,05,05,01,00,00) }, - { new DateTime(2015,05,05,17,30,00), new DateTime(2015,05,05,19,00,00) }, - { new DateTime(2015,05,05,20,30,00), new DateTime(2015,05,06,01,00,00) }, - { new DateTime(2015,05,06,17,30,00), new DateTime(2015,05,06,19,00,00) }, - { new DateTime(2015,05,06,20,00,00), new DateTime(2015,05,07,01,00,00) }, - { new DateTime(2015,05,07,20,30,00), new DateTime(2015,05,08,01,00,00) }, - { new DateTime(2015,05,08,17,30,00), new DateTime(2015,05,08,19,00,00) }, - { new DateTime(2015,05,08,20,30,00), new DateTime(2015,05,09,02,00,00) }, - { new DateTime(2015,05,09,11,00,00), new DateTime(2015,05,09,16,30,00) }, - { new DateTime(2015,05,10,10,00,00), new DateTime(2015,05,10,15,30,00) }, - { new DateTime(2015,05,10,16,30,00), new DateTime(2015,05,10,23,30,00) }, - { new DateTime(2015,05,11,21,00,00), new DateTime(2015,05,12,01,00,00) }, - { new DateTime(2015,05,12,21,30,00), new DateTime(2015,05,13,01,30,00) }, - { new DateTime(2015,05,13,20,30,00), new DateTime(2015,05,14,00,30,00) }, - { new DateTime(2015,05,14,21,00,00), new DateTime(2015,05,15,02,00,00) }, - { new DateTime(2015,05,15,22,00,00), new DateTime(2015,05,16,02,00,00) }, - { new DateTime(2015,05,16,16,00,00), new DateTime(2015,05,17,01,00,00) }, - { new DateTime(2015,05,17,19,00,00), new DateTime(2015,05,18,00,30,00) }, - { new DateTime(2015,05,18,20,30,00), new DateTime(2015,05,19,01,00,00) }, - { new DateTime(2015,05,19,13,00,00), new DateTime(2015,05,19,15,00,00) }, - { new DateTime(2015,05,19,20,00,00), new DateTime(2015,05,20,00,30,00) }, - { new DateTime(2015,05,20,20,30,00), new DateTime(2015,05,21,00,00,00) }, - { new DateTime(2015,05,21,21,00,00), new DateTime(2015,05,21,23,00,00) }, - { new DateTime(2015,05,22,20,30,00), new DateTime(2015,05,23,02,30,00) }, - { new DateTime(2015,05,23,09,30,00), new DateTime(2015,05,23,17,30,00) }, - { new DateTime(2015,05,23,18,30,00), new DateTime(2015,05,23,22,30,00) }, - { new DateTime(2015,05,24,13,00,00), new DateTime(2015,05,25,00,00,00) }, - { new DateTime(2015,06,02,20,00,00), new DateTime(2015,06,02,23,00,00) }, - { new DateTime(2015,06,05,17,30,00), new DateTime(2015,06,05,19,30,00) },*/ - { new DateTime(2015,05,26,21,00,00), new DateTime(2015,05,26,23,30,00) }, - { new DateTime(2015,05,27,21,00,00), new DateTime(2015,05,28,01,00,00) }, - { new DateTime(2015,05,28,20,00,00), new DateTime(2015,05,29,00,00,00) }, - { new DateTime(2015,05,30,10,30,00), new DateTime(2015,05,30,14,30,00) }, - { new DateTime(2015,05,30,16,00,00), new DateTime(2015,05,30,21,00,00) }, - { new DateTime(2015,05,30,22,00,00), new DateTime(2015,05,31,02,30,00) }, - { new DateTime(2015,05,31,13,30,00), new DateTime(2015,05,31,15,30,00) }, - { new DateTime(2015,05,31,16,30,00), new DateTime(2015,05,31,23,30,00) }, - { new DateTime(2015,06,01,21,00,00), new DateTime(2015,06,01,22,00,00) }, - { new DateTime(2015,06,04,18,00,00), new DateTime(2015,06,04,22,00,00) }, - }; - - StringBuilder inserts = new StringBuilder(); - - int counter = 0; - - foreach (var item in times) - AddInserts(inserts, item.Key, item.Value, ref counter); - - File.WriteAllText("times.sql", inserts.ToString()); - } - - private static void AddInserts(StringBuilder sb, DateTime from, DateTime to, ref int counter) - { - string format = @" -INSERT INTO ticket_change(ticket, ""time"", author, field, oldvalue, newvalue) VALUES (26114, {0}, 'grzegorz.russek', 'comment', '{1}', 'Google calendar import.'); -INSERT INTO ticket_change(ticket, ""time"", author, field, oldvalue, newvalue) VALUES (26114, {0}, 'grzegorz.russek', 'hours', '0', '{2:0.000000}');"; - - if (from.Date != to.Date) - { - if (to.Hour == 0 && to.Minute == 0) - sb.AppendFormat(format, GetTracEpoch(to.AddSeconds(-1)), ++counter, (to - from).TotalHours); - else - { - sb.AppendFormat(format, GetTracEpoch(to.Date.AddSeconds(-1)), ++counter, (to.Date - from).TotalHours); - sb.AppendFormat(format, GetTracEpoch(to), ++counter, (to - to.Date).TotalHours); - } + db.Execute("DROP TABLE Experiments "); } - else - sb.AppendFormat(format, GetTracEpoch(to), ++counter, (to - from).TotalHours); - } + catch { } - private static long GetTracEpoch(DateTime date) - { - return Convert.ToInt64((date.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds) * 1000000; - } + db.Execute("CREATE TABLE Experiments (t1 nvarchar(50) NOT NULL DEFAULT N'', t2 varchar(50) NOT NULL DEFAULT '');"); - private static void PrintWhatYouKnow(string name, StringBuilder code) - { - string yourConnStr = "packet size=4096;User Id=sa;Password=sa123;data source=192.168.1.9,1433;initial catalog=MOM_NEXT_Florentyna_WMS_PROD;"; - using (SqlConnection sqlConn = new SqlConnection(yourConnStr)) - using (SqlCommand sqlCmd = new SqlCommand(name, sqlConn)) - { - StringBuilder body = new StringBuilder(); + var q = db.From(x => x.Experiments.As(x.e1)); + q + .Where(x => x.t2 = "Dupą") + .Where(x => x.Exists( + q.SubQuery() + .From(y => y.Experiments.As(x.e2)) + .Where(y => y.e2.t1 == y.e1.t1))) + .Execute().ToList(); - sqlConn.Open(); - sqlCmd.CommandType = CommandType.StoredProcedure; - try - { - SqlCommandBuilder.DeriveParameters(sqlCmd); - Console.WriteLine("PROCEDURE: {0}", name); - Console.WriteLine(sqlCmd.Parameters.Count.ToString()); - - code.AppendFormat("public static void {0}(this DynamicDatabase db", name); - body.AppendFormat(" db.Procedures.{0}(x$x$", name); - - foreach (SqlParameter p in sqlCmd.Parameters) - { - Console.WriteLine(p.ParameterName.ToString() + "\t" - + p.Direction.ToString() + "\t" + p.DbType.ToString()); - - if (p.Direction != ParameterDirection.ReturnValue) - { - code.Append(", "); body.Append(", "); - - switch (p.Direction) - { - case ParameterDirection.InputOutput: - code.Append("ref "); body.Append("both_"); - break; - - case ParameterDirection.Output: - code.Append("out "); body.Append("out_"); - break; - - default: - break; - } - - code.AppendFormat("{0} {1}", p.DbType, p.ParameterName.Trim('@')); - body.AppendFormat("{0}: {0}", p.ParameterName.Trim('@')); - } - } - - code.AppendFormat("){0}{{{0}{1});{0}}}{0}", Environment.NewLine, body.ToString().Replace("(x$x$, ", "(")); - } - catch (Exception ex) - { - Console.WriteLine("PROCEDURE: {0}, has errors: {1}", name, ex.Message); - } - } + db.Execute("DROP TABLE Experiments "); } } } \ No newline at end of file