Пример #1
0
        /// <summary>
        /// Сохраняет бинарные и большие текстовые свойства для переданного объекта
        /// </summary>
        /// <param name="xs">Реализация XStorageConnection</param>
        /// <param name="xobj">Объект, для которого требуется обновить большие (бинарные и текстовые) свойства</param>
        protected virtual void updateBinAndLongDataForObject(XStorageConnection xs, XStorageObjectToSave xobj)
        {
            string sValue;

            // по всем текстовым полям переданного объекта
            foreach (DictionaryEntry entry in xobj.GetPropsByType(XPropType.vt_text))
            {
                // установка в NULL происходит сразу в insert/update'ах
                if (entry.Value == DBNull.Value)
                {
                    sValue = null;
                }
                else
                {
                    sValue = (string)entry.Value;
                }
                xs.SaveTextData(xobj.SchemaName, xobj.ObjectType, xobj.ObjectID, (string)entry.Key, sValue);
            }

            byte[] aValue;
            // по всем бинарным полям переданного объекта
            foreach (DictionaryEntry entry in xobj.GetPropsByType(XPropType.vt_bin))
            {
                // установка в NULL происходит сразу в insert/update'ах
                if (entry.Value == DBNull.Value)
                {
                    aValue = null;
                }
                else
                {
                    aValue = (byte[])entry.Value;
                }
                xs.SaveBinData(xobj.SchemaName, xobj.ObjectType, xobj.ObjectID, (string)entry.Key, aValue);
            }
        }
Пример #2
0
        public override void Merge(XStorageObjectBase p_xobj)
        {
            base.Merge(p_xobj);
            XStorageObjectToSave xobj = p_xobj as XStorageObjectToSave;

            if (xobj == null)
            {
                Debug.Fail("Некорректная реализация XStorageObjectBase::Merge");
                throw new ArgumentException();
            }
            UpdateTS = UpdateTS | xobj.UpdateTS;
            if (xobj.IsToInsert)
            {
                m_state = XStorageObjectState.ToInsert;
            }
            foreach (string sPropName in xobj.Props.Keys)
            {
                if (!Props.Contains(sPropName))
                {
                    // свойства не было - добавим
                    Props[sPropName] = xobj.Props[sPropName];
                }
                else
                {
                    XStorageObjectPropMergeModes mergeModeThis    = GetPropMergeMode(sPropName);
                    XStorageObjectPropMergeModes mergeModeForeign = xobj.GetPropMergeMode(sPropName);
                    // если хотя бы для одного свойства стоит флаг "слабой" проверки, то отключаем проверку на совпадание значений свойств
                    if (mergeModeThis == XStorageObjectPropMergeModes.Replace)
                    {
                        Debug.Assert(mergeModeForeign != XStorageObjectPropMergeModes.Replace, "Два свойства с признаком перезаписи - это некорректная ситуация");
                        // у текущего св-ва задан атрибут перезаписи, поэтому оставляем его в неприкосновенности (даже проверки не делаем)
                    }
                    else if (mergeModeForeign == XStorageObjectPropMergeModes.Replace)
                    {
                        Props[sPropName] = xobj.Props[sPropName];
                    }
                    else
                    {
                        if (!isPropsEquals(Props[sPropName], xobj.Props[sPropName]))
                        {
                            throw new XMergeConflictException("Значения свойста " + sPropName + " отличаются: '" + Props[sPropName] + "' и '" + xobj.Props[sPropName] + "'");
                        }
                    }
                }
            }

            // смерджим словарь свойств, данные которых загружены механизмом кусочного сохранения
            if (xobj.PropertiesWithChunkedData.Count > 0)
            {
                foreach (string sPropName in xobj.PropertiesWithChunkedData.Keys)
                {
                    PropertiesWithChunkedData[sPropName] = xobj.PropertiesWithChunkedData[sPropName];
                }
            }

            ParticipateInUniqueIndex = xobj.ParticipateInUniqueIndex | ParticipateInUniqueIndex;
        }
Пример #3
0
        public XStorageObjectBase createXStorageObject(DomainObjectData obj)
        {
            XStorageObjectBase xobj;
            object             vPropValue;

            if (obj.ToDelete)
            {
                xobj = new XStorageObjectToDelete(obj.TypeInfo, obj.ObjectID, obj.TS, true);
            }
            else
            {
                xobj = new XStorageObjectToSave(obj.TypeInfo, obj.ObjectID, obj.TS, obj.IsNew);
                ((XStorageObjectToSave)xobj).PropertiesWithChunkedData = obj.PropertiesWithChunkedData;
            }
            bool bNeedTrackUniqueIndexParticipation = xobj.TypeInfo.HasUniqueIndexes && xobj.TypeInfo.DeferrableIndexes && !obj.ToDelete;

            foreach (string sPropName in obj.UpdatedPropNames)
            {
                vPropValue = obj.GetUpdatedPropValue(sPropName);
                XPropInfoBase propInfo = obj.TypeInfo.GetProp(sPropName);
                if (propInfo is XPropInfoNumeric)
                {
                    if (((XPropInfoSimpleEnumerable)propInfo).IsEnum)
                    {
                        // в качестве значения свойства может быть поcле перечисления, надо привести его в элементарному типу
                        if (vPropValue.GetType().IsEnum)
                        {
                            if (propInfo.VarType == XPropType.vt_i4)
                            {
                                vPropValue = (Int32)vPropValue;
                            }
                            else if (propInfo.VarType == XPropType.vt_i2)
                            {
                                vPropValue = (Int16)vPropValue;
                            }
                            else                             // if (propInfo.VarType == XPropType.vt_ui1)
                            {
                                vPropValue = (byte)vPropValue;
                            }
                        }
                    }
                }
                if (vPropValue != null)
                {
                    xobj.Props[sPropName] = vPropValue;
                }
                // если свойство участвует в уникальном индексе, запомним это
                if (bNeedTrackUniqueIndexParticipation)
                {
                    if (xobj.TypeInfo.IsPropIncludedIntoUniqueIndex(sPropName))
                    {
                        ((XStorageObjectToSave)xobj).ParticipateInUniqueIndex = true;
                    }
                }
            }
            return(xobj);
        }
Пример #4
0
        /// <summary>
        /// Добавление объекта в коллекцию обновляемых объектов. Позволяет добавлять один и тот же объект несколько раз.
        /// В отличии от новых и удаляемых объектов, обновляемые могут добавляться явно, т.к. это требуется для "отложенного обновления".
        /// Это случай когда объект сохраняется для SQL оператора: сначала INSERT, а потом UPDATE.
        /// Отложенное обновление требуется для сохранения сетей объектов (Например, А ссылается на Б, а Б ссылается на А)
        /// </summary>
        /// <param name="xobj">Объект для помещения в список обновляемых</param>
        public void AddUpdated(XStorageObjectToSave xobj)
        {
            XStorageObjectToSave xobjExists = (XStorageObjectToSave)m_hashObjectsToUpdate[getKey(xobj)];

            if (xobjExists == null)
            {
                m_aObjectsToUpdate.Add(xobj);
                m_hashObjectsToUpdate.Add(getKey(xobj), xobj);
            }
            else
            {
                xobjExists.Merge(xobj);
            }
        }
Пример #5
0
        /// <summary>
        /// Сохраняет chunked-данные заданного объекта
        /// </summary>
        /// <param name="xobj">объект</param>
        /// <param name="con">соединение с БД</param>
        /// <returns>true - объект содержал chunked данные, иначе false</returns>
        protected static bool saveObjectChunkedData(XStorageObjectToSave xobj, XStorageConnection con)
        {
            string sPropName;                   // наименование свойтсва
            Guid   ownerID;                     // идентификатор цепочки кусочных данных свойства
            bool   bChunkedDataFound = false;

            // найдем свойства, чьи данные были загруженны по частам
            foreach (DictionaryEntry entry in xobj.PropertiesWithChunkedData)
            {
                sPropName         = (string)entry.Key;
                ownerID           = (Guid)entry.Value;
                bChunkedDataFound = true;
                XChunkStorageGateway.MergePropertyChunkedData(
                    ownerID,
                    xobj.ObjectType,
                    sPropName,
                    xobj.ObjectID,
                    con);
            }
            return(bChunkedDataFound);
        }
Пример #6
0
 public XDatagramFromXml(XmlElement xmlRoot, XMetadataManager mdManager)
 {
     m_xmodel = mdManager.XModel;
     parseXmlForest(xmlRoot);
     checkReverseProps();
     foreach (XStorageObjectBase xobj in m_objects)
     {
         // с момента вызова normalizeObject коллекция m_objects и словарь m_objectsDictionary не согласованы:
         // normalizeObject добавляет все создаваемые объекты в m_objectsDictionary, но не добавляет в коллекцию m_objects
         ArrayList aNewObject = normalizeObject(xobj);
         // если что-то вернут, то это будет список "новых" обновляемых объектов,
         // т.е. объекты которые надо проапдейтить в результате помещения ссылок на них в линки текущего объекта
         if (aNewObject != null)
         {
             foreach (XStorageObjectToSave xobjDetached in aNewObject)
             {
                 addUpdatedInternal(xobjDetached);
             }
         }
         if (xobj is XStorageObjectToDelete)
         {
             addDeletedInternal((XStorageObjectToDelete)xobj);
         }
         else
         {
             XStorageObjectToSave xobjSave = (XStorageObjectToSave)xobj;
             if (xobjSave.IsToInsert)
             {
                 addInsertedInternal(xobjSave);
             }
             else
             {
                 addUpdatedInternal(xobjSave);
             }
         }
     }
 }
Пример #7
0
        private void createObjectsFromLinks(XStorageObjectBase xobj)
        {
            // TODO: Здесь вопрос: удаленные объекты могут содержать линки с ссылками и, если да, то надо ли их обрабатывать ?
            if (xobj is XStorageObjectToDelete)
            {
                return;
            }
            XStorageObjectToSave xobjSave = (XStorageObjectToSave)xobj;

            foreach (DictionaryEntry entry in xobjSave.GetPropsByCapacity(XPropCapacity.Link, XPropCapacity.LinkScalar))
            {
                Guid[] valueOIDs = (Guid[])entry.Value;
                if (valueOIDs.Length == 0)
                {
                    continue;
                }
                string sPropName             = (string)entry.Key;
                XPropInfoObjectLink propInfo = (XPropInfoObjectLink)xobj.TypeInfo.GetProp(sPropName);

                int nIndex = 0;
                foreach (Guid valueOID in valueOIDs)
                {
                    XStorageObjectBase xobjValue = new XStorageObjectToSave(propInfo.ReferedType, valueOID, -1, false);
                    xobjValue.Props[propInfo.ReverseProp.Name] = xobj.ObjectID;
                    // пометим свойство специальным атрибутом, чтобы для него не выполнялась проверка на совпадение содержимого при мердже
                    xobjValue.SetPropMergeMode(propInfo.ReverseProp.Name, XStorageObjectPropMergeModes.Weak);
                    xobjValue = add(xobjValue);
                    // упорядоченный линк ? - установим индексное свойство
                    if (propInfo.OrderByProp != null)
                    {
                        xobjValue.Props[propInfo.OrderByProp.Name] = nIndex++;
                        // пометим свойство специальным атрибутом, говорящим о том что при Merge'е данное значение затрет другое значение
                        xobjValue.SetPropMergeMode(propInfo.OrderByProp.Name, XStorageObjectPropMergeModes.Replace);
                    }
                }
            }
        }
Пример #8
0
        private ArrayList normalizeObject(XStorageObjectBase xobj)
        {
            if (xobj is XStorageObjectToDelete)
            {
                return(null);
            }
            XStorageObjectToSave xobjSave    = (XStorageObjectToSave)xobj;
            ArrayList            aNewObjects = null;

            foreach (DictionaryEntry entry in xobjSave.GetPropsByCapacity(XPropCapacity.Link, XPropCapacity.LinkScalar))
            {
                Guid[] valueOIDs = (Guid[])entry.Value;
                if (valueOIDs.Length == 0)
                {
                    continue;
                }
                string sPropName             = (string)entry.Key;
                XPropInfoObjectLink propInfo = (XPropInfoObjectLink)xobj.TypeInfo.GetProp(sPropName);

                int nIndex = 0;
                foreach (Guid valueOID in valueOIDs)
                {
                    XStorageObjectBase xobjValue = (XStorageObjectBase)m_objectsDictionary[valueOID];
                    if (xobjValue == null)
                    {
                        // в датаграмме нет объекта, на который установлена ссылка в линке - значит создадим, этот объект точно не новый
                        xobjValue = new XStorageObjectToSave(propInfo.ReferedType, valueOID, -1, false);
                        if (aNewObjects == null)
                        {
                            aNewObjects = new ArrayList();
                        }
                        aNewObjects.Add(xobjValue);
                        // на случай если данный объект содержится еще в каком-нибудь линке
                        m_objectsDictionary.Add(valueOID, xobjValue);
                    }
                    else
                    {
                        object vValue = xobjValue.Props[propInfo.ReverseProp.Name];
                        if (vValue == null || vValue == DBNull.Value)
                        {
                            // все хорошо - обратное свойство (объектный скаляр) пустое - установим его на текущий объект (xobj)
                            xobjValue.Props[propInfo.ReverseProp.Name] = xobj.ObjectID;
                        }
                        else
                        {
                            Debug.Assert(vValue is Guid);                               // больше ничего другого быть не должно!
                            // обратное свойство уже заполнено, проверим что оно ссылается на текущий объект. если это не так - ругаемся
                            if (((Guid)vValue) != xobj.ObjectID)
                            {
                                throw new XInvalidXmlForestException("Ошибка при установке свойства " + propInfo.ReverseProp.Name + " объекта " + xobjValue.TypeInfo.Name + " [" + xobjValue.ObjectID + "]: нарушение согласованности со свойством " + sPropName + " объекта " + xobj.TypeInfo.Name + " [" + xobj.ObjectID + "]");
                            }
                        }
                    }
                    // упорядоченный линк ? - установим индексное свойство
                    if (propInfo.OrderByProp != null)
                    {
                        xobjValue.Props[propInfo.OrderByProp.Name] = nIndex++;
                    }
                }
            }
            return(aNewObjects);
        }
Пример #9
0
        public static XStorageObjectBase CreateXStorageObject(XmlElement xmlObject, XTypeInfo typeInfo)
        {
            XStorageObjectBase xobj;
            Guid  oid = new Guid(xmlObject.GetAttribute("oid"));
            Int64 nTS;

            if (xmlObject.HasAttribute("ts"))
            {
                nTS = Int32.Parse(xmlObject.GetAttribute("ts"));
            }
            else
            {
                nTS = -1;
            }
            bool bIsNew = false;

            if (xmlObject.HasAttribute("delete"))
            {
                xobj = new XStorageObjectToDelete(typeInfo, oid, nTS, true);
            }
            else
            {
                bIsNew = xmlObject.HasAttribute("new");
                xobj   = new XStorageObjectToSave(typeInfo, oid, nTS, bIsNew);
            }
            bool bNeedTrackUniqueIndexParticipation = typeInfo.HasUniqueIndexes && typeInfo.DeferrableIndexes && xobj is XStorageObjectToSave;

            // по всем свойствам без признака loaded="0"
            foreach (XmlElement xmlProp in xmlObject.SelectNodes("*[not(@loaded)]"))
            {
                XPropInfoBase xprop = typeInfo.GetProp(xmlProp.LocalName);
                if (xprop == null)
                {
                    continue;
                }
                // если на xml-свойстве неудаляемого объекта есть атрибут с идентификатором цепочки кусочных данных, то занесем его в специальный словарь
                if (xobj is XStorageObjectToSave && xmlProp.HasAttribute(ATTR_CHUNCK_CHAIN_ID))
                {
                    ((XStorageObjectToSave)xobj).PropertiesWithChunkedData.Add(xprop.Name, new Guid(xmlProp.GetAttribute(ATTR_CHUNCK_CHAIN_ID)));
                }
                // членство в массиве проигнорируем
                if (xprop is XPropInfoObjectArray)
                {
                    if (((XPropInfoObjectArray)xprop).Capacity == XPropCapacity.ArrayMembership)
                    {
                        continue;
                    }
                }
                // пустые массивные свойства новых объектов проигнорируем
                if (bIsNew)
                {
                    if (xprop is XPropInfoObjectArray || xprop is XPropInfoObjectLink)
                    {
                        if (!xmlProp.HasChildNodes)
                        {
                            continue;
                        }
                    }
                }
                xobj.Props.Add(xprop.Name, getPropValue(xmlProp, xprop));
                // если свойство участвует в уникальном индексе, запомним это
                if (bNeedTrackUniqueIndexParticipation)
                {
                    if (typeInfo.IsPropIncludedIntoUniqueIndex(xprop.Name))
                    {
                        ((XStorageObjectToSave)xobj).ParticipateInUniqueIndex = true;
                    }
                }
            }
            return(xobj);
        }
Пример #10
0
        /// <summary>
        /// Обновляет кросс-таблицы для массивных свойств (collection, collection-membership, array) заданного объекта
        /// </summary>
        /// <param name="xs">Реализация XStorageConnection</param>
        /// <param name="disp">диспетчер запросов</param>
        /// <param name="xobj">ds-Объект</param>
        protected void updateCrossTablesForObject(XStorageConnection xs, XDbStatementDispatcher disp, XStorageObjectToSave xobj)
        {
            string sPropName;                           // наименование свойства
            string sDBCrossTableName;                   // полное наименование кросс-таблицы
            int    nIndex;                              // значение колонки k
            string sKeyColumn;                          // наименование колонки кросс таблицы, по которой будем очищать
            string sValueColumn;                        //

            // по всем свойствам текущего объекта вида: массив, коллекция, членство в коллекции:
            foreach (DictionaryEntry entry in xobj.GetPropsByCapacity(XPropCapacity.Collection, XPropCapacity.Array, XPropCapacity.CollectionMembership))
            {
                sPropName = (string)entry.Key;
                XPropInfoObject propInfo = (XPropInfoObject)xobj.TypeInfo.GetProp(sPropName);
                Debug.Assert(entry.Value is Guid[]);
                Guid[] values = (Guid[])entry.Value;

                // сформируем наименование кросс-таблицы по поля, по которому будем очищать кросс-таблицу:
                sDBCrossTableName = xs.GetTableQName(xobj.SchemaName, xobj.TypeInfo.GetPropCrossTableName(sPropName));

                // Сохранение массива: очистим по ObjectID и вставим все значения из свойства
                if (propInfo.Capacity == XPropCapacity.Array)
                {
                    StringBuilder cmdBuilder = new StringBuilder();
                    // если сохраняем массив (array) нового объекта (отложенное обновление), то DELETE выполнять не будем
                    if (!xobj.IsToInsert)
                    {
                        // сформируем необходимый оператор delete на кросс-таблицу:
                        cmdBuilder.AppendFormat(
                            "DELETE FROM {0} WHERE {1}={2}",
                            sDBCrossTableName,                                                  // 0
                            xs.ArrangeSqlName("ObjectID"),                                      // 1
                            xs.GetParameterName("ObjectID")                                     // 2
                            );
                        disp.DispatchStatement(
                            cmdBuilder.ToString(),
                            new XDbParameter[] { xs.CreateCommand().CreateParameter("ObjectID", DbType.Guid, ParameterDirection.Input, false, xobj.ObjectID) },
                            false
                            );
                    }
                    nIndex = 0;
                    // для каждого значения массивного свойства добавим INSERT в кросс-таблицу
                    foreach (Guid value in values)
                    {
                        cmdBuilder.Length = 0;
                        cmdBuilder.AppendFormat("INSERT INTO {0} ({1}, {2}, {3}) values ({4}, {5}, {6})",
                                                sDBCrossTableName,                              // 0
                                                xs.ArrangeSqlName("ObjectID"),                  // 1
                                                xs.ArrangeSqlName("Value"),                     // 2
                                                xs.ArrangeSqlName("k"),                         // 3
                                                xs.ArrangeSqlGuid(xobj.ObjectID),               // 4
                                                xs.ArrangeSqlGuid(value),                       // 5
                                                nIndex                                          // 6
                                                );
                        disp.DispatchStatement(cmdBuilder.ToString(), false);
                        ++nIndex;
                    }
                }
                // Сохранение коллекции и членства в коллекции
                else
                {
                    if (propInfo.Capacity == XPropCapacity.CollectionMembership)
                    {
                        sKeyColumn   = "Value";
                        sValueColumn = "ObjectID";
                    }
                    else
                    {
                        sKeyColumn   = "ObjectID";
                        sValueColumn = "Value";
                    }
                    // сформируем необходимый оператор delete на кросс-таблицу:
                    StringBuilder cmdBuilder = new StringBuilder();
                    cmdBuilder.AppendFormat(
                        "DELETE FROM {0} WHERE {1}={2}",
                        sDBCrossTableName,                                              // 0
                        xs.ArrangeSqlName(sKeyColumn),                                  // 1
                        xs.ArrangeSqlGuid(xobj.ObjectID)                                // 2
                        //xs.GetParameterName("ObjectID")		// 2
                        );
                    // если есть новые значения свойства, то исключим их из удаления
                    if (values.Length > 0)
                    {
                        cmdBuilder.AppendFormat(
                            " AND NOT {0} IN (", xs.ArrangeSqlName(sValueColumn)
                            );
                        foreach (Guid oid in values)
                        {
                            cmdBuilder.Append(xs.ArrangeSqlGuid(oid));
                            cmdBuilder.Append(",");
                        }
                        // удалим последнюю запятую
                        cmdBuilder.Length--;
                        cmdBuilder.Append(")");
                    }
                    disp.DispatchStatement(
                        cmdBuilder.ToString(),
                        //new XDbParameter[] {xs.CreateCommand().CreateParameter("ObjectID", DbType.Guid, ParameterDirection.Input, false, xobj.ObjectID)},
                        false
                        );

                    // для каждого значения массивного свойства добавим INSERT в кросс-таблицу
                    foreach (Guid value in values)
                    {
                        cmdBuilder.Length = 0;
                        cmdBuilder.AppendFormat("INSERT INTO {0} ({1}, {2}) SELECT {3}, {4} WHERE NOT EXISTS (SELECT 1 FROM {0} WHERE {1}={3} AND {2}={4})",
                                                sDBCrossTableName,                              // 0
                                                xs.ArrangeSqlName(sKeyColumn),                  // 1
                                                xs.ArrangeSqlName(sValueColumn),                // 2
                                                xs.ArrangeSqlGuid(xobj.ObjectID),               // 3
                                                xs.ArrangeSqlGuid(value)                        // 4
                                                );
                        disp.DispatchStatement(cmdBuilder.ToString(), false);
                    }
                }
            }
        }
Пример #11
0
        /// <summary>
        /// Формирует заготовку команды update для переданного объекта.
        /// Формируется текст ADO-команда, параметры и подсчитывается размер команды.
        /// Имя параметра устанавливается как имя колонки + "t" +  nBatch + "o" + nIndex
        /// Для всех колонок используются параметры (в отличии от createUpdateCommandForSameTypeObjects).
        /// </summary>
        /// <param name="xs">Реализация XStorageConnection</param>
        /// <param name="disp">диспетчер запросов</param>
        /// <param name="xobj">объект, для которого требуется сформировать insert-команду</param>
        /// <param name="nBatchIndex">индекс группы объектов</param>
        /// <param name="nIndex">индекс объекта в списке</param>
        /// <param name="cmd">команда, как фабрика параметров</param>
        /// <param name="bSuppressMagicBit">признак того, что надо исключить обработку поля MagicBit.
        /// Если передан false, то в команде insert добавляется поле MagicBit устанавливаемое в 1.
        /// Если передан true, то в команде insert поле MagicBit не участвует.
        /// </param>
        /// <returns>заготовка команды с оператором UPDATE всех объектов из списка, либо null</returns>
        protected bool updateObject(XStorageConnection xs, XDbStatementDispatcher disp, XStorageObjectToSave xobj, int nBatchIndex, int nIndex, XDbCommand cmd, bool bSuppressMagicBit)
        {
            StringBuilder       cmdBuilder;                              // построитель текста одной команды update
            string              sPropName;                               // наименование свойства, колонки и параметра
            string              sParamName;                              // наименование параметра команды
            object              vValue;                                  // значение свойства
            List <XDbParameter> aParameters = new List <XDbParameter>(); // коллекция параметров формируемой команды
            bool bCmdConstructed            = false;                     // признак того, что команда update сформирована

            cmdBuilder = new StringBuilder();
            cmdBuilder.AppendFormat("UPDATE {0} SET ",
                                    xs.GetTableQName(xobj.SchemaName, xobj.ObjectType));
            if (xobj.UpdateTS)
            {
                cmdBuilder.AppendFormat("{0} = CASE WHEN {0}<{1} THEN {0}+1 ELSE 1 END{2}",
                                        xs.ArrangeSqlName("ts"),        // 0
                                        Int64.MaxValue,                 // 1
                                        xs.Behavior.SqlNewLine);        // 2
                bCmdConstructed = true;
            }
            foreach (DictionaryEntry propDesc in xobj.Props)
            {
                sPropName = (String)propDesc.Key;
                vValue    = propDesc.Value;
                XPropInfoBase propInfo = xobj.TypeInfo.GetProp(sPropName);
                if (!(propInfo is IXPropInfoScalar))
                {
                    continue;
                }
                if ((propInfo.VarType == XPropType.vt_bin || propInfo.VarType == XPropType.vt_text) /*&& vValue != DBNull.Value */)
                {
                    continue;
                }
                if (bCmdConstructed)
                {
                    cmdBuilder.Append(",");                             // текущая колонка уже не первая - добавим запятую
                }
                bCmdConstructed = true;
                xobj.TypeInfo.CheckPropValue(sPropName, propInfo.VarType, vValue);
                sParamName = xs.GetParameterName(String.Format("{0}t{1}o{2}", sPropName, nBatchIndex, nIndex));
                cmdBuilder.Append(xs.ArrangeSqlName(sPropName) + "=" + sParamName + xs.Behavior.SqlNewLine);
                aParameters.Add(cmd.CreateParameter(sParamName, propInfo.VarType, ParameterDirection.Input, true, vValue));
            }

            if (!bCmdConstructed)
            {
                return(false);
            }
            // если объект участвует в уникальных индексах и есть объекты в списках на вставку и/или удаление, то
            // установим MagicBit в 1 для предотвражения нарушения уникальных индексов
            if (!bSuppressMagicBit && xobj.ParticipateInUniqueIndex)
            {
                xobj.MagicBitAffected = true;
                cmdBuilder.AppendFormat(", {0}=1", xs.ArrangeSqlName("MagicBit"));
            }
            // сформируем условие WHERE: (ObjectID={@oid} AND ts={@ts}),
            // однако условие AND ts={@ts} добавим только если у объекта установлен признак AnalizeTS
            cmdBuilder.Append(" WHERE ");
            sParamName = xs.GetParameterName(String.Format("{0}t{1}o{2}", "ObjectID", nBatchIndex, nIndex));
            cmdBuilder.AppendFormat("({0}={1}",
                                    xs.ArrangeSqlName("ObjectID"),
                                    sParamName);
            aParameters.Add(cmd.CreateParameter(sParamName, DbType.Guid, ParameterDirection.Input, true, xobj.ObjectID));
            if (xobj.AnalyzeTS)
            {
                sParamName = xs.GetParameterName(String.Format("{0}t{1}o{2}", "ts", nBatchIndex, nIndex));
                cmdBuilder.AppendFormat(" AND {0}={1}",
                                        xs.ArrangeSqlName("ts"),        // 0
                                        sParamName);                    // 1
                aParameters.Add(cmd.CreateParameter(sParamName, DbType.Int64, ParameterDirection.Input, true, xobj.TS));
            }
            cmdBuilder.Append(")");

            disp.DispatchStatement(cmdBuilder.ToString(), aParameters, true);
            return(true);
        }
Пример #12
0
        /// <summary>
        /// Формирует заготовку команды insert для переданного объекта.
        /// Формирутеся текст ADO-команда, параметры и подсчитывается размер команды.
        /// Имя параметра устанавливается как имя колонки + индекс объекта в общем списке
        /// </summary>
        /// <param name="xs">Реализация XStorageConnection</param>
        /// <param name="disp">диспетчер запросов</param>
        /// <param name="xobj">объект, для которого требуется сформировать insert-команду</param>
        /// <param name="cmd">команда</param>
        /// <param name="nIndex">индекс объекта в списке</param>
        /// <param name="bSuppressMagicBit">признак того, что надо исключить обработку поля MagicBit.
        /// Если передан false, то в команде insert добавляется поле MagicBit устанавливаемое в 1.
        /// Если передан true, то в команде insert поле MagicBit не участвует.
        /// </param>
        protected void insertObject(XStorageConnection xs, XDbStatementDispatcher disp, XStorageObjectToSave xobj, XDbCommand cmd, int nIndex, bool bSuppressMagicBit)
        {
            StringBuilder queryBuilder  = new StringBuilder();  // построитель отдельного insert'a
            StringBuilder valuesBuilder = new StringBuilder();  // построитель списка значений
            string        sPropName;                            // наименование свойства, колонки и параметра
            string        sParamName;                           // наименование параметра команды
            object        vValue;                               // значение свойства


            List <XDbParameter> Params = new List <XDbParameter>();

            queryBuilder.AppendFormat("INSERT INTO {0} ({1}, {2}",
                                      xs.GetTableQName(xobj.SchemaName, xobj.ObjectType), // 0
                                      xs.ArrangeSqlName("ObjectID"),                      // 1
                                      xs.ArrangeSqlName("ts")                             // 2
                                      );
            // установим значения ObjectID, ts (в качастве ts установим 1)
            valuesBuilder.Append(xs.ArrangeSqlGuid(xobj.ObjectID) + ",1");
            // если не запрещено, то значение MagicBit = 1
            if (!bSuppressMagicBit && xobj.ParticipateInUniqueIndex)
            {
                queryBuilder.AppendFormat(",{0}", xs.ArrangeSqlName("MagicBit"));
                xobj.MagicBitAffected = true;
                valuesBuilder.Append(",1");
            }
            foreach (DictionaryEntry propDesc in xobj.Props)
            {
                sPropName = (String)propDesc.Key;
                vValue    = propDesc.Value;
                if (vValue == null)
                {
                    continue;
                }
                XPropInfoBase propInfo = xobj.TypeInfo.GetProp(sPropName);
                if (!(propInfo is IXPropInfoScalar))
                {
                    continue;
                }
                if ((propInfo.VarType == XPropType.vt_bin || propInfo.VarType == XPropType.vt_text) /* && vValue != DBNull.Value*/)
                {
                    continue;
                }
                xobj.TypeInfo.CheckPropValue(sPropName, propInfo.VarType, vValue);
                if (vValue != DBNull.Value)
                {
                    queryBuilder.Append(',');
                    queryBuilder.Append(xs.ArrangeSqlName(sPropName));
                    valuesBuilder.Append(',');
                    if (xs.DangerXmlTypes.ContainsKey(propInfo.VarType))
                    {
                        // сформируем наименование параметра (без префикса) как имя колонки + "o" + переданный индекс
                        sParamName = xs.GetParameterName(sPropName + "o" + nIndex);
                        Params.Add(cmd.CreateParameter(sParamName, propInfo.VarType, ParameterDirection.Input, false, vValue));
                        valuesBuilder.Append(sParamName);
                    }
                    else
                    {
                        valuesBuilder.Append(xs.ArrangeSqlValue(vValue, propInfo.VarType));
                    }
                }
            }
            // сформируем команду и добавим ее в общий батч
            queryBuilder.AppendFormat(") values ({0})", valuesBuilder.ToString());
            disp.DispatchStatement(queryBuilder.ToString(), Params, false);
        }
Пример #13
0
 /// <summary>
 /// Добавление объекта в коллекцию вставляемых объектов
 /// </summary>
 /// <param name="xobj"></param>
 public void AddInserted(XStorageObjectToSave xobj)
 {
     m_aObjectsToInsert.Add(xobj);
     m_hashObjectsToInsert.Add(getKey(xobj), xobj);
 }