SyncDataServerFunctions.cs 9.93 KB
using System;
using System.Collections.Generic;
using System.Linq;
using Sungero.Core;
using Sungero.CoreEntities;
using Sungero.Domain.SessionExtensions;
using Sungero.Domain.Shared;
using DirRX.Storage.SyncData;
using Newtonsoft.Json.Linq;
using Sungero.Metadata;

namespace DirRX.Storage.Server
{
  partial class SyncDataFunctions
  {
    /// <summary>
    /// Создать или обновить запись справочника по json-описанию.
    /// </summary>
    /// <returns>Сообщение об ошибке, либо пустая строка при успешном выполнении.</returns>
    [Public]
    public virtual string AddOrUpdateEntity()
    {
      // Распарсить данные. Проверить необходимость проведения синхронизации.
      if (string.IsNullOrWhiteSpace(_obj.Data))
        return SyncDatas.Resources.ErrorEmptyData;
      
      var jsonData = JObject.Parse(_obj.Data);
      if (jsonData == null || !jsonData.HasValues)
        return SyncDatas.Resources.ErrorInvalidDataFormat;
      
      // Получить систему-источник.
      var systemUid = jsonData.Value<string>("SystemUid");
      var externalSystem = Storage.ExternalSystems.GetAllCached(x => x.SourceUid.ToLower() == systemUid.ToLower()).FirstOrDefault();
      if (externalSystem == null)
        return SyncDatas.Resources.ErrorSourceSystemNotFoundFormat(systemUid);

      // Получить и проверить настройки для интегрируемого справочника.
      var sourceName = jsonData.Value<string>("SourceName");
      var sourceType = jsonData.Value<string>("SourceType");
      var archiveName = jsonData.Value<string>("ArchiveName");
      var archiveType = jsonData.Value<string>("ArchiveType");
      
      var externalEntity = Storage.ExternalEntities.Null;
      
      if (archiveType != string.Empty)
        externalEntity = Storage.ExternalEntities.GetAll(x => x.ExternalSystem.Equals(externalSystem) && x.EntityType.ToLower() == archiveType.ToLower()).FirstOrDefault();
      
      if (externalEntity == null && sourceType != string.Empty)
        externalEntity = Storage.ExternalEntities.GetAll(x => x.ExternalSystem.Equals(externalSystem) && x.Uid.ToLower() == sourceType.ToLower()).FirstOrDefault();
      
      if (externalEntity == null)
        return SyncDatas.Resources.ErrorEntityNotFoundFormat(archiveType != string.Empty ? archiveType : sourceType);
      
      if (externalEntity.MappingMode != Storage.ExternalEntity.MappingMode.Auto)
        return SyncDatas.Resources.ErrorSynchronizationNotConfiguredFormat(externalEntity.DisplayValue);
      
      if (archiveType == string.Empty)
        archiveType = externalEntity.EntityType;
      
      if (string.IsNullOrEmpty(archiveType))
        return SyncDatas.Resources.ErrorArchiveTypeNotSpecified;
      
      // Определить ИД записи исходной системы.
      var jsonProperties = jsonData.Value<JArray>("Properties");
      if (jsonProperties == null || !jsonProperties.Any(x => x.Value<string>("Name") == "_sourceId"))
        return SyncDatas.Resources.ErrorEntityRecordIdNotFound;
      
      var sourceId = jsonProperties.First(x => x.Value<string>("Name") == "_sourceId").Value<string>("Value");
      if (string.IsNullOrEmpty(sourceId))
        return SyncDatas.Resources.ErrorEmptyEntityRecordId;
      
      // Найти связанную запись архивной системы.
      var link = LongTermArchive.ExternalEntityLinks.GetAll(x => x.ExtSystemId.ToLower() == _obj.ExternalSystem.SourceUid.ToLower() &&
                                                            x.ExtEntityType.ToLower() == sourceType.ToLower() &&
                                                            x.EntityType.ToLower() == archiveType.ToLower() &&
                                                            x.ExtEntityId.ToLower() == sourceId.ToLower() &&
                                                            x.EntityId.HasValue)
        .OrderByDescending(x => x.Id)
        .FirstOrDefault();
      
      Sungero.Domain.Shared.IEntity entity = null;
      var type = Sungero.Domain.Shared.TypeExtension.GetTypeByGuid(Guid.Parse(archiveType));
      
      // Открыть запись.
      if (link != null)
      {
        try
        {
          using (var session = new Sungero.Domain.Session())
          {
            entity = session.Get(type, link.EntityId.Value);
          }
        }
        catch
        {
          // Если не удалось открыть запись, удалить убитую ссылку.
          Storage.PublicFunctions.Module.DeleteExternalEntityLink(link);
          link = null;
        }
      }
      
      // Создать новую запись.
      if (entity == null)
      {
        try
        {
          using (var session = new Sungero.Domain.Session())
          {
            entity = session.Create(type);
          }
        }
        catch (Exception e)
        {
          Logger.Debug(e.ToString());
          return SyncDatas.Resources.ErrorCreatingEntityFormat((e.InnerException != null ? e.InnerException : e).Message);
        }
      }

      // Заполнить значения свойств в зависимости от их типа.
      var properties = entity.GetType().GetProperties();
      foreach (var jsonProp in jsonProperties)
      {
        var propertyName = jsonProp.Value<string>("Name");
        var propertyStringValue = jsonProp.Value<string>("Value");
        
        if (propertyName != "_sourceId")
        {
          var property = properties.Where(p => p.Name == propertyName).LastOrDefault();
          if (property != null)
          {
            Type propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;

            try
            {
              if (propertyType.IsEntity())
              {
                int childEntityId;
                
                var childTypeGuid = propertyType.GetEntityMetadata().GetOriginal().NameGuid.ToString();
                
                var childExternalEntity = Storage.ExternalEntities.GetAll(x => x.ExternalSystem.Equals(_obj.ExternalSystem) &&
                                                                          x.EntityType.ToLower() == childTypeGuid.ToLower())
                  .FirstOrDefault();
                
                if (childExternalEntity != null && childExternalEntity.MappingMode != Storage.ExternalEntity.MappingMode.NoMapping)
                {
                  var childLink = LongTermArchive.ExternalEntityLinks.GetAll(x => x.ExtSystemId.ToLower() == childExternalEntity.ExternalSystem.SourceUid.ToLower() &&
                                                                             x.ExtEntityType.ToLower() == childExternalEntity.Uid.ToLower() &&
                                                                             x.EntityType.ToLower() == childExternalEntity.EntityType.ToLower() &&
                                                                             x.ExtEntityId.ToLower() == propertyStringValue.ToLower() &&
                                                                             x.EntityId.HasValue)
                    .OrderByDescending(x => x.Id)
                    .FirstOrDefault();
                  
                  childEntityId = childLink != null ? childLink.EntityId.Value : 0;
                }
                else
                {
                  int.TryParse(propertyStringValue, out childEntityId);
                }

                if (childEntityId > 0)
                {
                  using (var anotherSession = new Sungero.Domain.Session())
                  {
                    var childEntity = anotherSession.Get(propertyType, childEntityId);
                    property.SetValue(entity, childEntity);
                  }
                }
              }
              else if (propertyType.FullName == "Sungero.Core.Enumeration")
              {
                if (!string.IsNullOrEmpty(propertyStringValue))
                {
                  var enumValue = new Sungero.Core.Enumeration(propertyStringValue);
                  property.SetValue(entity, enumValue);
                }
                else
                {
                  property.SetValue(entity, null);
                }
              }
              else if (propertyType.FullName == "System.Guid")
                property.SetValue(entity, Guid.NewGuid());
              else
              {
                object safeValue = propertyStringValue == string.Empty ? null : Convert.ChangeType(propertyStringValue, propertyType);
                property.SetValue(entity, safeValue);
              }
            }
            catch (ArgumentException ex)
            {
              Logger.Debug("Не удалось присвоить значение " + propertyStringValue + "  свойству " + property.Name + " типа " + propertyType.Name);
              Logger.Debug(ex.ToString());
            }
            catch (Exception e)
            {
              Logger.Debug(e.ToString());
            }
          }
        }
      }
      
      // Сохранить запись справочника. Создать или обновить связь.
      try
      {
        if (entity.State.IsChanged)
          entity.Save();
        
        if (link == null)
        {
          link = LongTermArchive.ExternalEntityLinks.Create();
          link.ExtSystemId = _obj.ExternalSystem.SourceUid;
          link.ExtEntityType = sourceType;
          link.ExtEntityId = sourceId;
          link.EntityType = archiveType;
          link.EntityId = entity.Id;
        }
        link.SyncDate = Calendar.Now;
        link.Save();
      }
      catch (Exception e)
      {
        Logger.Debug(e.ToString());
        return SyncDatas.Resources.ErrorFailedSynchronizeDataFormat((e.InnerException != null ? e.InnerException : e).Message);
      }
      
      return string.Empty;
    }
  }
}