public void Reset() { if (m_version != m_collection.m_version) { throw new InvalidOperationException("Collection was modified; enumeration operation may not execute"); } m_currentElement = null; }
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; }
public override void Merge(XStorageObjectBase p_xobj) { base.Merge(p_xobj); XStorageObjectToDelete xobj = p_xobj as XStorageObjectToDelete; if (xobj == null) { Debug.Fail("Некорректная реализация XStorageObjectBase::Merge"); throw new ArgumentException(); } }
public void Add(XStorageObjectBase xobj) { IDictionary objects = (IDictionary)m_types[xobj.ObjectType]; if (objects == null) { objects = new Hashtable(1); m_types.Add(xobj.ObjectType, objects); } objects.Add(xobj.ObjectID, xobj); ++m_version; }
public XDatagram GetDatagram(DomainObjectDataSet dataSet) { XDatagram dg = new XDatagram(); IEnumerator enumerator = dataSet.GetModifiedObjectsEnumerator(false); while (enumerator.MoveNext()) { XStorageObjectBase xobj = createXStorageObject((DomainObjectData)enumerator.Current); add(xobj); createObjectsFromLinks(xobj); } fillDatagram(dg); return(dg); }
/// <summary> /// Добавляет ко множеству xml-объект /// </summary> /// <param name="xmlObject"></param> private void Add(XmlElement xmlObject, XTypeInfo typeInfo) { XStorageObjectBase xobj = CreateXStorageObject(xmlObject, typeInfo); XStorageObjectBase xobjExists = (XStorageObjectBase)m_objectsDictionary[xobj.ObjectID]; if (xobjExists != null) { merge(xobjExists, xobj); } else { m_objects.Add(xobj); m_objectsDictionary.Add(xobj.ObjectID, xobj); } }
/// <summary> /// Добавление объекта в датаграмму. Если объект с таким типом и идентификатором уже существует /// </summary> /// <param name="xobj"></param> protected XStorageObjectBase add(XStorageObjectBase xobj) { XStorageObjectBase xobjExists = (XStorageObjectBase)m_objects[xobj]; if (xobjExists == null) { m_objects.Add(xobj, xobj); xobjExists = xobj; } else { xobjExists.Merge(xobj); } return(xobjExists); }
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); } } } }
private void checkReverseProps() { foreach (XStorageObjectBase xobj in m_objects) { if (xobj is XStorageObjectToSave) { foreach (DictionaryEntry entry in ((XStorageObjectToSave)xobj).GetPropsByCapacity(XPropCapacity.CollectionMembership /*, XPropCapacity.Link, XPropCapacity.LinkScalar*/)) { string sPropName = (string)entry.Key; Guid[] valueOIDs = (Guid[])entry.Value; if (valueOIDs.Length == 0) { continue; } XPropInfoObject propInfo = (XPropInfoObject)xobj.TypeInfo.GetProp(sPropName); bool bError = false; foreach (Guid valueOID in valueOIDs) { XStorageObjectBase xobjValue = (XStorageObjectBase)m_objectsDictionary[valueOID]; if (xobjValue == null) { continue; } // владелец обратного свойства есть в датаграмме if (!xobjValue.Props.Contains(propInfo.ReverseProp.Name)) { continue; } // владелец обратного свойства содержит это обратное свойство object vValue = xobjValue.Props[propInfo.ReverseProp.Name]; Debug.Assert(vValue != null); if (propInfo.ReverseProp is XPropInfoObjectScalar) { if (vValue == DBNull.Value || (Guid)vValue != xobj.ObjectID) { bError = true; } } else { // обратное свойство - коллекция, в свойстве массив гидов Guid[] valueOIDsReverse = (Guid[])vValue; // в этом массиве должна быть ссылка на текущий объект (xobj) bool bFound = false; foreach (Guid valueOIDReverse in valueOIDsReverse) { if (valueOIDReverse == xobj.ObjectID) { bFound = true; break; } } if (!bFound) { bError = true; } } if (bError) { throw new XInvalidXmlForestException( String.Format("Не согласованы свойства объектов: {0}[ID='{1}'], свойство {2} и {3}[ID='{4}'], свойство {5}", xobj.ObjectType, // 0 xobj.ObjectID, // 1 sPropName, // 2 xobjValue.ObjectType, // 3 xobjValue.ObjectID, // 4 propInfo.ReverseProp.Name // 5 ) ); } } } } } }
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); }
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 + " не совпадают"); } } } } }
/// <summary> /// Возвращает ключ под которым объект храниться в словаре /// </summary> /// <param name="xobj"></param> /// <returns>Ключ для хранения в словаре</returns> protected string getKey(XStorageObjectBase xobj) { return(xobj.ObjectType + ":" + xobj.ObjectID); }
public XStorageObjectCollectionSimpleEnumerator(XStorageObjectCollection collection) { m_collection = collection; m_version = collection.m_version; m_currentElement = null; }