public MainViewModel() { for (int i = 0; i < InitialColumnsNumber; ++i) { Columns.Add(new ColumnHeader { Header = _columnCounter++ }); } for (int j = 0; j < InitialRowsNumber; ++j) { var row = new DynamicRow <int, PropertyData> { Title = _rowCounter++ }; for (int i = 0; i < InitialColumnsNumber; ++i) { row.Add(new PropertyData { Data = _dataCounter++ }); } Rows.Add(row); } }
public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { object instance; JContainer container; if (reader.TokenType == JsonToken.Null) { return(null); } if (reader.TokenType == JsonToken.String) { if (objectType == typeof(DynamicItem)) { return new DynamicControl { Control = Convert.ToString(reader.Value) } } ; if (objectType == typeof(TableCell)) { return(new DynamicRow(new DynamicControl { Control = Convert.ToString(reader.Value) })); } } if (reader.TokenType == JsonToken.StartArray) { container = JArray.Load(reader); if (objectType == typeof(DynamicRow)) { var dynamicRow = new DynamicRow(); instance = dynamicRow; serializer.Populate(container.CreateReader(), dynamicRow); } else if (objectType == typeof(DynamicItem)) { var dynamicTable = new DynamicTable(); instance = dynamicTable; serializer.Populate(container.CreateReader(), dynamicTable.Rows); } else { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Invalid object graph")); } } else { container = JObject.Load(reader); if (container["$type"] == null) { if (container["Rows"] != null) { instance = new DynamicTable(); } else if (container["Control"] != null) { instance = new DynamicControl(); } else { throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Could not infer the type of object to create")); } serializer.Populate(container.CreateReader(), instance); } else { var type = Type.GetType((string)container["$type"]); if (!typeof(DynamicItem).IsAssignableFrom(type)) { var dynamicControl = new DynamicControl(); dynamicControl.Control = serializer.Deserialize(container.CreateReader()) as Control; instance = dynamicControl; } else { instance = serializer.Deserialize(container.CreateReader()); } } } if (objectType == typeof(DynamicRow) && instance.GetType() != typeof(DynamicRow)) { var row = new DynamicRow(); row.Add(instance as DynamicItem); return(row); } return(instance); }
/// <summary> /// Connects to the DB and loads the results of a single dynamic statement described in <paramref name="args"/>. /// </summary> /// <param name="connString">The connection string of the SQL database from which to load the data.</param> /// <param name="args">All the information needed to connect to the database and execute the statement.</param> /// <param name="cancellation">The cancellation instruction.</param> /// <returns>The requested data packaged in a <see cref="DynamicOutput"/>.</returns> public async Task <DynamicOutput> LoadDynamic(string connString, DynamicLoaderArguments args, CancellationToken cancellation = default) { // Destructure the args var countSql = args.CountSql; var principalStatement = args.PrincipalStatement; var dimAncestorsStatements = args.DimensionAncestorsStatements ?? new List <SqlDimensionAncestorsStatement>(); var ps = args.Parameters; var vars = args.Variables; ////////////// Prepare the complete SQL code // Add any variables in the preparatory SQL string variablesSql = vars.ToSql(); var statements = new List <string>(1 + dimAncestorsStatements.Count) { principalStatement.Sql }; statements.AddRange(dimAncestorsStatements.Select(e => e.Sql)); string sql = PrepareSql( variablesSql: variablesSql, countSql: countSql, statements.ToArray()); // The result DynamicOutput result = null; try { using var trx = TransactionFactory.ReadCommitted(); await ExponentialBackoff(async() => { var rows = new List <DynamicRow>(); var trees = new List <DimensionAncestorsOutput>(); var count = 0; // Connection using var conn = new SqlConnection(connString); // Command Text using var cmd = conn.CreateCommand(); cmd.CommandTimeout = TimeoutInSeconds; cmd.CommandText = sql; // Parameters foreach (var parameter in ps) { cmd.Parameters.Add(parameter); } // Execute try // To capture { await conn.OpenAsync(cancellation); using var reader = await cmd.ExecuteReaderAsync(cancellation); // (1) Load the count if any if (!string.IsNullOrWhiteSpace(countSql)) { if (await reader.ReadAsync(cancellation)) { count = reader.GetInt32(0); } // Go over to the next result set await reader.NextResultAsync(cancellation); } // (2) Load results of the principal query { int columnCount = principalStatement.ColumnCount; while (await reader.ReadAsync(cancellation)) { var row = new DynamicRow(columnCount); for (int index = 0; index < columnCount; index++) { var dbValue = reader.Value(index); row.Add(dbValue); } rows.Add(row); } } // (3) Load the tree dimensions foreach (var treeStatement in dimAncestorsStatements) { int columnCount = treeStatement.TargetIndices.Count(); int index; int minIndex = treeStatement.TargetIndices.Min(); int[] targetIndices = treeStatement.TargetIndices.Select(i => i - minIndex).ToArray(); var treeResult = new DimensionAncestorsOutput ( idIndex: treeStatement.IdIndex, minIndex: minIndex, result: new List <DynamicRow>() ); await reader.NextResultAsync(cancellation); while (await reader.ReadAsync(cancellation)) { var row = new DynamicRow(columnCount); for (index = 0; index < targetIndices.Length; index++) { var dbValue = reader.Value(index); int targetIndex = targetIndices[index]; row.AddAt(dbValue, targetIndex); } treeResult.Result.Add(row); } trees.Add(treeResult); } } catch (SqlException ex) when(ex.Number is 8134) // Divide by zero { throw new QueryException(DivisionByZeroMessage); } finally { // Otherwise it will fail on retry cmd.Parameters.Clear(); } trx.Complete(); result = new DynamicOutput(rows, trees, count); }, cancellation); } catch (Exception ex) when(ex is not OperationCanceledException && ex is not ReportableException) { // Include the SQL and the parameters throw new StatementLoaderException(sql, ps, ex); } return(result); }