/// <summary> /// Save monitoring data /// </summary> /// <param name="obj">Object instance</param> /// <returns>True if successfull</returns> public bool Save(TableMonitorData obj) { obj.UpdateDateTime = DateTime.Now; return(repository.Save(obj)); }
/// <summary> /// Process data /// </summary> /// <param name="data">Data to process</param> public void Process(TableMonitorData data) { if (data == null) { throw new ArgumentNullException(nameof(data)); } // primary keys var primaryKeyNames = new List <string>(); var columns = new List <string>(); if (string.IsNullOrWhiteSpace(data.ConnectionStringName)) { data.ConnectionStringName = "default"; } sqlService.OpenConnection((connection) => { primaryKeyNames = connection.Query <string>("SELECT cname FROM sys.syscolumns WHERE in_primary_key = 'Y' AND tname = :tableName ORDER BY cname", new { tableName = data.TableName }).ToList(); if (!string.IsNullOrWhiteSpace(data.PrimaryKeys)) { primaryKeyNames.AddRange(data.PrimaryKeys.Split(new[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim())); } // Assert primary columns if (!primaryKeyNames.Any()) { throw new Exception($"The table {data.TableName} has no primary columns."); } columns = connection.Query <string>("SELECT cname FROM sys.syscolumns WHERE tname = :tableName ORDER BY cname", new { tableName = data.TableName }).ToList(); foreach (var nonePrimaryKey in primaryKeyNames) { Console.WriteLine($"Primary key: {nonePrimaryKey}"); } var statement = $"SELECT string({string.Join(",", WrapInQuotes(primaryKeyNames))}) as primary_key_column, {string.Join(",", WrapInQuotes(columns))} FROM {data.TableName} ORDER BY {string.Join(",", WrapInQuotes(primaryKeyNames))}"; int counter = 0; try { var enumerator = connection.Query(statement); Console.WriteLine($"TableMonitor statement: {statement}"); foreach (var dapperRow in enumerator.Select(x => (IDictionary <string, object>)x)) { counter++; if (counter % 100 == 0) { Console.WriteLine($"Processed {data.TableName} data: {counter}"); } // Get and remove pk var primaryKey = dapperRow["primary_key_column"]?.ToString(); dapperRow.Remove("primary_key_column"); // Generate hash var hash = GenerateHash(dapperRow); // Find row in existing data var existingData = data.Row.FirstOrDefault(x => x.PrimaryKey == primaryKey); // Data not found if (existingData == null) { // Filter primary keys var rowCopy = new Dictionary <string, object>(dapperRow); var row = dapperRow.Where(x => primaryKeyNames.Any(y => y.ToLower() == x.Key.ToLower())).ToDictionary(y => y.Key, v => v.Value); existingData = new TableMonitorDataRow { Hash = hash, Updated = true, PrimaryKey = primaryKey, // Set row containting only pks Row = row }; // Invoke event. All columns must be included here DataAdded?.Invoke(this, new AffectedRowEventArgs { TableName = data.TableName, Row = rowCopy }); // Add data data.Row.Add(existingData); } // Data changed else if (hash != existingData.Hash) { // Filter primary keys var rowCopy = new Dictionary <string, object>(dapperRow); existingData.Hash = hash; existingData.Updated = true; // Invoke event. All columns must be included here DataChanged?.Invoke(this, new AffectedRowEventArgs { TableName = data.TableName, Row = rowCopy }); } else { existingData.Updated = true; } } Console.WriteLine($"Processed {data.TableName} data: {counter}"); // Create copy of rows foreach (var removedData in data.Row.Where(x => !x.Updated)) { counter++; if (counter % 100 == 0) { Console.WriteLine($"Processed {data.TableName} data: {counter}"); } // Invoke remove event DataRemoved?.Invoke(this, new AffectedRowEventArgs { TableName = data.TableName, Row = removedData.Row }); } Console.WriteLine($"Processed {data.TableName} data: {counter}"); // Just add updated rows data.Row = data.Row.Where(x => x.Updated).ToList(); } catch (Exception ex) { var message = $"Could not process data. Query-Statement: {statement}.\r\nFailed row: {counter}.\r\nPrimary keys: {string.Join(",", primaryKeyNames)}.\r\nColumns: {string.Join(",", columns)}"; LogManagerInstance.Instance.Error($"Error in TableMonitorService.Process\r\n{message}"); throw new Exception(message, ex); } }, data.ConnectionStringName); }
/// <summary> /// Remove data /// </summary> /// <param name="obj">Data instance</param> /// <returns>True if successfull</returns> public bool Delete(TableMonitorData obj) { return(repository.Delete(obj)); }