Beispiel #1
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);
        }
Beispiel #2
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);
        }
        /// <summary>
        /// Формирует и выполняет явный SQL-запрос на получение значения свойства
        /// (столбца) ObjectID для указанного ds-типа, для экземпляра, заданного
        /// значениями своих параметров
        /// </summary>
        /// <param name="sRequiredTypeName">
        /// Наименование ds-типа, для которого формируется запрос
        /// </param>
        /// <param name="dictionaryParams">
        /// Хеш параметров; здесь в паре ключ пары - наименование параметра,
        /// значение пары - собственно значение параметра. Последний может быть
        /// типизированным значением, значением в стрковом представленнии.
        /// Технически допустимо значение в виде массива типизированных значений
        /// или их строковых представлений, но такие значения в данном случае
        /// неприменимы и приводят к генерации исключения ArgumentException.
        /// </param>
        /// <param name="connection">Соединение с СУБД; на момент вызова д.б. открыто</param>
        /// <returns>Значение ObjectID экземпляра объекта</returns>
        protected Guid processExplicitObjectIdRequest(
            string sRequiredTypeName,
            Hashtable dictionaryParams,
            XStorageConnection connection)
        {
            // SQL-операция получения значения ObjectID экземпляра заданного типа
            XDbCommand command = connection.CreateCommand();
            // Строка, в которой будем собирать WHERE-условие для SQL-операции
            StringBuilder sWhereClause = new StringBuilder();

            // #1: Формируем WHERE-условие; для этого перебираем все параметры,
            // переданные в составе коллекции, и для каждого параметра (а) добавляем
            // условие в WHERE-выражение, (б) добавляем соответствующий параметр в
            // коллекцию параметров SQL-операции. Наименование свойства, на которое
            // накладывается условие и наименование параметра формируются на основании
            // наименования парамтра, переданного в исходной коллекции; на всякий
            // пожарный случай к нарименованию параметра в SQL-выражении добавляем
            // префикс "param":
            foreach (DictionaryEntry item in dictionaryParams)
            {
                // В случае непосредственного запроса на получение ObjectID
                // массивные значения параметров недопустимы:
                if (item.Value is ArrayList || item.Value is Array)
                {
                    throw new ArgumentException(String.Format(
                                                    "В качестве значения параметра {0} передан массив значений, " +
                                                    "что недопустимо в случае явного запроса идентификатора объекта типа {1}",
                                                    item.Key.ToString(), sRequiredTypeName)
                                                );
                }

                // Если значение параметра задано как NULL, то это специальный случай
                // условия, обрабатываем его отдельно:
                if (null == item.Value)
                {
                    // Наименование свойства, на которое накладывается условие,
                    // есть наименования параметра, переданного в коллекции:
                    sWhereClause.AppendFormat(
                        "(obj.{0} IS NULL) AND ",
                        connection.Behavior.ArrangeSqlName(item.Key.ToString())
                        );
                }
                else
                {
                    // Наименование SQL-параметра: наименование параметра из
                    // в исходной коллекции, к которому добавлен префикс:
                    string sParamName = "param" + item.Key.ToString();

                    // Наименование свойства, на которое накладывается условие,
                    // есть наименования параметра из исходной коллекции:
                    sWhereClause.AppendFormat("(obj.{0}={1}{2}) AND ",
                                              connection.Behavior.ArrangeSqlName(item.Key.ToString()),          // 0
                                              connection.Behavior.ParameterPrefix,                              // 1
                                              sParamName                                                        // 2
                                              );

                    // Создаем объект-параметр, добавлем его в коллекцию параметров
                    // SQL-операции:
                    XDbParameter param = command.CreateParameter();
                    param.ParameterName = sParamName;
                    param.VarType       = XPropTypeParser.GetNearestTypeForCLR(item.Value.GetType());
                    param.Value         = item.Value;
                    // Если тип параметра есть строка - ограничим размерность,
                    // т.к. в противном случае это будет максимальная размерность - 4К -
                    // и будет достаточно заметно тормозить. В качестве исходной размерности
                    // укажем длину реально заданного значения, увеличенного на 2:
                    if (item.Value is string)
                    {
                        param.Size = ((string)item.Value).Length + 2;
                    }
                    command.Parameters.Add(param);
                }
            }
            sWhereClause.Append("(1=1)");


            // #2: Формируем и выполняем полную SQL-операцию
            command.CommandType = System.Data.CommandType.Text;
            command.CommandText = String.Format(
                "SELECT TOP 1 obj.ObjectID FROM {0} obj WHERE {1}",
                connection.GetTableQName(sRequiredTypeName),
                sWhereClause.ToString()
                );
            object oResult = command.ExecuteScalar();


            // #3: Ожидается, что в результате мы получаем GUID; если
            // результата нет вообще, возвращаем Guid.Empty;
            Guid uidResult = Guid.Empty;

            if (null != oResult && DBNull.Value != oResult)
            {
                uidResult = connection.Behavior.CastGuidValueFromDB(oResult);
            }

            return(uidResult);
        }