コード例 #1
0
        private void merge(XStorageObjectBase xobjExists, XStorageObjectBase xobj)
        {
            if (xobjExists.GetType() != xobj.GetType())
            {
                throw new XMergeConflictException("Объект " + xobj.TypeInfo.Name + " [" + xobj.ObjectID + "] присутствует в нескольких несогласованных экземплярах: один помечен delete='1', а другой нет");
            }
            if (xobjExists is XStorageObjectToSave)
            {
                if (((XStorageObjectToSave)xobjExists).IsToInsert != ((XStorageObjectToSave)xobj).IsToInsert)
                {
                    throw new XMergeConflictException("Объект " + xobj.TypeInfo.Name + " [" + xobj.ObjectID + "] присутствует в нескольких несогласованных экземплярах: один помечен new='1', а другой нет ");
                }
            }
            if (xobjExists.TS != xobj.TS && xobjExists.AnalyzeTS && xobj.AnalyzeTS)
            {
                throw new XMergeConflictException("Обнаружены две копии объекта с различающимся ts");
            }

            foreach (DictionaryEntry entry in xobj.Props)
            {
                string sPropName = (string)entry.Key;
                if (!xobjExists.Props.Contains(sPropName))
                {
                    xobjExists.Props.Add(sPropName, entry.Value);
                }
                else
                {
                    bool bNeedScalarCheck = true;
                    // текущее свойство уже есть - если оно массивное, то merge
                    XPropInfoBase propInfo = xobjExists.TypeInfo.GetProp(sPropName);
                    if (propInfo is XPropInfoObject && !(propInfo is XPropInfoObjectScalar))
                    {
                        bNeedScalarCheck = false;
                        XPropCapacity capacity  = ((XPropInfoObject)propInfo).Capacity;
                        Guid[]        valuesOld = (Guid[])xobjExists.Props[sPropName];
                        Guid[]        valuesCur = (Guid[])entry.Value;
                        if (capacity == XPropCapacity.Array || (capacity == XPropCapacity.Link && ((XPropInfoObjectLink)propInfo).OrderByProp != null))
                        {
                            // массивы и упорядоченные линки не подвергаются слиянию - только проверке на совпадение значений
                            if (valuesOld.Length != valuesCur.Length)
                            {
                                throw new XMergeConflictException("Не совпадает количество элементов в свойстве " + sPropName);
                            }
                            for (int i = 0; i < valuesOld.Length; ++i)
                            {
                                if (valuesOld[i] != valuesCur[i])
                                {
                                    throw new XMergeConflictException("Не совпадает значение свойства " + sPropName);
                                }
                            }
                        }
                        else
                        {
                            // коллекция и членство в коллекции
                            ArrayList aValuesNew = new ArrayList(valuesOld.Length + valuesCur.Length);
                            aValuesNew.AddRange(valuesOld);
                            foreach (Guid value in valuesCur)
                            {
                                if (aValuesNew.IndexOf(value) < 0)
                                {
                                    aValuesNew.Add(value);
                                }
                            }

                            Guid[] valuesNew = new Guid[aValuesNew.Count];
                            aValuesNew.CopyTo(valuesNew);
                            xobjExists.Props[sPropName] = valuesNew;
                        }
                    }
                    else if (propInfo is XPropInfoNumeric)
                    {
                        //скалярное - сравним значения, если это не индексное свойство
                        if (((XPropInfoNumeric)propInfo).OrderedLinkProp != null)
                        {
                            bNeedScalarCheck = false;
                        }
                    }
                    if (bNeedScalarCheck)
                    {
                        if (!xobjExists.Props[sPropName].Equals(entry.Value))
                        {
                            throw new XMergeConflictException("Значения свойства " + sPropName + " не совпадают");
                        }
                    }
                }
            }
        }
コード例 #2
0
        private DomainObjectData DeserializeObject(XmlElement xmlObject, XTypeInfo typeInfo, DomainObjectDataSet dataSet)
        {
            DomainObjectData xobj;
            Guid             oid        = new Guid(xmlObject.GetAttribute("oid"));
            bool             bIsNew     = xmlObject.HasAttribute("new");
            bool             bToDelete  = xmlObject.HasAttribute("delete");
            bool             bNeedMerge = false;
            object           vPropValue;

            xobj = dataSet.Find(typeInfo.Name, oid);
            if (xobj == null)
            {
                // такого объекта нет в множестве: создадим его и добавить
                if (bToDelete)
                {
                    xobj = dataSet.CreateToDelete(typeInfo.Name, oid);
                }
                else
                {
                    bIsNew = xmlObject.HasAttribute("new");
                    xobj   = dataSet.CreateStub(typeInfo.Name, oid, bIsNew);
                }
            }
            else
            {
                // объект уже присутствует
                if (bIsNew != xobj.IsNew)
                {
                    throw new XMergeConflictException("Объект " + xobj.TypeInfo.Name + " [" + xobj.ObjectID + "] присутствует в нескольких несогласованных экземплярах: один помечен new='1', а другой нет ");
                }
                if (bToDelete != xobj.ToDelete)
                {
                    throw new XMergeConflictException("Объект " + xobj.TypeInfo.Name + " [" + xobj.ObjectID + "] присутствует в нескольких несогласованных экземплярах: один помечен delete='1', а другой нет ");
                }
                bNeedMerge = true;
            }
            if (xmlObject.HasAttribute("ts"))
            {
                xobj.SetTS(Int64.Parse(xmlObject.GetAttribute("ts")));
            }
            // по всем свойствам без признака loaded="0"
            foreach (XmlElement xmlProp in xmlObject.SelectNodes("*[not(@loaded)]"))
            {
                XPropInfoBase propInfo = typeInfo.GetProp(xmlProp.LocalName);
                // xml-узлы не соответствующие свойствам из МД игнорируем
                if (propInfo == null)
                {
                    continue;
                }

                if (!bToDelete && xmlProp.HasAttribute(XDatagram.ATTR_CHUNCK_CHAIN_ID))
                {
                    xobj.PropertiesWithChunkedData.Add(propInfo.Name, new Guid(xmlProp.GetAttribute(XDatagram.ATTR_CHUNCK_CHAIN_ID)));
                }

                // членство в массиве проигнорируем
                if (propInfo is XPropInfoObjectArray)
                {
                    if (((XPropInfoObjectArray)propInfo).Capacity == XPropCapacity.ArrayMembership)
                    {
                        continue;
                    }
                }
                // пустые массивные свойства новых объектов проигнорируем
                if (bIsNew)
                {
                    if (propInfo is XPropInfoObjectArray || propInfo is XPropInfoObjectLink)
                    {
                        if (!xmlProp.HasChildNodes)
                        {
                            continue;
                        }
                    }
                }
                vPropValue = getPropValue(xmlProp, propInfo);
                if (bNeedMerge && xobj.HasUpdatedProp(propInfo.Name))
                {
                    bool   bNeedScalarCheck = true;
                    object vPropValueExist  = xobj.GetUpdatedPropValue(propInfo.Name);
                    if (propInfo is XPropInfoObject && !(propInfo is XPropInfoObjectScalar))
                    {
                        // объектное массивное свойство
                        bNeedScalarCheck = false;
                        XPropCapacity capacity  = ((XPropInfoObject)propInfo).Capacity;
                        Guid[]        valuesOld = (Guid[])vPropValueExist;
                        Guid[]        valuesCur = (Guid[])vPropValue;
                        if (capacity == XPropCapacity.Array || (capacity == XPropCapacity.Link && ((XPropInfoObjectLink)propInfo).OrderByProp != null))
                        {
                            // массивы и упорядоченные линки не подвергаются слиянию - только проверке на совпадение значений
                            if (valuesOld.Length != valuesCur.Length)
                            {
                                throw new XMergeConflictException("Не совпадает количество элементов в свойстве " + propInfo.Name);
                            }
                            for (int i = 0; i < valuesOld.Length; ++i)
                            {
                                if (valuesOld[i] != valuesCur[i])
                                {
                                    throw new XMergeConflictException("Не совпадает значение свойства " + propInfo.Name);
                                }
                            }
                        }
                        else
                        {
                            // коллекция и членство в коллекции - произведем слияние
                            ArrayList aValuesNew = new ArrayList(valuesOld.Length + valuesCur.Length);
                            aValuesNew.AddRange(valuesOld);
                            foreach (Guid value in valuesCur)
                            {
                                if (aValuesNew.IndexOf(value) < 0)
                                {
                                    aValuesNew.Add(value);
                                }
                            }

                            Guid[] valuesNew = new Guid[aValuesNew.Count];
                            aValuesNew.CopyTo(valuesNew);
                            vPropValue = valuesNew;
                        }
                    }
                    else if (propInfo is XPropInfoNumeric)
                    {
                        // числовое свойтсво - будем сравнивать значения, если это не индексное свойство линка
                        if (((XPropInfoNumeric)propInfo).OrderedLinkProp != null)
                        {
                            bNeedScalarCheck = false;
                        }
                    }
                    if (bNeedScalarCheck)
                    {
                        // надо сравнить значения скалярного свойства
                        // т.к. Equals - виртуальный метод, то должно работать
                        if (!vPropValueExist.Equals(vPropValue))
                        {
                            throw new XMergeConflictException("Значения свойства " + propInfo.Name + " не совпадают");
                        }
                    }
                }
                xobj.SetUpdatedPropValue(propInfo.Name, vPropValue);
                // Удалено: кусочная загрузка (xmlProp.HasAttribute(ATTR_CHUNCK_CHAIN_ID))
            }
            return(xobj);
        }