Beispiel #1
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);
                    }
                }
            }
        }
Beispiel #2
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);
        }
Beispiel #3
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);
                    }
                }
            }
        }