Exemplo n.º 1
0
        /// <summary>
        /// Запускает сохранение в рамках текущей трпнзакции.
        /// </summary>
        /// <param name="xs">Реализация XStorageConnection</param>
        /// <param name="datagram">множество объектов</param>
        protected void saveWithinTransaction(XStorageConnection xs, XDatagram datagram)
        {
            const string SAVEPOINT_NAME = "SP_XStorage_Save";
            bool         bSavePointUsed = xs.IsSavePointAllowed;

            if (bSavePointUsed)
            {
                xs.SetSavePoint(SAVEPOINT_NAME);
            }
            try
            {
                DoSave(xs, datagram);
                if (bSavePointUsed)
                {
                    xs.ReleaseSavePoint();
                }
            }
            catch (XDbDeadlockException)
            {
                // если произошел Dealock, то не будем пытаться откатить транзакцию, т.к. она уже не существует
                throw;
            }
            catch
            {
                if (bSavePointUsed)
                {
                    xs.RollbackToSavePoint();
                }
                throw;
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Сохранение данных множества объектов.
        /// </summary>
        /// <remarks>
        /// Управление транзакцией внешнее.
        /// </remarks>
        /// <param name="context"></param>
        /// <param name="dataSet"></param>
        /// <param name="transactionID"></param>
        public static void Save(IXExecutionContext context, DomainObjectDataSet dataSet, Guid transactionID)
        {
            // #1: Вызов триггеров Before
            XTriggersController.Instance.FireTriggers(dataSet, XTriggerFireTimes.Before, context);

            // #2: Сбросим закэшированные данные объектов
            IEnumerator enumerator = dataSet.GetModifiedObjectsEnumerator(false);

            while (enumerator.MoveNext())
            {
                DomainObjectData xobj = (DomainObjectData)enumerator.Current;
                // Примечание: для новых объектов сбрасывать кэш бессмысленно - их там нет
                if (!xobj.IsNew)
                {
                    DomainObjectRegistry.ResetObject(xobj);
                }
            }

            // #3: Запись данных
            XDatagramProcessorEx dg_proc   = XDatagramProcessorMsSqlEx.Instance;
            XDatagramBuilder     dgBuilder = dg_proc.GetDatagramBuilder();
            XDatagram            dg        = dgBuilder.GetDatagram(dataSet);

            dg_proc.Save(context.Connection, dg);

            // #4: Сохранение chunked-данных
            saveChunkedData(transactionID, dg, context.Connection);

            // #5: Сигнализируем Securitymanager, что обновились данные (для очистки кэшей)
            XSecurityManager.Instance.TrackModifiedObjects(dataSet);

            // #6: Вызов триггеров After
            XTriggersController.Instance.FireTriggers(dataSet, XTriggerFireTimes.After, context);
        }
Exemplo n.º 3
0
        /// <summary>
        /// Формирует список устаревших и список удаленных объектов после неудачной процедуры обновления.
        /// Метод должен вызываться в рамках процедуры обновления измененных объектов когда количество обновленных
        /// объектов в БД не совпало с ожидаемым количество. Это означает, что некоторые объекты (из списка aUptObjects)
        /// либо "устарели", либо удалены. Данный метод как раз выявляет эти объекты
        /// Списки objects_obsolete и objects_deleted содержат объекты типов XObjectIdentity.
        /// </summary>
        /// <param name="xs">Наследник XStorageConnection</param>
        /// <param name="aUptObjects">Список обновляемых объектов</param>
        /// <param name="objects_obsolete">Возвращаемый список устаревших объектов</param>
        /// <param name="objects_deleted">Возвращаемый список удаленных объектов</param>
        protected void getOutdatedObjects(XStorageConnection xs, IList aUptObjects, out ArrayList objects_obsolete, out ArrayList objects_deleted)
        {
            XDbCommand cmd;                                     // команда
            ArrayList  objects_notdeleted = new ArrayList();    // список не удаленных объектов

            objects_obsolete = new ArrayList();                 // список устаревших объектов
            objects_deleted  = new ArrayList();                 // список удаленных объектов
            XStorageObjectToSave xobjFirst;                     // первый объект группы однотипных объектов
            // пойдем по группам однотипных объектов
            IEnumerator   enumerator = XDatagram.GetEnumerator(aUptObjects);
            StringBuilder cmdBuilder = new StringBuilder();

            while (enumerator.MoveNext())
            {
                ArrayList aGroup = (ArrayList)enumerator.Current;
                xobjFirst         = (XStorageObjectToSave)aGroup[0];
                cmdBuilder.Length = 0;
                cmdBuilder.AppendFormat("SELECT {0}, ts FROM {1} WHERE ",
                                        xs.ArrangeSqlName("ObjectID"),                               // 0
                                        xs.GetTableQName(xobjFirst.SchemaName, xobjFirst.ObjectType) // 1
                                        );
                foreach (XStorageObjectToSave xobj in aGroup)
                {
                    cmdBuilder.AppendFormat("{0}={1} OR ",
                                            xs.ArrangeSqlName("ObjectID"), xs.ArrangeSqlGuid(xobj.ObjectID));
                }
                // отрежем последний " OR "
                cmdBuilder.Length -= 4;
                // получим список удаленных объектов:
                // для этого сначала получим список неудаленных объектов
                objects_notdeleted.Clear();
                cmd = xs.CreateCommand(cmdBuilder.ToString());
                using (IDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        // под индексом 0 здесь ObjectID объекта, он всегда NOT NULL, поэтому IsDbNull не проверяем
                        objects_notdeleted.Add(new XObjectIdentity(xobjFirst.ObjectType, reader.GetGuid(0), reader.GetInt64(1)));
                    }
                }
                // теперь у нас есть изначальный список объектов, и список неудаленных объектов, их разность и будет список удаленных объектов
                foreach (XStorageObjectToSave xobj in aGroup)
                {
                    // объект для поиска
                    XObjectIdentity xobjID = new XObjectIdentity(xobj.ObjectType, xobj.ObjectID);
                    int             nIndex = objects_notdeleted.IndexOf(xobjID);
                    // если текущего объекта нет в списке неудаленных объектов, значит он удаленный
                    if (nIndex == -1)
                    {
                        objects_deleted.Add(xobjID);
                    }
                    // иначе, если у зачитанного объекта отличается ts от текущего, значит он устаревший
                    else if ((objects_notdeleted[nIndex] as XObjectIdentity).TS != xobj.TS && xobj.AnalyzeTS)
                    {
                        objects_obsolete.Add(xobjID);
                    }
                }
            }
        }
Exemplo n.º 4
0
 /// <summary>
 /// Сохраняет бинарные и большие текстовые свойства у всех объектов
 /// (из списка новых и списка обновляемых объектов)
 /// </summary>
 /// <param name="xs">Реализация XStorageConnection</param>
 /// <param name="datagram">Множество обрабатываемых объектов</param>
 protected void updateBinAndLongData(XStorageConnection xs, XDatagram datagram)
 {
     foreach (XStorageObjectToSave xobj in datagram.ObjectsToInsert)
     {
         updateBinAndLongDataForObject(xs, xobj);
     }
     foreach (XStorageObjectToSave xobj in datagram.ObjectsToUpdate)
     {
         updateBinAndLongDataForObject(xs, xobj);
     }
 }
Exemplo n.º 5
0
        /// <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();
        }
Exemplo n.º 6
0
        public XDatagram GetDatagram(DomainObjectDataSet dataSet)
        {
            XDatagram   dg         = new XDatagram();
            IEnumerator enumerator = dataSet.GetModifiedObjectsEnumerator(false);

            while (enumerator.MoveNext())
            {
                XStorageObjectBase xobj = createXStorageObject((DomainObjectData)enumerator.Current);
                add(xobj);
                createObjectsFromLinks(xobj);
            }
            fillDatagram(dg);
            return(dg);
        }
Exemplo n.º 7
0
 /// <summary>
 /// Расносит объекты из списка m_objects по 3-м списка в переданной датаграмме:
 /// списку удаляемых, обновляемых, вставляемых
 /// </summary>
 protected void fillDatagram(XDatagram dg)
 {
     foreach (XStorageObjectBase xobj in m_objects.Values)
     {
         if (xobj.State == XStorageObjectState.ToDelete)
         {
             dg.AddDeleted((XStorageObjectToDelete)xobj);
         }
         else if (xobj.State == XStorageObjectState.ToInsert)
         {
             dg.AddInserted((XStorageObjectToSave)xobj);
         }
         else
         {
             dg.AddUpdated((XStorageObjectToSave)xobj);
         }
     }
 }
Exemplo n.º 8
0
 /// <summary>
 /// Запускает сохранение при отсутствии внещней транзакции, создает транзакцию внутри
 /// </summary>
 /// <param name="xs">Реализация XStorageConnection</param>
 /// <param name="datagram">множество объектов</param>
 protected void saveWithoutTransaction(XStorageConnection xs, XDatagram datagram)
 {
     xs.BeginTransaction();
     try
     {
         DoSave(xs, datagram);
         xs.CommitTransaction();
     }
     catch (XDbDeadlockException)
     {
         // если произошел Dealock, то не будем пытаться откатить транзакцию, т.к. она уже не существует
         throw;
     }
     catch
     {
         xs.RollbackTransaction();
         throw;
     }
 }
Exemplo n.º 9
0
        /// <summary>
        /// Сохраняет chunked-данные всех объектов из датаграммы
        /// </summary>
        /// <param name="transactionID">Идентификатор транзакции</param>
        /// <param name="datagram">датаграмма</param>
        /// <param name="con">соединение</param>
        protected static void saveChunkedData(Guid transactionID, XDatagram datagram, XStorageConnection con)
        {
            bool bChunkedDataFound = false;

            foreach (XStorageObjectToSave xobj in datagram.ObjectsToInsert)
            {
                bChunkedDataFound = saveObjectChunkedData(xobj, con);
            }

            foreach (XStorageObjectToSave xobj in datagram.ObjectsToUpdate)
            {
                bChunkedDataFound = bChunkedDataFound || saveObjectChunkedData(xobj, con);
            }

            // Если в процессе какие-либо "кусочные" данные были перегружены
            // в положенные таблицы - удаляем такие "куски":
            if (bChunkedDataFound)
            {
                XChunkStorageGateway.RemoveTransactionData(transactionID, con);
            }
        }
Exemplo n.º 10
0
        public void Save(XStorageConnection xs, XDatagram datagram)
        {
            if (xs == null)
            {
                throw new ArgumentNullException("xs");
            }
            if (datagram == null)
            {
                throw new ArgumentNullException("xobjSet");
            }

            Debug.Assert(datagram.ObjectsToInsert != null, "Массив объектов на вставку не определен (null)");
            Debug.Assert(datagram.ObjectsToUpdate != null, "Массив объектов на обновление не определен (null)");
            Debug.Assert(datagram.ObjectsToDelete != null, "Массив объектов на удаление не определен (null)");

            if (xs.Transaction == null)
            {
                saveWithoutTransaction(xs, datagram);
            }
            else
            {
                saveWithinTransaction(xs, datagram);
            }
        }
Exemplo n.º 11
0
 public XDatagramWalker(XDatagram dg)
 {
     m_datagram = dg;
 }
Exemplo n.º 12
0
        /// <summary>
        /// Подчищает ссылки объектов, удаленных из линков
        /// </summary>
        /// <param name="xs">Реализация XStorageConnection</param>
        /// <param name="disp">диспетчер запросов</param>
        /// <param name="datagram">Множество обрабатываемых объектов</param>
        protected void purgeLinks(XStorageConnection xs, XDbStatementDispatcher disp, XDatagram datagram)
        {
            StringBuilder queryBuilder;                 // построитель запроса
            string        sTypeName;                    // наименование типа объекта владельца обратного свойства

            if (datagram.ObjectsToUpdate.Count == 0)
            {
                return;                                                 // обновлять нечего
            }
            queryBuilder = new StringBuilder();
            // по всем объектам из списка обновляемых
            foreach (XStorageObjectToSave xobj in datagram.ObjectsToUpdate)
            {
                foreach (DictionaryEntry entry in xobj.GetPropsByCapacity(XPropCapacity.Link, XPropCapacity.LinkScalar))
                {
                    XPropInfoObject propInfo = (XPropInfoObject)xobj.TypeInfo.GetProp((string)entry.Key);
                    Guid[]          values   = (Guid[])entry.Value;
                    queryBuilder.Length = 0;
                    sTypeName           = propInfo.ReferedType.Name;
                    // всем объектам ссылающимся на текущуй объект по обратному относительно текущего свойству
                    // обNULLим ссылку..
                    queryBuilder.AppendFormat(
                        "UPDATE {0} SET {1} = NULL, {2} = CASE WHEN {2}<{3} THEN {2}+1 ELSE 1 END {5}WHERE {1}={4} ",
                        xs.GetTableQName(xobj.TypeInfo.Schema, sTypeName),                                      // 0
                        xs.ArrangeSqlName(propInfo.ReverseProp.Name),                                           // 1
                        xs.ArrangeSqlName("ts"),                                                                // 2
                        Int64.MaxValue,                                                                         // 3
                        xs.ArrangeSqlGuid(xobj.ObjectID),                                                       // 4
                        xs.Behavior.SqlNewLine                                                                  // 5
                        );
                    // ...при условии, что идентификаторы этих объектов не упомянуты в свойстве
                    if (values.Length > 0)
                    {
                        // в текущем св-ве есть объекты (их идентификаторы в values)
                        queryBuilder.AppendFormat("AND NOT {0} IN (", xs.ArrangeSqlName("ObjectID"));
                        foreach (Guid value in values)
                        {
                            queryBuilder.AppendFormat("{0},", xs.ArrangeSqlGuid(value));
                        }
                        // отрежем последнюю запятую
                        queryBuilder.Length--;
                        queryBuilder.Append(") ");
                    }
                    // так же исключим объекты, присутствующие в списке удаляемых,
                    // т.к. при удалении проверяется ts, а формируемый update его увеличивает, да и вообще бессмыселен
                    if (datagram.ObjectsToDelete.Count > 0)
                    {
                        StringBuilder addWhereBuilder = new StringBuilder();
                        foreach (XStorageObjectToDelete xobjDel in datagram.ObjectsToDelete)
                        {
                            if (xobjDel.ObjectType == sTypeName)
                            {
                                addWhereBuilder.AppendFormat("{0},", xs.ArrangeSqlGuid(xobjDel.ObjectID));
                            }
                        }
                        if (addWhereBuilder.Length > 0)
                        {
                            // отрежем последнюю запятую
                            addWhereBuilder.Length--;
                            queryBuilder.AppendFormat("AND NOT {0} IN ({1}) ",
                                                      xs.ArrangeSqlName("ObjectID"),            // 0
                                                      addWhereBuilder.ToString()                // 1
                                                      );
                        }
                    }
                    disp.DispatchStatement(queryBuilder.ToString(), false);
                }               // конец цикла по свойствам объекта xobj
            }                   // конец цикла по объектам из списка обновляемых
        }
Exemplo n.º 13
0
        /// <summary>
        /// Вставляет новые объекты
        /// </summary>
        /// <param name="xs">Реализация XStorageConnection</param>
        /// <param name="disp">диспетчер запросов</param>
        /// <param name="datagram">Множество обрабатываемых объектов</param>
        /// <param name="bSuppressMagicBit">признак того, что надо исключить обработку поля MagicBit</param>
        protected virtual void insertObjects(XStorageConnection xs, XDbStatementDispatcher disp, XDatagram datagram, bool bSuppressMagicBit)
        {
            int        nIndex;                                          // порядковый индекс объекта
            XDbCommand cmd;                                             // команда как фабрика для создания параметров

            // получим упорядоченный список новых объектов упорядоченный по индексу зависимости
            IList aInsObjects = datagram.ObjectsToInsert;

            if (aInsObjects.Count == 0)
            {
                return;
            }
            nIndex = -1;
            cmd    = xs.CreateCommand();
            // для каждого объекта создадим заготовку ADO-команды с оператором insert и коллекцией параметров
            foreach (XStorageObjectToSave xobj in aInsObjects)
            {
                insertObject(xs, disp, xobj, cmd, ++nIndex, bSuppressMagicBit);
            }
        }
Exemplo n.º 14
0
 /// <summary>
 /// Сохранение (вставка, обновление, удаление) множества объектов
 /// Не оборачивается ни транзакцией, ни savepoint'ами.
 /// </summary>
 /// <param name="xs">Реализация XStorageConnection</param>
 /// <param name="datagram">множество объектов</param>
 public abstract void DoSave(XStorageConnection xs, XDatagram datagram);