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); }
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); }