/// <summary> /// »змен¤ет помеченные свойства объекта, добав뤤 к ним подпись /// </summary> /// <param name="xobj">текущий объект</param> /// <param name="signature">подпись</param> private void modifyObjectProps(DomainObjectData xobj, string signature) { // пройдемс¤ по всем свойствам объекта foreach (string sPropName in xobj.UpdatedPropNames) { // получим информацию о свойстве по его названию XPropInfoBase propInfo = xobj.TypeInfo.GetProp(sPropName); // если подпись дл¤ данного свойства не нужна, пропускаем его if (hasPropSignature(propInfo)) { object vPropValue = xobj.GetUpdatedPropValue(sPropName); if (vPropValue != null && vPropValue != DBNull.Value) { string sText = null; if (propInfo.VarType == XPropType.vt_string || propInfo.VarType == XPropType.vt_text) { sText = (string)vPropValue; } else { throw new ApplicationException("ћеханизм автоподписи применим только к строковым и текстовым пол¤м"); } if (sText != null) { xobj.SetUpdatedPropValue(sPropName, addSignature(sText, signature)); } } } } }
public XStorageObjectBase createXStorageObject(DomainObjectData obj) { XStorageObjectBase xobj; object vPropValue; if (obj.ToDelete) { xobj = new XStorageObjectToDelete(obj.TypeInfo, obj.ObjectID, obj.TS, true); } else { xobj = new XStorageObjectToSave(obj.TypeInfo, obj.ObjectID, obj.TS, obj.IsNew); ((XStorageObjectToSave)xobj).PropertiesWithChunkedData = obj.PropertiesWithChunkedData; } bool bNeedTrackUniqueIndexParticipation = xobj.TypeInfo.HasUniqueIndexes && xobj.TypeInfo.DeferrableIndexes && !obj.ToDelete; foreach (string sPropName in obj.UpdatedPropNames) { vPropValue = obj.GetUpdatedPropValue(sPropName); XPropInfoBase propInfo = obj.TypeInfo.GetProp(sPropName); if (propInfo is XPropInfoNumeric) { if (((XPropInfoSimpleEnumerable)propInfo).IsEnum) { // в качестве значения свойства может быть поcле перечисления, надо привести его в элементарному типу if (vPropValue.GetType().IsEnum) { if (propInfo.VarType == XPropType.vt_i4) { vPropValue = (Int32)vPropValue; } else if (propInfo.VarType == XPropType.vt_i2) { vPropValue = (Int16)vPropValue; } else // if (propInfo.VarType == XPropType.vt_ui1) { vPropValue = (byte)vPropValue; } } } } if (vPropValue != null) { xobj.Props[sPropName] = vPropValue; } // если свойство участвует в уникальном индексе, запомним это if (bNeedTrackUniqueIndexParticipation) { if (xobj.TypeInfo.IsPropIncludedIntoUniqueIndex(sPropName)) { ((XStorageObjectToSave)xobj).ParticipateInUniqueIndex = true; } } } return(xobj); }
protected string getObjectValueTypeName(string sObjectType, string sPropName, XStorageConnection con) { XPropInfoBase xprop_base = con.MetadataManager.GetTypeInfo(sObjectType).GetProp(sPropName); if (!(xprop_base is XPropInfoObject)) { throw new ArgumentException("Поддерживаются только объектные свойства"); } return(((XPropInfoObject)xprop_base).ReferedType.Name); }
protected DomainPropObjectBase getReverseProp(DomainObject obj) { XPropInfoBase xprop = PropInfo.ReverseProp; if (xprop != null) { // задано обратное свойства return((DomainPropObjectBase)obj.Props[xprop.Name]); } return(null); }
/// <summary> /// ѕровер¤ет, должно ли свойство иметь подпись /// </summary> /// <param name="propInfo">метаданные свойства</param> /// <returns>true - свойство должно иметь подпись</returns> private bool hasPropSignature(XPropInfoBase propInfo) { // если свойство не текстовое, подпись не нужна if (propInfo.VarType != XPropType.vt_string && propInfo.VarType != XPropType.vt_text) { return(false); } // если свойство содержит элемент auto-signature, равный true, // то подпись нужна if (propInfo.SelectSingleNode("itds:auto-signature[.='true']") != null) { return(true); } // иначе подпись не нужна return(false); }
private static object getPropValue(XmlElement xmlProp, XPropInfoBase propInfo) { object propValue; if (propInfo is XPropInfoObjectScalar) { if (!xmlProp.HasChildNodes) { propValue = DBNull.Value; } else { propValue = new Guid(xmlProp.FirstChild.Attributes["oid"].Value); } } else if (propInfo is IXPropInfoScalar) { // скалярное необъектное свойство propValue = XmlPropValueReader.GetTypedValueFromXml(xmlProp, propInfo.VarType); // if (propInfo.VarType == XPropType.vt_bin || propInfo.VarType == XPropType.vt_text) // propValue = XStorageLOBPropHandle.Create(propInfo.VarType, propValue); //else if (propValue == null) { propValue = DBNull.Value; } } else { // массивное объектное свойство XmlNodeList xmlChildren = xmlProp.SelectNodes("*"); Guid[] oids = new Guid[xmlChildren.Count]; int i = -1; foreach (XmlElement xmlChildObj in xmlChildren) { oids[++i] = new Guid(xmlChildObj.GetAttribute("oid")); } propValue = oids; //propValue = new XStorageObjectArrayPropHandle(oids); } return(propValue); }
/// <summary> /// Записывает данные LOB-свойства /// </summary> /// <param name="xobj">объект-владелец свойства</param> /// <param name="xmlProp">xml-свойство</param> /// <param name="propInfo">описание свойства</param> private void writeLOBProp(DomainObjectData xobj, XmlElement xmlProp, XPropInfoBase propInfo) { string sPropName = propInfo.Name; XPropType vt = propInfo.VarType; object vPropValue; int nDataSize = 0; if (xobj.IsNew) { vPropValue = xobj.GetUpdatedPropValue(sPropName); if (vPropValue == null || vPropValue == DBNull.Value) { nDataSize = 0; } else { xmlProp.InnerText = XmlPropValueWriter.GetXmlTypedValue(vPropValue, vt); } } else { nDataSize = xobj.GetLoadedPropDataSize(sPropName); if (nDataSize > 0) { vPropValue = xobj.GetLoadedPropValue(sPropName); if (vPropValue == null) { // данные в свойстве есть, но не загружены xmlProp.SetAttribute("loaded", "0"); } else { xmlProp.InnerText = XmlPropValueWriter.GetXmlTypedValue(vPropValue, vt); } } } xmlProp.SetAttribute("data-size", XmlConvert.ToString(nDataSize)); }
public DomainPropLOB(DomainObject objParent, XPropInfoBase xpropInfo) : base(objParent, xpropInfo) { m_state = DomainPropLoadableState.Ghost; }
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 + " не совпадают"); } } } } }
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); }
/// <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); }
protected virtual DomainPropBase createPropInstace(DomainObject obj, XPropInfoBase xpropInfo) { DomainPropBase prop; switch (xpropInfo.VarType) { case XPropType.vt_object: if (xpropInfo is XPropInfoObjectScalar) { prop = new DomainPropObjectScalar(obj, (XPropInfoObject)xpropInfo); } else if (xpropInfo is XPropInfoObjectArray) { prop = new DomainPropCollection(obj, (XPropInfoObjectArray)xpropInfo); } else if (xpropInfo is XPropInfoObjectLink) { prop = new DomainPropLink(obj, (XPropInfoObjectLink)xpropInfo); } else { throw new ApplicationException(); } break; case XPropType.vt_text: prop = new DomainPropText(obj, xpropInfo); break; case XPropType.vt_bin: prop = new DomainPropBinary(obj, xpropInfo); break; case XPropType.vt_boolean: prop = new DomainPropBoolean(obj, (XPropInfoBoolean)xpropInfo); break; case XPropType.vt_string: prop = new DomainPropString(obj, (XPropInfoString)xpropInfo); break; case XPropType.vt_uuid: prop = new DomainPropUUID(obj, (XPropInfoSimple)xpropInfo); break; case XPropType.vt_smallBin: prop = new DomainPropSmallBin(obj, (XPropInfoSmallBin)xpropInfo); break; case XPropType.vt_r4: prop = new DomainPropNumericSingle(obj, (XPropInfoNumeric)xpropInfo); break; case XPropType.vt_r8: prop = new DomainPropNumericDouble(obj, (XPropInfoNumeric)xpropInfo); break; case XPropType.vt_fixed: prop = new DomainPropNumericDecimal(obj, (XPropInfoNumeric)xpropInfo); break; default: if (xpropInfo is XPropInfoNumeric) { prop = new DomainPropNumericInt(obj, (XPropInfoNumeric)xpropInfo); } else if (xpropInfo is XPropInfoDatetime) { prop = new DomainPropDateTime(obj, (XPropInfoDatetime)xpropInfo); } else { throw new ApplicationException(); } break; } return(prop); }
internal void deleteObject(DomainObject obj) { OnDeletingObject(new DeletingObjectEventArgs(obj)); // Сформируем список ссылок и список обязательных ссылок на текущий объект ArrayList aReferences = new ArrayList(); ArrayList aMandatoryReferences = new ArrayList(); // по всем свойствам Скаляр, Массив, Коллекция, ссылающиймся на тип текущего объекта foreach (XPropInfoObject propInfo in obj.TypeInfo.ReferencesOnMe) { // по всем объектам реестра, обладающим текущим свойством foreach (DomainObject objRef in m_objects.GetSameTypeObjects(propInfo.ParentType.Name).Values) { // ссылки со стороны заглушек и инвалиндых объектов нам не интересны if (!objRef.IsLoaded && !objRef.IsNew) { continue; } DomainPropBase prop = (DomainPropBase)objRef.Props[propInfo.Name]; if (prop == null) { continue; } if (prop is DomainPropObjectScalar) { DomainPropObjectScalar propScalar = (DomainPropObjectScalar)prop; if (propScalar.HasReferedOn(obj.ObjectID)) { aReferences.Add(propScalar); if (propScalar.PropInfo.NotNull) { aMandatoryReferences.Add(propScalar); } } } else if (prop is DomainPropCollectionBase) { DomainPropCollectionBase propCol = (DomainPropCollectionBase)prop; if (propCol.FindObjectValue(obj.ObjectID) != null) { aReferences.Add(prop); // если массив или коллекция без обратного свойства, значит свойство обязательное if (!(propCol.PropInfo.Capacity == XPropCapacity.Collection && propCol.PropInfo.ReverseProp == null)) { aMandatoryReferences.Add(prop); } } } } } if (aReferences.Count > 0) { if (OnDeleteObjectConflict(new DeleteObjectConflictEventArgs(obj, aReferences, aMandatoryReferences))) { // TODO: а что делать дальше??? return; } else { throw new InvalidOperationException("Объект " + obj.ObjectType + " [" + obj.ObjectID.ToString() + "] не может быть удален, т.к. на него имеются обязательные ссылки"); } } // раз объект можно удалять, вычистим ссылки на него из линков, членств в коллекции и массиве foreach (DomainPropBase prop in obj.Props.Values) { if (prop is DomainPropObjectBase) { XPropInfoBase revPropInfo = ((DomainPropObjectBase)prop).PropInfo.ReverseProp; // синхронизируем "слабые" обратные свойства, т.е. удалим ссылки на текущий объект if (revPropInfo != null) { if (prop is DomainPropObjectScalar) { // удалим текущий объект из обратного линка DomainPropObjectScalar propScalar = (DomainPropObjectScalar)prop; if (!propScalar.IsNull) { ((DomainPropLink)propScalar.Value.Props[revPropInfo.Name]).internal_AddPendingAction(DomainPropPendingActionMode.Remove, obj); } } else if (prop is DomainPropArray || prop is DomainPropCollection) { // удалим текущий объект из обратного членства в массиве или членства в коллекции DomainPropCollectionBase propArray = (DomainPropCollectionBase)prop; foreach (DomainObject objValue in propArray.Internal_Values) { ((DomainPropCollectionBase)objValue.Props[revPropInfo.Name]).internal_AddPendingAction(DomainPropPendingActionMode.Remove, obj); } } } } } if (obj.IsNew) { m_objects.Remove(obj); } obj.setDeleted(); }
public DomainPropObjectBase(DomainObject obj, XPropInfoBase xpropInfo) : base(obj, xpropInfo) { }
public DomainPropText(DomainObject objParent, XPropInfoBase xpropInfo) : base(objParent, xpropInfo) { }
public DomainPropBase(DomainObject obj, XPropInfoBase xpropInfo) { m_objParent = obj; m_xpropInfo = xpropInfo; }
/// <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); }
private void checkAndSyncReverseProps(DomainObjectDataSet dataSet) { IEnumerator enumerator = dataSet.GetModifiedObjectsEnumerator(true); object vPropValue; while (enumerator.MoveNext()) { DomainObjectData xobj = (DomainObjectData)enumerator.Current; foreach (string sPropName in xobj.UpdatedPropNames) { XPropInfoBase propInfo = xobj.TypeInfo.GetProp(sPropName); Debug.Assert(propInfo != null); if (propInfo.VarType != XPropType.vt_object) { continue; } XPropInfoObject propInfoObj = (XPropInfoObject)propInfo; if (propInfoObj.Capacity == XPropCapacity.CollectionMembership || propInfoObj.Capacity == XPropCapacity.Link) { Guid[] values = (Guid[])xobj.GetUpdatedPropValue(sPropName); if (values.Length > 0) { foreach (Guid valueObjectID in values) { bool bError = false; DomainObjectData xobjValue = dataSet.Find(propInfoObj.ReferedType.Name, valueObjectID); // объект-значение объектного свойства sPropName есть в контексте и он будет сохраняться if (xobjValue != null && xobjValue.HasNewData) { // если текущее свойство "членство в коллекции" и в объекте-значении есть обратное свойство (коллекция), // проверим, что обратное свойство содержит ссылку на текущий объект (xobj) if (propInfoObj.Capacity == XPropCapacity.CollectionMembership && xobjValue.HasUpdatedProp(propInfoObj.ReverseProp.Name)) { Guid[] propRevValues = (Guid[])xobjValue.GetUpdatedPropValue(propInfoObj.ReverseProp.Name); Debug.Assert(propRevValues != null); // если обратное свойство (коллекция) не содержит ссылку на текущий объект - исключение if (Array.IndexOf(propRevValues, xobj.ObjectID) == -1) { bError = true; } } // если текущее свойство линк, то установим обратное свойство - объектный скаляр else if (propInfoObj.Capacity == XPropCapacity.Link) { vPropValue = xobjValue.GetUpdatedPropValue(propInfoObj.ReverseProp.Name); // если обратное свойство (скаляр) установлено, то проверим, что оно ссылается на текущий объект if (vPropValue != null) { Debug.Assert(vPropValue is Guid); if ((vPropValue is DBNull) || ((Guid)vPropValue) != xobj.ObjectID) { bError = true; } } // обратное свойство неустановлено - установим его на текущий объект else { xobjValue.SetUpdatedPropValue(propInfoObj.ReverseProp.Name, xobj.ObjectID); } } 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 propInfoObj.ReverseProp.Name // 5 )); } } } } } } } }
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); }
private void serializePropertyInternal(DomainObjectData xobj, XmlElement xmlProp, PreloadsNavigator nav) { DomainObjectDataSet dataSet = xobj.Context; string sPropName; object vPropValue; sPropName = xmlProp.LocalName; XPropInfoBase propInfo = xobj.TypeInfo.GetProp(sPropName); switch (propInfo.VarType) { case XPropType.vt_bin: case XPropType.vt_text: writeLOBProp(xobj, xmlProp, propInfo); break; case XPropType.vt_object: if (propInfo is XPropInfoObjectScalar) { // скалярное свойство if (xobj.IsNew) { vPropValue = xobj.GetUpdatedPropValue(sPropName); } else { vPropValue = xobj.GetLoadedPropValue(sPropName); } if (vPropValue != null && !(vPropValue is DBNull)) { addValueIntoObjectProp(dataSet, xmlProp, (XPropInfoObjectScalar)propInfo, (Guid)vPropValue, nav); } } else { // массивное свойство if (xobj.IsNew) { vPropValue = xobj.GetUpdatedPropValue(sPropName); } else { vPropValue = xobj.GetLoadedPropValue(sPropName); } writeArrayProp(xobj, xmlProp, vPropValue, (XPropInfoObject)propInfo, nav); } break; default: if (xobj.IsNew) { vPropValue = xobj.GetUpdatedPropValue(sPropName); } else { vPropValue = xobj.GetLoadedPropValue(sPropName); } if (vPropValue != null && !(vPropValue is DBNull)) { xmlProp.InnerText = XmlPropValueWriter.GetXmlTypedValue(vPropValue, propInfo.VarType); } else { xmlProp.InnerText = String.Empty; } break; } }