/// <summary> /// Обновляет кросс-таблицы для массивных свойств (collection, collection-membership, array) /// </summary> /// <param name="xs">Реализация XStorageConnection</param> /// <param name="datagram">датаграмма</param> protected void updateCrossTables(XStorageConnection xs, XDatagram datagram) { XDbStatementDispatcher disp = xs.CreateStatementDispatcher(); foreach (XStorageObjectToSave xobj in datagram.ObjectsToInsert) { updateCrossTablesForObject(xs, disp, xobj); } foreach (XStorageObjectToSave xobj in datagram.ObjectsToUpdate) { updateCrossTablesForObject(xs, disp, xobj); } disp.ExecutePendingStatementsAndReturnTotalRowsAffected(); }
/// <summary> /// Выполняет удаление в БД объектов в списке в порядке их следования в нем /// </summary> /// <param name="xs">Экземпляр XStorageConection</param> /// <param name="disp">Диспетчер запросов</param> /// <param name="aDelObjects">список объектов (типа ObjectToDelete), для которых надо выполнить delete в БД</param> protected virtual int doDelete(XStorageConnection xs, XDbStatementDispatcher disp, ICollection aDelObjects) { int nRowsAffected = 0; // количество удаленных записей bool bForcedMode = false; // признак форсированного удаления (есть хотя бы один объект с незаданным ts) string sTypeNamePrev = String.Empty; // наименование типа предыдущего объекта (в цикле) StringBuilder queryTextBuilder = new StringBuilder(); // построитель оператора delete if (aDelObjects.Count == 0) { return(0); } foreach (XStorageObjectToDelete obj in aDelObjects) { if (obj.TS == -1) { bForcedMode = true; } if (sTypeNamePrev != obj.ObjectType) { // объект нового типа (в т.ч. первый) if (queryTextBuilder.Length > 0) { disp.DispatchStatement(queryTextBuilder.ToString(), true); queryTextBuilder.Length = 0; } queryTextBuilder.AppendFormat("DELETE FROM {0} WHERE {1}={2}", xs.GetTableQName(obj.TypeInfo), // 0 xs.ArrangeSqlName("ObjectID"), // 1 xs.ArrangeSqlGuid(obj.ObjectID) // 2 ); // если для объекта задан TS, добавим условие на него if (obj.AnalyzeTS) { queryTextBuilder.AppendFormat(" AND {0}={1}", xs.ArrangeSqlName("ts"), obj.TS ); } } else { // еще один объект того же типа queryTextBuilder.AppendFormat(" OR {0}={1}", xs.ArrangeSqlName("ObjectID"), // 0 xs.ArrangeSqlGuid(obj.ObjectID) // 1 ); // если для объекта задан TS, добавим условие на него if (obj.AnalyzeTS) { queryTextBuilder.AppendFormat(" AND {0}={1}", xs.ArrangeSqlName("ts"), obj.TS ); } } sTypeNamePrev = obj.ObjectType; } if (queryTextBuilder.Length > 0) { disp.DispatchStatement(queryTextBuilder.ToString(), true); } nRowsAffected = disp.ExecutePendingStatementsAndReturnTotalRowsAffected(); if (!bForcedMode) { if (nRowsAffected != aDelObjects.Count) { // количество удаленных объектов не совпадает с ожидаемым кол-вом. // если в БД остался хотя бы один объект из тех, которые мы удалили, то // это означает, что у него "устарел" ts, следовательно будем ругаться. // Иначе (в БД нет ниодного объект из тех, которые мы удаляли) все хорошо, просто // нас кто-то опередил, но главное результат - все требуемые объекты удалены. sTypeNamePrev = String.Empty; queryTextBuilder = new StringBuilder(); XDbCommand cmd = xs.CreateCommand(); cmd.CommandType = CommandType.Text; foreach (XStorageObjectToDelete obj in aDelObjects) { if (sTypeNamePrev != obj.ObjectType) { // объект нового типа (в т.ч. первый) if (queryTextBuilder.Length > 0) { cmd.CommandText = queryTextBuilder.ToString(); if (Convert.ToInt32(cmd.ExecuteScalar()) > 0) { throw new XOutdatedTimestampException(); } queryTextBuilder.Length = 0; } queryTextBuilder.AppendFormat("SELECT COUNT(1) FROM {0} WHERE {1}={2}", xs.GetTableQName(obj.TypeInfo), // 0 xs.ArrangeSqlName("ObjectID"), // 1 xs.ArrangeSqlGuid(obj.ObjectID) // 2 ); } else { // еще один объект того же типа queryTextBuilder.AppendFormat(" OR {0}={1}", xs.ArrangeSqlName("ObjectID"), // 0 xs.ArrangeSqlGuid(obj.ObjectID) // 1 ); } sTypeNamePrev = obj.ObjectType; } cmd.CommandText = queryTextBuilder.ToString(); if (Convert.ToInt32(cmd.ExecuteScalar()) > 0) { throw new XOutdatedTimestampException(); } } } return(nRowsAffected); }