/// <summary> /// Executes the changeset. Operation is persisting changes to database. /// </summary> /// <param name="changeset">The changeset that is persisted.</param> public override void ExecuteChangeset(DBXml changeset) { if (this.executionMode == 1) { repository.ExecuteOperations(changeset); } else { DBXml xml = new DBXml(); DBTable tab = xml.AddTable(this.MainObjectTag); foreach (var valuation in changeset.Table(this.MainObjectTag).Rows) { Guid?savepointName = null; var row = tab.AddRow(valuation); try { savepointName = Guid.NewGuid(); this.repository.CreateSavepoint(savepointName.ToString()); repository.ExecuteOperations(xml); } catch (SqlException) { if (savepointName.HasValue) { this.repository.RollbackToSavepoint(savepointName.ToString()); } } row.Remove(); } } }
/// <summary> /// Executes the changeset. Operation is persisting changes to database. /// </summary> /// <param name="changeset">The changeset that is persisted.</param> public override void ExecuteChangeset(Makolab.Fractus.Communication.DBLayer.DBXml changeset) { //remove valuations that link to lines marked as deleted if (changeset.Table("warehouseDocumentValuation") != null && changeset.Table("warehouseDocumentLine") != null) { List <DBRow> deletedValuations = new List <DBRow>(); foreach (var line in changeset.Table("warehouseDocumentLine").Rows.Where(l => l.Action == DBRowState.Delete)) { foreach (var valuation in changeset.Table("warehouseDocumentValuation").Rows) { if (valuation.Element("incomeWarehouseDocumentLineId").Value.Equals(line.Element("id").Value, StringComparison.OrdinalIgnoreCase) || valuation.Element("outcomeWarehouseDocumentLineId").Value.Equals(line.Element("id").Value, StringComparison.OrdinalIgnoreCase)) { deletedValuations.Add(valuation); } } } deletedValuations.ForEach(v => v.Remove()); } //TODO kod dodany by wykorzystywac mechanizm savepointow, ale dziwia warunki na korekte pz/wz //TODO nalezy sprawdzi czy zmiana wycen rusza wersje obiektu glownego bo wyglda na to ze nie var docType = Makolab.Fractus.Kernel.Mappers.DictionaryMapper.Instance.GetDocumentType( new Guid(this.CurrentPackage.Table(this.MainObjectTag).FirstRow().Element("documentTypeId").Value)); if ((docType.DocumentCategory == Makolab.Fractus.Kernel.Enums.DocumentCategory.IncomeWarehouseCorrection || docType.DocumentCategory == Makolab.Fractus.Kernel.Enums.DocumentCategory.OutcomeWarehouseCorrection) && changeset.Table("warehouseDocumentValuation") != null) { var warehouseValuationTable = changeset.Table("warehouseDocumentValuation"); warehouseValuationTable.Remove(); DBXml valuationXml = new DBXml(); valuationXml.AddTable(warehouseValuationTable); this.Repository.ExecuteOperations(changeset); WarehouseDocumentValuation valuationProcessor = new WarehouseDocumentValuation(this.UnitOfWork, this.ExecutionController, this.IsHeadquarter); valuationProcessor.Log = this.Log; valuationProcessor.LocalTransactionId = this.LocalTransactionId; CommunicationPackage valuationPackage = new CommunicationPackage(new XmlTransferObject() { Content = valuationXml.Xml.ToString(SaveOptions.DisableFormatting) }); valuationPackage.DatabaseId = this.package.DatabaseId; valuationPackage.XmlData.LocalTransactionId = this.package.XmlData.LocalTransactionId; valuationPackage.XmlData.DeferredTransactionId = this.package.XmlData.DeferredTransactionId; valuationProcessor.ExecutePackage(valuationPackage, 0); } else { this.Repository.ExecuteOperations(changeset); } }
/// <summary> /// Process communication package persisting it's data to database. /// </summary> /// <param name="communicationPackage">The communication package to execute.</param> /// <returns> /// <c>true</c> if execution succeeded; otherwise, <c>false</c> /// </returns> public override bool ExecutePackage(ICommunicationPackage communicationPackage) { SessionManager.VolatileElements.DeferredTransactionId = communicationPackage.XmlData.DeferredTransactionId; SessionManager.VolatileElements.LocalTransactionId = this.LocalTransactionId; this.CurrentPackage = new DBXml(XDocument.Parse(communicationPackage.XmlData.Content)); //Guid mainObjectId = new Guid(this.CurrentPackage.Table(MainObjectTag).Row().Element("id").Value); //DBXml dbSnapshot = GetCurrentSnapshot(mainObjectId); DBXml dbSnapshot = new DBXml(); Guid currentConGrMemId = Guid.Empty; var dbTables = new List <DBTable>(); try { var groupsAlreadyRemoved = new List <DBRow>(); foreach (var conGrMem in this.CurrentPackage.Table(MainObjectTag).Rows) { currentConGrMemId = new Guid(conGrMem.Element("id").Value); DBXml currentDBSnapshot = GetCurrentSnapshot(currentConGrMemId); if (conGrMem.Action == DBRowState.Delete && currentDBSnapshot == null) { groupsAlreadyRemoved.Add(conGrMem); } // TODO conflict detection & resolution //if (ValidateVersion(conGrMem, currentDBSnapshot) == false) //{ // throw new ConflictException("Conflict detected while changing " + this.MainObjectTag + " id: " + currentConGrMemId); //} if (conGrMem.Element("_object1from") != null) { DBXml contractor = repository.FindContractorSnapshot(new Guid(conGrMem.Element("contractorId").Value)); if (contractor != null && contractor.Table("contractor").FirstRow().Element("version").Value.Equals(conGrMem.Element("_object1from").Value) == false) { this.Log.Error("ItemGroupMembershipScript: Wystapil konflikt wersji towaru " + conGrMem.Element("contractorId").Value + " oczekiwano " + conGrMem.Element("_object1from").Value + " otrzymano " + contractor.Table("contractor").FirstRow().Element("version").Value); conGrMem.Element("_object1from").Value = contractor.Table("contractor").FirstRow().Element("version").Value; } } if (currentDBSnapshot != null) { dbTables.Add(currentDBSnapshot.Table(this.MainObjectTag)); } } dbSnapshot.AddTable(dbTables); DBXml changeset = GenerateChangeset(CurrentPackage, dbSnapshot); ExecuteChangeset(changeset); } catch (SqlException e) { if (e.Number == 50012) // Conflict detection { throw new ConflictException("Conflict detected while changing " + this.MainObjectTag + " id: " + currentConGrMemId.ToString()); } else { this.Log.Error("SnapshotScript:ExecutePackage " + e.ToString()); return(false); } } return(true); }
/// <summary> /// Generates the changeset - diff beetween two snapshots. /// </summary> /// <param name="commSnapshot">The snapshot from other branch.</param> /// <param name="dbSnapshot">The snapshot created from database.</param> /// <returns>Generated xml changeset.</returns> public virtual DBXml GenerateChangeset(DBXml commSnapshot, DBXml dbSnapshot) { DBXml result = new DBXml(commSnapshot); Dictionary <string, string> previousVersion = GetPreviousVersion(result); RemovePreviousVersion(result); IEnumerable <DBRow> resultEntries = result.Tables.SelectMany(table => table.Rows); if (dbSnapshot == null) { var eTables = new List <DBTable>(); foreach (var table in result.Tables) { if (table.HasRows == false) { eTables.Add(table); } } foreach (var table in eTables) { table.Remove(); } return(MarkAsInserted(resultEntries).First().Table.Document); } IEnumerable <DBRow> dbEntries = dbSnapshot.Tables.SelectMany(table => table.Rows).Where(row => row.HasAction == false); List <DBRow> unmodifiedEntries = new List <DBRow>(); foreach (DBRow entry in resultEntries) { DBRow match = dbSnapshot.FindRow(entry); if (match != null) { //entry.Action != DBRowState.Delete - niestety musialem dolozyc ten warunek gdyz ciezko jest dogadac sie z chlopakami // by entry przy delete tez zawieraly wersje if (entry.Action != DBRowState.Delete && entry.IsTheSameAs(match)) { if (entry.Action == null) { unmodifiedEntries.Add(entry); } else if (entry.Action == DBRowState.Insert) { entry.SetAction(DBRowState.Update); } } else if (entry.Action == null) { entry.Element("version").Name = "_version"; entry.SetAction(DBRowState.Update); } match.Remove(); } else if (entry.Action == null) { entry.SetAction(DBRowState.Insert); } } if (previousVersion != null) // && result.Table(MainObjectTag).FirstRow().Element("version") == null { SetPreviousVersion(result, previousVersion); //result.Table(MainObjectTag).FirstRow().AddElement("version", previousVersion); } // remove unmodified entries from result unmodifiedEntries.ForEach(entry => entry.Remove()); foreach (DBRow entry in dbEntries) { entry.SetAction(DBRowState.Delete); } result.AddTable(from table in dbSnapshot.Tables where table.HasRows select table); var emptyTables = new List <DBTable>(); foreach (var table in result.Tables) { if (table.HasRows == false) { emptyTables.Add(table); } } foreach (var table in emptyTables) { table.Remove(); } return(result); }
/// <summary> /// Process communication package persisting it's data to database. /// </summary> /// <param name="communicationPackage">The communication package to execute.</param> /// <returns> /// <c>true</c> if execution succeeded; otherwise, <c>false</c> /// </returns> public override bool ExecutePackage(ICommunicationPackage communicationPackage) { try { SessionManager.VolatileElements.DeferredTransactionId = communicationPackage.XmlData.DeferredTransactionId; SessionManager.VolatileElements.LocalTransactionId = this.LocalTransactionId; bool result = base.ExecutePackage(communicationPackage); if (result == false) { return(false); } //skip local shift documents if (IsLocal(this.CurrentPackage) == true) { return(true); } using (var wrapper = this.UnitOfWork.ConnectionManager.SynchronizeConnection()) { SqlConnectionManager.Instance.SetConnection(wrapper.Connection, this.UnitOfWork.Transaction as SqlTransaction); } bool isOutcomeshift = IsOutcomeshift(this.CurrentPackage); bool isIncomeShift = IsIncomeshift(this.CurrentPackage); bool isTargetBranch = IsTargetBranch(this.CurrentPackage); bool isSourceBranch = IsSourceBranch(this.CurrentPackage); if (isOutcomeshift == true) { if (isTargetBranch == true) { if (this.IsHeadquarter == false) { DBXml series = new DBXml(); series.AddTable(this.CurrentPackage.Table("series")); SeriesScript seriesProcessor = new SeriesScript(this.UnitOfWork, this.ExecutionController); seriesProcessor.Log = this.Log; seriesProcessor.LocalTransactionId = this.LocalTransactionId; CommunicationPackage seriesPackage = new CommunicationPackage(new XmlTransferObject() { Content = series.Xml.ToString(SaveOptions.DisableFormatting) }); seriesPackage.DatabaseId = communicationPackage.DatabaseId; seriesPackage.XmlData.LocalTransactionId = communicationPackage.XmlData.LocalTransactionId; seriesPackage.XmlData.DeferredTransactionId = communicationPackage.XmlData.DeferredTransactionId; seriesProcessor.ExecutePackage(seriesPackage); } this.ExecutionController.ExecuteCommand(() => ExecuteOutcomeShift()); if (this.CurrentPackage.Xml.Root.Attribute("skipPackage") == null) { this.CurrentPackage.Xml.Root.Add(new XAttribute("skipPackage", true)); } } if (this.IsHeadquarter && isTargetBranch == false) { DBXml series = this.Repository.FindSeries(new Guid(this.CurrentPackage.Table("warehouseDocumentHeader").FirstRow().Element("seriesId").Value)); this.CurrentPackage.AddTable(series.Table("series")); } if (this.IsHeadquarter == false && isTargetBranch == false && isSourceBranch == false) { throw new InvalidOperationException("ShiftDocumentSnapshot is in invalid branch."); } } else if (isIncomeShift == true && this.IsHeadquarter == true && (isTargetBranch || IsNewOrChanged(this.CurrentPackage, this.previousDocument))) { this.ExecutionController.ExecuteCommand(() => ExecuteIncomeShift()); } communicationPackage.XmlData.Content = this.CurrentPackage.Xml.ToString(SaveOptions.DisableFormatting); return(result); } catch (SqlException e) { if (e.Number == 50012) // Conflict detection { throw new ConflictException("Conflict detected while changing " + this.MainObjectTag); } else { this.Log.Error("ShiftDocumentSnapshot:ExecutePackage " + e.ToString()); return(false); } } }