/// <summary> /// Извлечение детейла из сериализованного представления /// </summary> /// <param name="xmldetailobjects"> Текущий элемент xml </param> /// <param name="detail"> Текущий список детейлов </param> /// <param name="assemblies"> Необходимые сборки </param> /// <param name="DataObjectCache"> DataObjectCache </param> /// <param name="deserializedObjectsList"> Словарь десериализованных объектов с их первичными ключами </param> private static void prv_ReadDetail( XmlNodeList xmldetailobjects, DetailArray detail, SortedList assemblies, DataObjectCache DataObjectCache, Dictionary <string, ICSSoft.STORMNET.DataObject> deserializedObjectsList) { for (int j = 0; j < xmldetailobjects.Count; j++) { XmlNode xmldetailobject = xmldetailobjects[j]; Assembly asm = AssemblyLoader.LoadAssembly((string)assemblies[xmldetailobject.Name]); System.Type dotype = asm.GetType(xmldetailobject.Name); DataObject detailobject = DataObjectCache.CreateDataObject(dotype, Information.TranslateValueToPrimaryKeyType(dotype, ((XmlElement)xmldetailobject).GetAttribute("__PrimaryKey"))); prv_XmlElement2DataObject((XmlElement)xmldetailobject, detailobject, assemblies, DataObjectCache, deserializedObjectsList); detail.AddObject(detailobject); } }
/// <summary> /// Скопировать объект данных при работе с ремоутингом (т.к. CopyTo в этом случае не срабатывает) /// Объект datadest должен быть загружен также, как и datasource. /// </summary> /// <param name="datasource"> /// Исходный объект данных. /// </param> /// <param name="datadest"> /// Целевой объект данных. /// </param> protected void prv_CopyDataObject(DataObject datasource, DataObject datadest) { DataObject obj = datadest; DataObject dataobj = datasource; obj.__PrimaryKey = dataobj.__PrimaryKey; string[] lp = dataobj.GetLoadedProperties(); foreach (string propname in lp) { bool bcopy = true; object val = Information.GetPropValueByName(dataobj, propname); if (val != null) { if (val is DataObject) { // Master. DataObject val2 = (DataObject)DataObjectCache.Creator.CreateObject(val.GetType()); val2.SetExistObjectPrimaryKey((val as DataObject).__PrimaryKey); Information.SetPropValueByName(obj, propname, val2); // Тут ничего не делаем. bcopy = false; } else if (val is DetailArray) { DetailArray det = (DetailArray)Information.GetPropValueByName(obj, propname); foreach (DataObject line in (DetailArray)val) { DataObject destline = det.GetByKey(line.__PrimaryKey); if (destline == null) { destline = (DataObject)DataObjectCache.Creator.CreateObject(line.GetType()); destline.SetExistObjectPrimaryKey(line.__PrimaryKey); destline.SetStatus(ObjectStatus.Created); det.AddObject(destline); } prv_CopyDataObject(line, destline); } foreach (DataObject ln in det) { DataObject dd = (val as DetailArray).GetByKey(ln.__PrimaryKey); if (dd == null) { ln.SetStatus(ObjectStatus.Deleted); } } // Тут ничего не делаем. bcopy = false; } } if (bcopy) { // просто пихаем сюда Information.SetPropValueByName(obj, propname, val); } } foreach (string key in dataobj.DynamicProperties.GetAllKeys()) { obj.DynamicProperties.Add(key, dataobj.DynamicProperties[key]); } }
/// <summary> /// Построение объекта данных по сущности OData. /// </summary> /// <param name="edmEntity"> Сущность OData. </param> /// <param name="key"> Значение ключевого поля сущности. </param> /// <param name="dObjs"> Список объектов для обновления. </param> /// <param name="endObject"> Признак, что объект добавляется в конец списка обновления. </param> /// <returns> Объект данных. </returns> private DataObject GetDataObjectByEdmEntity(EdmEntityObject edmEntity, object key, List <DataObject> dObjs, bool endObject = false) { if (edmEntity == null) { return(null); } IEdmEntityType entityType = (IEdmEntityType)edmEntity.ActualEdmType; Type objType = _model.GetDataObjectType(_model.GetEdmEntitySet(entityType).Name); // Значение свойства. object value; // Получим значение ключа. var keyProperty = entityType.Properties().FirstOrDefault(prop => prop.Name == _model.KeyPropertyName); if (key != null) { value = key; } else { edmEntity.TryGetPropertyValue(keyProperty.Name, out value); } // Загрузим объект из хранилища, если он там есть (используем представление по умолчанию), или создадим, если нет, но только для POST. // Тем самым гарантируем загруженность свойств при необходимости обновления и установку нужного статуса. DataObject obj = ReturnDataObject(objType, value); // Добавляем объект в список для обновления, если там ещё нет объекта с таким ключом. var objInList = dObjs.FirstOrDefault(o => o.__PrimaryKey.ToString() == obj.__PrimaryKey.ToString()); if (objInList == null) { if (!endObject) { // Добавляем объект в начало списка. dObjs.Insert(0, obj); } else { // Добавляем в конец списка. dObjs.Add(obj); } } // Все свойства объекта данных означим из пришедшей сущности, если они были там установлены(изменены). foreach (var prop in entityType.Properties()) { string dataObjectPropName = _model.GetDataObjectProperty(entityType.FullTypeName(), prop.Name).Name; if (edmEntity.GetChangedPropertyNames().Contains(prop.Name)) { // Обработка мастеров и детейлов. if (prop is EdmNavigationProperty) { EdmNavigationProperty navProp = (EdmNavigationProperty)prop; edmEntity.TryGetPropertyValue(prop.Name, out value); EdmMultiplicity edmMultiplicity = navProp.TargetMultiplicity(); // var aggregator = Information.GetAgregatePropertyName(objType); // Обработка мастеров. if (edmMultiplicity == EdmMultiplicity.One || edmMultiplicity == EdmMultiplicity.ZeroOrOne) { if (value != null && value is EdmEntityObject) { EdmEntityObject edmMaster = (EdmEntityObject)value; DataObject master = GetDataObjectByEdmEntity(edmMaster, null, dObjs); Information.SetPropValueByName(obj, dataObjectPropName, master); } else { Information.SetPropValueByName(obj, dataObjectPropName, null); } } // Обработка детейлов. if (edmMultiplicity == EdmMultiplicity.Many) { Type detType = Information.GetPropertyType(objType, dataObjectPropName); DetailArray detarr = (DetailArray)Information.GetPropValueByName(obj, dataObjectPropName); if (value != null && value is EdmEntityObjectCollection) { EdmEntityObjectCollection coll = (EdmEntityObjectCollection)value; if (coll != null && coll.Count > 0) { foreach (var edmEnt in coll) { DataObject det = GetDataObjectByEdmEntity( (EdmEntityObject)edmEnt, null, dObjs, true); if (det.__PrimaryKey == null) { detarr.AddObject(det); } else { detarr.SetByKey(det.__PrimaryKey, det); } } } } else { detarr.Clear(); } } } else { // Обработка собственных свойств объекта (неключевых, т.к. ключ устанавливаем при начальной инициализации объекта obj). if (prop.Name != keyProperty.Name) { Type dataObjectPropertyType = Information.GetPropertyType(objType, dataObjectPropName); edmEntity.TryGetPropertyValue(prop.Name, out value); // Если тип свойства относится к одному из зарегистрированных провайдеров файловых свойств, // значит свойство файловое, и его нужно обработать особым образом. if (FileController.HasDataObjectFileProvider(dataObjectPropertyType)) { IDataObjectFileProvider dataObjectFileProvider = FileController.GetDataObjectFileProvider(dataObjectPropertyType); // Обработка файловых свойств объектов данных. string serializedFileDescription = value as string; if (serializedFileDescription == null) { // Файловое свойство было сброшено на клиенте. // Ассоциированный файл должен быть удален, после успешного сохранения изменений. // Для этого запоминаем метаданные ассоциированного файла, до того как свойство будет сброшено // (для получения метаданных свойство будет дочитано в объект данных). // Файловое свойство типа File хранит данные ассоциированного файла прямо в БД, // соответственно из файловой системы просто нечего удалять, // поэтому обходим его стороной, чтобы избежать лишных вычиток файлов из БД. if (dataObjectPropertyType != typeof(File)) { _removingFileDescriptions.Add(dataObjectFileProvider.GetFileDescription(obj, dataObjectPropName)); } // Сбрасываем файловое свойство в изменяемом объекте данных. Information.SetPropValueByName(obj, dataObjectPropName, null); } else { // Файловое свойство было изменено, но не сброшено. // Если в метаданных файла присутствует FileUploadKey значит файл был загружен на сервер, // но еще не был ассоциирован с объектом данных, и это нужно сделать. FileDescription fileDescription = FileDescription.FromJson(serializedFileDescription); if (!(string.IsNullOrEmpty(fileDescription.FileUploadKey) || string.IsNullOrEmpty(fileDescription.FileName))) { Information.SetPropValueByName(obj, dataObjectPropName, dataObjectFileProvider.GetFileProperty(fileDescription)); // Файловое свойство типа File хранит данные ассоциированного файла прямо в БД, // поэтому после успешного сохранения объекта данных, оссоциированный с ним файл должен быть удален из файловой системы. // Для этого запоминаем описание загруженного файла. if (dataObjectPropertyType == typeof(File)) { _removingFileDescriptions.Add(fileDescription); } } } } else { // Преобразование типов для примитивных свойств. if (value is DateTimeOffset) { value = ((DateTimeOffset)value).UtcDateTime; } if (value is EdmEnumObject) { value = ((EdmEnumObject)value).Value; } Information.SetPropValueByName(obj, dataObjectPropName, value); } } } } } return(obj); }