Example #1
0
        public void RefreshTableCache <T>() where T : DataEntity
        {
            TableCache.Remove(typeof(T));
            var table = _context.GetTable <T>();

            TableCache.Add(typeof(T), table);
        }
Example #2
0
        private void GetOrCreateTable <T>() where T : DataEntity
        {
            _context.CreateTableIfNotExists(new CreateTableArgs <T>(g => g.HashKey, g => g.Id));
            Stopwatch timer = Stopwatch.StartNew();

            try
            {
                _context.SubmitChanges();
                Logger.Trace($"{nameof(DynamoStore)}.{nameof(GetCachedTable)}<{typeof(T).Name}>",
                             new LogItem("Action", "Getting or Creating table"),
                             new LogItem("Type", typeof(T).ToString),
                             new LogItem("DurationMilliseconds", timer.Elapsed.TotalMilliseconds));
            }
            catch (Exception ex)
            {
                Logger.Error($"{nameof(DynamoStore)}.{nameof(GetCachedTable)}<{typeof(T).Name}>",
                             new LogItem("Action", "Failed to create table"),
                             new LogItem("Type", typeof(T).ToString),
                             new LogItem("Exception Message", ex.Message),
                             new LogItem("Stack Trace", ex.StackTrace),
                             new LogItem("DurationMilliseconds", timer.Elapsed.TotalMilliseconds));
                throw;
            }

            var table = _context.GetTable <T>();

            TableCache.Add(typeof(T), table);
        }
        public bool LoadCollection <C>() where C : UnifiedIMObject <C>
        {
            string collection = UnifiedCollectionAttribute.GetCollection <C>();

            if (string.IsNullOrEmpty(collection))
            {
                throw new Exception($"Missing UnifiedCollectionAttribute on type {typeof(C).Name}");
            }
            TableCache.Add(typeof(C), collection);
            ColumnCache.Add(typeof(C), ColumnProperty.GetCollumns <C>(MSSQLHelper.Instance, true, "ObjectID").Values.ToList());
            return(true);
        }
Example #4
0
        public static AzureTableContext <T> GetContext <T>(string tableName) where T : ITableEntity, new()
        {
            lock (TableCache) {
                if (!TableCache.ContainsKey(tableName))
                {
                    var context = new AzureTableContext <T>(GetAccount(), tableName);
                    TableCache.Add(tableName, context);
                    context.Create();
                }

                return(TableCache[tableName] as AzureTableContext <T>);
            }
        }
Example #5
0
        public void TableCache_UnitTests()
        {
            //set a cache with a max of 5 items.
            TableCache tableCache = new TableCache(5);

            //add less items that the max size to the cache.
            for (int i = 0; i < 4; i++)
            {
                tableCache.Add(new object[] { i });
            }

            Assert.True(tableCache.Count == 4);

            //test the items are added
            int count = 0;
            int index = 0;

            foreach (object[] row in tableCache)
            {
                Assert.Equal(count, (int)row[0]);                 //check enumerated result.
                Assert.Equal(count, (int)tableCache[index++][0]); //check indexed result
                count++;
            }

            Assert.Equal(4, index);

            //add another item so that the cache = maxsize.
            tableCache.Add(new object[] { 4 });

            Assert.Equal(5, tableCache.Count);

            //test the items are added
            count = 0;
            index = 0;
            foreach (object[] row in tableCache)
            {
                Assert.Equal(count, (int)row[0]);
                Assert.Equal(count, (int)tableCache[index++][0]); //check indexed result
                count++;
            }

            Assert.Equal(5, index);

            //add another item so that the cache will be exceed.
            tableCache.Add(new object[] { 5 });

            //table cound should be 5 as this is the max.
            Assert.Equal(5, tableCache.Count);
            //test the items are added starting the count at 1
            count = 1;
            index = 0;
            foreach (object[] row in tableCache)
            {
                Assert.Equal(count, (int)row[0]);
                Assert.Equal(count, (int)tableCache[index++][0]); //check indexed result
                count++;
            }

            Assert.Equal(5, index);

            //add one more items to be sure
            tableCache.Add(new object[] { 6 });

            //table cound should be 5 as this is the max.
            Assert.Equal(5, tableCache.Count);

            //test the items are added starting the count at 1
            count = 2;
            index = 0;
            foreach (object[] row in tableCache)
            {
                Assert.Equal(count, (int)row[0]);
                Assert.Equal(count, (int)tableCache[index++][0]); //check indexed result
                count++;
            }

            Assert.Equal(5, index);


            //run a test with rows = 0 (which means no unlimited cache)
            //set a cache with a max of 5 items.
            tableCache = new TableCache();

            //add less items that the max size to the cache.
            for (int i = 0; i < 4; i++)
            {
                tableCache.Add(new object[] { i });
            }

            Assert.True(tableCache.Count == 4);

            //test the items are added
            count = 0;
            index = 0;
            foreach (object[] row in tableCache)
            {
                Assert.Equal(count, (int)row[0]);                 //check enumerated result.
                Assert.Equal(count, (int)tableCache[index++][0]); //check indexed result
                count++;
            }
        }
 public void Add(object[] values)
 {
     _data.Add(values);
 }
Example #7
0
        /// <summary>
        /// Runs the datalink test and returns the results
        /// </summary>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        /// <exception cref="DatalinkTestRunException"></exception>
        public async Task <List <TestResult> > Run(CancellationToken cancellationToken)
        {
            try
            {
                var ct = CancellationTokenSource.CreateLinkedTokenSource(_cancellationTokenSource.Token,
                                                                         cancellationToken);

                var token = ct.Token;
                token.ThrowIfCancellationRequested();

                var tempTargetTableKey = -10000;

                WriterResult.SetRunStatus(TransformWriterResult.ERunStatus.Started, null, null);

                var passed = 0;
                var failed = 0;

                foreach (var step in _datalinkTest.DexihDatalinkTestSteps.OrderBy(c => c.Position).Where(c => c.IsValid))
                {
                    var datalink = _hub.DexihDatalinks.SingleOrDefault(c => c.IsValid && c.Key == step.DatalinkKey);

                    if (datalink == null)
                    {
                        throw new DatalinkTestRunException($"The datalink test {_datalinkTest.Name} failed as the datalink with the key {step.DatalinkKey} could not be found.");
                    }

                    UpdateProgress(1);

                    // prepare all the relevant tables
                    foreach (var testTable in step.DexihDatalinkTestTables)
                    {
                        await PrepareTestTable(testTable, token);
                    }

                    UpdateProgress(2);

                    datalink.AuditConnectionKey = _datalinkTest.AuditConnectionKey;

                    var dexihTargetConnection = _hub.DexihConnections.Single(c => c.IsValid && c.Key == step.TargetConnectionKey);
                    ICollection <DexihTable> targetTables;

                    // add a target table to store the data when the datalink doesn't have one.
                    if (!datalink.DexihDatalinkTargets.Any())
                    {
                        var target = new DexihDatalinkTarget()
                        {
                            TableKey = tempTargetTableKey--,
                        };

                        datalink.DexihDatalinkTargets.Add(target);
                        datalink.UpdateStrategy = EUpdateStrategy.Reload;
                        datalink.LoadStrategy   = TransformWriterTarget.ETransformWriterMethod.Bulk;

                        // var targetTable = datalink.GetOutputTable();
                        var table = new DexihTable()
                        {
                            Key = target.TableKey,
                            DexihTableColumns = datalink.GetOutputTable().DexihDatalinkColumns
                                                .Select(c => c.CloneProperties <DexihTableColumn>()).ToArray()
                        };

                        // dexihTargetConnection.DexihTables.Add(table);
                        targetTables = new List <DexihTable> {
                            table
                        };
                    }
                    else
                    {
                        targetTables = datalink.DexihDatalinkTargets.Select(c => _hub.GetTableFromKey(c.TableKey)).ToList();
                    }

                    if (targetTables.Count > 1)
                    {
                        throw new DatalinkTestRunException("Currently datalink tests can only be used with datalinks containing no more than one target table.");
                    }

                    foreach (var table in targetTables)
                    {
                        table.ConnectionKey = dexihTargetConnection.Key;
                        table.Name          = step.TargetTableName;
                        table.Schema        = step.TargetSchema;
                    }

                    UpdateProgress(50);

                    // run the datalink
                    var datalinkRun = new DatalinkRun(_transformSettings, _logger, WriterResult.AuditKey, datalink, _hub, null, _transformWriterOptions, _alertQueue, _alertEmails);
                    datalinkRun.WriterTarget.WriterResult.AuditType    = "DatalinkTestStep";
                    datalinkRun.WriterTarget.WriterResult.ReferenceKey = step.Key;

                    // await datalinkRun.Initialize(cancellationToken);
                    await datalinkRun.Build(token);

                    await datalinkRun.Run(token);

                    UpdateProgress(70);

                    foreach (var table in targetTables)
                    {
                        var testResult = new TestResult()
                        {
                            Name        = step.Name,
                            StartDate   = DateTime.Now,
                            TestStepKey = step.Key
                        };

                        var dexihExpectedConnection = _hub.DexihConnections.Single(c => c.IsValid && c.Key == step.ExpectedConnectionKey);
                        var dexihExpectedTable      = table.CloneProperties();
                        dexihExpectedTable.ConnectionKey = dexihExpectedConnection.Key;
                        dexihExpectedTable.Name          = step.ExpectedTableName;
                        dexihExpectedTable.Schema        = step.ExpectedSchema;

                        var expectedConnection = dexihExpectedConnection.GetConnection(_transformSettings);
                        var expectedTable      = dexihExpectedTable.GetTable(_hub, expectedConnection, _transformSettings);
                        var expectedTransform  = expectedConnection.GetTransformReader(expectedTable);

                        var targetConnection = dexihTargetConnection.GetConnection(_transformSettings);
                        var targetTable      = table.GetTable(_hub, targetConnection, _transformSettings);
                        var targetTransform  = targetConnection.GetTransformReader(targetTable);

                        // the error table is used to store any rows which do not match.
                        var        dexihErrorConnection = _hub.DexihConnections.SingleOrDefault(c => c.IsValid && c.Key == step.ErrorConnectionKey);
                        Connection errorConnection      = null;
                        Table      errorTable           = null;
                        if (dexihErrorConnection != null)
                        {
                            var dexihErrorTable = table.CloneProperties();
                            dexihErrorTable.ConnectionKey = dexihErrorConnection.Key;
                            dexihErrorTable.Name          = step.ErrorTableName;
                            dexihErrorTable.Schema        = step.ErrorSchema;
                            errorConnection = dexihErrorConnection.GetConnection(_transformSettings);
                            errorTable      = dexihErrorTable.GetTable(_hub, errorConnection, _transformSettings);

                            foreach (var column in errorTable.Columns)
                            {
                                column.DeltaType = EDeltaType.NonTrackingField;
                            }

                            errorTable.Columns.Add(new TableColumn("error_audit_key", ETypeCode.Int64,
                                                                   EDeltaType.CreateAuditKey));
                            errorTable.Columns.Add(new TableColumn("error_operation", ETypeCode.CharArray,
                                                                   EDeltaType.DatabaseOperation)
                            {
                                MaxLength = 1
                            });
                            errorTable.Columns.Add(new TableColumn("mismatch_reason", ETypeCode.String,
                                                                   EDeltaType.UpdateReason)
                            {
                                AllowDbNull = true
                            });
                        }

                        // use the delta transform to compare expected and target tables.
                        await using var delta = new TransformDelta(targetTransform, expectedTransform,
                                                                   EUpdateStrategy.AppendUpdateDelete, 0, false, true);
                        await delta.Open(0, null, token);

                        testResult.RowsMismatching       = 0;
                        testResult.RowsMissingFromSource = 0;
                        testResult.RowsMissingFromTarget = 0;

                        var operationColumn    = delta.CacheTable.Columns.GetOrdinal(EDeltaType.DatabaseOperation);
                        var updateReasonColumn = delta.CacheTable.Columns.GetOrdinal(EDeltaType.UpdateReason);

                        var errorCache = new TableCache();

                        // loop through the delta.  any rows which don't match on source/target should filter through, others will be ignored.
                        while (await delta.ReadAsync(token))
                        {
                            testResult.TestPassed = false;
                            switch (delta[operationColumn])
                            {
                            case 'C':
                                testResult.RowsMissingFromTarget++;
                                break;

                            case 'U':
                                testResult.RowsMismatching++;
                                break;

                            case 'D':
                                testResult.RowsMissingFromSource++;
                                break;
                            }
                            datalinkRun.WriterTarget.WriterResult.Failed++;
                            WriterResult.Failed++;
                            WriterResult.IncrementRowsCreated();

                            if (errorTable != null && errorCache.Count < MaxErrorRows)
                            {
                                var row = new object[errorTable.Columns.Count];

                                for (var i = 0; i < errorTable.Columns.Count; i++)
                                {
                                    var column = errorTable[i];
                                    switch (column.DeltaType)
                                    {
                                    case EDeltaType.CreateAuditKey:
                                        row[i] = datalinkRun.WriterTarget.WriterResult.AuditKey;
                                        break;

                                    case EDeltaType.DatabaseOperation:
                                        row[i] = delta[operationColumn];
                                        break;

                                    case EDeltaType.UpdateReason:
                                        row[i] = delta[updateReasonColumn];
                                        break;

                                    default:
                                        row[i] = delta[column.Name];
                                        break;
                                    }
                                }

                                errorCache.Add(row);
                            }
                        }

                        if (errorCache.Count > 0)
                        {
                            errorTable.Data = errorCache;
                            var createReader = new ReaderMemory(errorTable);

                            if (!await errorConnection.TableExists(errorTable, cancellationToken))
                            {
                                await errorConnection.CreateTable(errorTable, false, cancellationToken);
                            }

                            await errorConnection.ExecuteInsertBulk(errorTable, createReader, cancellationToken);
                        }

                        WriterResult.RowsIgnored   += delta.TotalRowsIgnored;
                        WriterResult.RowsPreserved += delta.TotalRowsPreserved;

                        if (testResult.TestPassed == false)
                        {
                            failed++;
                        }
                        else
                        {
                            passed++;
                        }

                        if (datalinkRun.WriterTarget.WriterResult.RunStatus == TransformWriterResult.ERunStatus.Finished)
                        {
                            if (testResult.TestPassed)
                            {
                                datalinkRun.WriterTarget.WriterResult.SetRunStatus(TransformWriterResult.ERunStatus.Passed, "Datalink test passed", null);
                            }
                            else
                            {
                                datalinkRun.WriterTarget.WriterResult.SetRunStatus(TransformWriterResult.ERunStatus.Failed, $"Datalink test failed, {testResult.RowsMissingFromSource} rows missing from expected, {testResult.RowsMissingFromTarget} rows missing from actual, {testResult.RowsMismatching} rows with mismatching columns.", null);
                            }
                        }

                        TestResults.Add(testResult);
                    }
                }

                if (WriterResult.Failed > 0)
                {
                    WriterResult.SetRunStatus(TransformWriterResult.ERunStatus.Failed, $"{passed} tests passed, {failed} test failed.", null);
                }
                else
                {
                    WriterResult.SetRunStatus(TransformWriterResult.ERunStatus.Passed, $"{passed} tests passed.", null);
                }

                await WriterResult.CompleteDatabaseWrites();

                return(TestResults);
            }
            catch (Exception ex)
            {
                WriterResult.SetRunStatus(TransformWriterResult.ERunStatus.Abended, ex.Message, ex);
                return(TestResults);
            }
        }
Example #8
0
        public async Task WriteRecord(TransformWriterResult writerResult, Transform reader)
        {
            if (_writeOpen == false)
            {
                throw new TransformWriterException($"Transform write failed to write record as the WriteStart has not been called.");
            }

            //split the operation field (if it exists) and create copy of the row.
            char operation;

            //determine the type of operation (create, update, delete, reject)
            if (_operationColumnIndex == -1)
            {
                operation = 'C';
            }
            else
            {
                operation = (char)reader[_operationColumnIndex];
            }

            Table table;
            var   ordinals = _fieldOrdinals;

            if (operation == 'R')
            {
                table    = _rejectTable;
                ordinals = _rejectFieldOrdinals;
                if (_rejectTable == null)
                {
                    var rejectColumn = reader.GetOrdinal("RejectedReason");
                    var rejectReason = "";
                    if (rejectColumn > 0)
                    {
                        rejectReason = reader[rejectColumn].ToString();
                    }
                    else
                    {
                        rejectReason = "No reject reason found.";
                    }

                    throw new TransformWriterException($"Transform write failed as a record was rejected, however there is no reject table set.  The reject reason was: {rejectReason}.");
                }
            }
            else
            {
                table = _targetTable;
            }

            var columnCount = table.Columns.Count;

            var row = new object[columnCount];

            for (var i = 0; i < columnCount; i++)
            {
                //int ordinal = reader.GetOrdinal(table.Columns[i].ColumnName);
                var ordinal = ordinals[i];
                if (ordinal >= 0)
                {
                    row[i] = reader[ordinal];
                }
            }

            switch (operation)
            {
            case 'C':
                _createRows.Add(row);
                writerResult.IncrementRowsCreated();
                if (_createRows.Count >= CommitSize)
                {
                    await DoCreates();

                    return;
                }
                break;

            case 'U':
                _updateRows.Add(row);
                writerResult.IncrementRowsUpdated();
                if (_updateRows.Count >= CommitSize)
                {
                    await DoUpdate();

                    return;
                }
                break;

            case 'D':
                _deleteRows.Add(row);
                writerResult.IncrementRowsDeleted();
                if (_deleteRows.Count >= CommitSize)
                {
                    await DoDelete();

                    return;
                }
                break;

            case 'R':
                _rejectRows.Add(row);
                if (_rejectRows.Count >= CommitSize)
                {
                    await DoReject();

                    return;
                }
                break;

            case 'T':
                if (!_targetConnection.DynamicTableCreation)
                {
                    await _targetConnection.TruncateTable(_targetTable, _cancellationToken);
                }
                else
                {
                    return;
                }
                break;
            }

            return;
        }
        public bool LoadCollection <C>() where C : UnifiedIMObject <C>
        {
            string collection = UnifiedCollectionAttribute.GetCollection <C>();

            if (string.IsNullOrEmpty(collection))
            {
                throw new Exception($"Missing UnifiedCollectionAttribute on type {typeof(C).Name}");
            }
            TableCache.Add(typeof(C), collection);
            ColumnCache.Add(typeof(C), ColumnProperty.GetCollumns <C>(MySQLHelper.Instance, true, "ObjectID").Values.ToList());
            ColumnProperty objidcol = GetColumns <C>().FirstOrDefault(X => X.Name == "ObjectID");

            foreach (ColumnProperty prop in GetColumns <C>())
            {
                if (prop.Name == "ObjectID")
                {
                    prop.OverrideSqlType("char(32)");
                }
                else
                {
                    prop.OverrideSqlType(MySQLHelper.Instance.GetSqlType(prop.Type, prop.Column));
                }
            }

            if (!MySQLTable.GetTables(SQL).Contains(collection))
            {
                try
                {
                    MySQLTable.CreateTable(SQL, collection, GetColumns <C>());
                }
                catch (Exception ex)
                {
                    throw new Exception($"Failed to create table {collection}");
                }
            }
            else
            {
                MySQLTable            table = MySQLTable.GetTable(SQL, collection);
                List <ColumnProperty> todo  = table.Columns.ToList();
                foreach (ColumnProperty col in GetColumns <C>())
                {
                    ColumnProperty existing = table.Columns.FirstOrDefault(X => X.Name == col.Name);
                    if (existing == null)
                    {
                        System.Console.WriteLine($"SQL missing Column {col.Name}... Adding");
                        try
                        {
                            MySQLTable.AddColumn(SQL, collection, col.Name, col.SqlType);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception($"Failed to add collumn {col.Name}\n{ex.Message}");
                        }
                    }
                    else if (!existing.SqlType.StartsWith(col.SqlType))
                    {
                        System.Console.WriteLine($"SQL incorrect Column Type for {col.Name}... Converting");
                        try
                        {
                            MySQLTable.ConvertColumn(SQL, collection, col.Name, col.SqlType);
                        }
                        catch (Exception ex)
                        {
                            throw new Exception($"Failed to convert collumn {col.Name}\n{ex.Message}");
                        }
                    }
                    if (existing != null)
                    {
                        todo.Remove(existing);
                    }
                }
                foreach (ColumnProperty prop in todo)
                {
                    System.Console.WriteLine($"Excess collumn {prop.Name}... Removing");
                    try
                    {
                        MySQLTable.RemoveColumn(SQL, collection, prop.Name);
                    }
                    catch (Exception ex)
                    {
                        throw new Exception($"Failed to remove collumn {prop.Name}\n{ex.Message}");
                    }
                }
            }

            return(true);
        }