/// <summary> /// Identity stage II: update EdgeObject DB (staging) with edge object from Delivery DB /// using LOCK on EdgeObject table: /// * sync last changes according transform timestamp /// * update modified EdgeObjects --> IdentityStatus = Modified /// * insert new EdgeObjects --> IdentityStatus = New /// * find best match staging table /// * insert delivery metrics into staging metrics table /// </summary> public void UpdateEdgeObjects(SqlTransaction transaction) { // load object dependencies Dependencies = EdgeObjectConfigLoader.GetEdgeObjectDependencies(AccountId, _objectsSqlConnection).Values.ToList(); int maxDependecyDepth = Dependencies.Max(x => x.Depth); for (int i = 0; i <= maxDependecyDepth; i++) { var currentDepth = i; foreach (var field in Dependencies.Where(x => x.Depth == currentDepth)) { UpdateObjectDependencies(field.Field); if (DeliveryContainsChanges(field.Field.FieldEdgeType, IdentityStatus.Unchanged, true)) { SyncLastChangesWithLock(field.Field.FieldEdgeType); if (DeliveryContainsChanges(field.Field.FieldEdgeType, IdentityStatus.Modified)) { UpdateExistingEdgeObjectsByDelivery(field.Field.FieldEdgeType); } if (DeliveryContainsChanges(field.Field.FieldEdgeType, IdentityStatus.New)) { InsertNewEdgeObjects(field.Field.FieldEdgeType); } } CreateTempGkTkTable4Field(field.Field); } } }
protected virtual void InitMappings() { if (Configuration.Parameters["AccountID"] != null) { int.TryParse(Configuration.Parameters["AccountID"].ToString(), out _accountId); } var store = new SqlPersistenceStore { ConnectionString = AppSettings.GetConnectionString(typeof(MetricsDeliveryManager), Consts.ConnectionStrings.Objects) }; var cache = new EntityCache(); // load definitions from DB using (var connection = store.ConnectThread() as SqlPersistenceConnection) { connection.Cache = cache; // TODO: temporary load edge types and fields using ConfigLoader, to replace by Cache Accounts = EdgeObjectConfigLoader.LoadAccounts(_accountId, connection.DbConnection); Channels = EdgeObjectConfigLoader.LoadChannels(connection.DbConnection); Measures = EdgeObjectConfigLoader.LoadMeasures(_accountId, connection.DbConnection); EdgeTypes = EdgeObjectConfigLoader.LoadEdgeTypes(_accountId, connection.DbConnection); EdgeFields = EdgeObjectConfigLoader.LoadEdgeFields(_accountId, EdgeTypes, connection.DbConnection); EdgeObjectConfigLoader.SetEdgeTypeEdgeFieldRelation(_accountId, EdgeTypes, EdgeFields, connection.DbConnection); //Accounts = Account.Get().ToDictionary(x => x.Name, x => x); //Channels = Channel.Get().ToDictionary(x => x.Name, x => x); //Measures = Measure.GetInstances(_accountId).ToDictionary(x => x.Name, x => x); //EdgeTypes = EdgeType.Get(Accounts.Where(x => x.Value.ID == _accountId).Select(x => x.Value).FirstOrDefault()).ToDictionary(x => x.Name, x => x); //EdgeFields = EdgeField.Get().ToList(); //EdgeFields = new List<EdgeField>(); //foreach (var field in EdgeTypes.Values.SelectMany(type => type.Fields.Where(field => !EdgeFields.Contains(field.Field)))) //{ // EdgeFields.Add(field.Field); //} } // Load mapping configuration AddExternalMethods(); Mappings.Compile(); // set full account info including parent accounts if (Delivery.Account != null && Accounts.Any(x => x.Value.ID == Delivery.Account.ID)) { Delivery.Account = Accounts.First(x => x.Value.ID == Delivery.Account.ID).Value; } }
/// <summary> /// Save current delivery metrics table structure to find best match Metrics table (Staging) /// </summary> /// <param name="flatObjectList"></param> private void SaveMetricsMetadata(IEnumerable <object> flatObjectList) { using (var cmd = new SqlCommand()) { cmd.Connection = _deliverySqlConnection; cmd.CommandText = "INSERT INTO DBO.MD_MetricsMetadata ([TableName], [EdgeFieldID], [EdgeFieldName], [EdgeTypeID], [MeasureName], [ParentFieldName]) " + "VALUES (@TableName, @EdgeFieldID, @EdgeFieldName, @EdgeTypeID, @MeasureName, @ParentFieldName)"; cmd.Parameters.Add(new SqlParameter("@TableName", TableName)); cmd.Parameters.Add(new SqlParameter("@EdgeFieldID", null)); cmd.Parameters.Add(new SqlParameter("@EdgeFieldName", null)); cmd.Parameters.Add(new SqlParameter("@EdgeTypeID", null)); cmd.Parameters.Add(new SqlParameter("@MeasureName", null)); cmd.Parameters.Add(new SqlParameter("@ParentFieldName", null)); foreach (var obj in flatObjectList) { var dimension = obj as ObjectDimension; if (dimension != null && dimension.Value is EdgeObject && dimension.Field != null) { if (dimension.Field.FieldEdgeType == null) { throw new Exception(String.Format("ieldEdgeType not set for field '{0}'", dimension.Field.Name)); } // GK field and all its childs if exist foreach (var childType in EdgeObjectConfigLoader.FindEdgeTypeInheritors(dimension.Field.FieldEdgeType, EdgeTypes)) { var fieldName = childType == dimension.Field.FieldEdgeType ? dimension.Field.Name : String.Format("{0}-{1}", dimension.Field.Name, childType.Name); cmd.Parameters["@EdgeFieldID"].Value = dimension.Field.FieldID; cmd.Parameters["@EdgeFieldName"].Value = String.Format("{0}_gk", fieldName); cmd.Parameters["@EdgeTypeID"].Value = childType.TypeID; cmd.Parameters["@MeasureName"].Value = DBNull.Value; cmd.Parameters["@ParentFieldName"].Value = String.Format("{0}_gk", dimension.Field.Name); cmd.ExecuteNonQuery(); } } else if (obj is KeyValuePair <Measure, double> ) { cmd.Parameters["@EdgeFieldID"].Value = DBNull.Value; cmd.Parameters["@EdgeFieldName"].Value = DBNull.Value; cmd.Parameters["@EdgeTypeID"].Value = DBNull.Value; cmd.Parameters["@MeasureName"].Value = ((KeyValuePair <Measure, double>)obj).Key.Name; cmd.Parameters["@ParentFieldName"].Value = DBNull.Value; cmd.ExecuteNonQuery(); } } } }
/// <summary> /// Identity stage I: update delivery objects with existing in EdgeObject DB object GKs /// tag Delivery objects by IdentityStatus (New, Modified or Unchanged) /// </summary> public void IdentifyDeliveryObjects() { // load object dependencies Dependencies = EdgeObjectConfigLoader.GetEdgeObjectDependencies(AccountId, _objectsSqlConnection).Values.ToList(); int maxDependecyDepth = Dependencies.Max(x => x.Depth); for (int i = 0; i <= maxDependecyDepth; i++) { var currentDepth = i; foreach (var field in Dependencies.Where(x => x.Depth == currentDepth)) { UpdateObjectDependencies(field.Field); var deliveryObjects = GetDeliveryObjects(field.Field.FieldEdgeType); if (deliveryObjects == null) { continue; } using (var selectEdgeObjectCommand = PrepareSelectEdgeObjectCommand(field.Field.FieldEdgeType)) using (var updateGkCommand = PrepareUpdateGkCommand(field)) { foreach (var deliveryObject in deliveryObjects) { SetDeliveryObjectByEdgeObject(deliveryObject, selectEdgeObjectCommand); // TODO: add log GK was found or not found // update delivery with GKs if GK was found by identity fields and set IdentityStatus accordingly (Modified or Unchanged) if (!String.IsNullOrEmpty(deliveryObject.GK)) { updateGkCommand.Parameters["@gk"].Value = deliveryObject.GK; updateGkCommand.Parameters["@tk"].Value = deliveryObject.TK; updateGkCommand.Parameters["@identityStatus"].Value = deliveryObject.IdentityStatus; updateGkCommand.ExecuteNonQuery(); } } CreateTempGkTkTable4Field(field.Field); } } } }
/// <summary> /// Insert new EdgeObjects, generate GK and update GK according to identity fields in Deliveru tables /// for later UpdateDependencies /// </summary> /// <param name="edgeType"></param> private void InsertNewEdgeObjects(EdgeType edgeType) { if (edgeType.Fields.Count == 0) { return; } var createfieldsStr = "GK BIGINT,"; var whereStr = "TYPEID=@typeId AND "; var outputStr = "INSERTED.GK,"; var fieldsStr = String.Format("LASTUPDATED,TYPEID,ACCOUNTID,{0}", edgeType.ClrType.IsSubclassOf(typeof(ChannelSpecificObject)) ? "CHANNELID," : String.Empty); foreach (var field in edgeType.Fields) { fieldsStr = String.Format("{0}{1},", fieldsStr, field.ColumnNameGK); if (field.IsIdentity) { createfieldsStr = String.Format("{0}{1} {2},", createfieldsStr, field.ColumnNameGK, EdgeObjectConfigLoader.GetDbFieldType(field)); whereStr = String.Format("{0}{2}.{1}=#TEMP.{1} AND ", whereStr, field.ColumnNameGK, GetDeliveryTableName(edgeType.TableName)); outputStr = String.Format("{0}INSERTED.{1},", outputStr, field.ColumnNameGK); } } fieldsStr = fieldsStr.Remove(fieldsStr.Length - 1, 1); createfieldsStr = createfieldsStr.Remove(createfieldsStr.Length - 1, 1); outputStr = outputStr.Remove(outputStr.Length - 1, 1); whereStr = whereStr.Remove(whereStr.Length - 5, 5); // in one command insert new EdgeObjects and update delivery objects with inserted GKs by TK- hope will work using (var cmd = new SqlCommand { Connection = _objectsSqlConnection }) { cmd.CommandText = String.Format(@"CREATE TABLE #TEMP ({0}) INSERT INTO {1} ({2}) OUTPUT {5} INTO #TEMP SELECT @{2} FROM {3} WHERE TYPEID=@typeId AND IDENTITYSTATUS=@newStatus; UPDATE {3} SET GK=#TEMP.GK, IDENTITYSTATUS=@unchangesStatus FROM #TEMP, {3} WHERE {4}" , createfieldsStr, edgeType.TableName, fieldsStr, GetDeliveryTableName(edgeType.TableName), whereStr, outputStr); cmd.Parameters.AddWithValue("@typeId", edgeType.TypeID); cmd.Parameters.AddWithValue("@lastUpdated", DateTime.Now); cmd.Parameters.AddWithValue("@newStatus", (int)IdentityStatus.New); cmd.Parameters.AddWithValue("@unchangesStatus", (int)IdentityStatus.Unchanged); cmd.ExecuteNonQuery(); } }