сериализация/десериализация Entity и EntityCollection

Есть задача, в которой нужно будет сериализовывать и десериализовывать entity или коллекцию. Стандартное обращение к JsonConvert.SerializeObject не работает сходу, но можно настроить с помощью пользовательских объектов, чтобы отбрасывались лишние свойства. Но DeserializeObject<Entity> сделать так и не получилось. В доках нашёл функционал в ядре системы, предназначенный для этой задачи. Получился примерно такой код:

        public virtual string Serialize(Entity entity)
        {
            using (var textWriter = new StringWriter())
            using (var writer = GetDataWriter(textWriter))
            {
                entity.WriteData(writer);
                return textWriter.ToString();
            }
        }

        public virtual Entity Deserialize(string schemaName, string stringValue)
        {
            var manager = UserConnection.EntitySchemaManager;
            var entitySchema = manager.GetInstanceByName(schemaName);
            var entity = entitySchema.CreateEntity(UserConnection);
            using (var textReader = new StringReader(stringValue))
            using (var reader = GetReader(textReader))
            {
                entity.ReadData(reader);
                return entity;
            }
        }

        protected override DataWriter GetDataWriter(TextWriter textWriter)
        {
            var settings = new JsonDataWriterSettings()
            {
                WriteDefValues = false,
                QuoteName = false
            };
            var writer = new JsonDataWriter(settings, textWriter);
            return writer;
        }

        protected override DataReader GetReader(TextReader textReader)
        {
            var reader = new JsonDataReader(textReader);
            return reader;
        }

Аналогичный код для EntityCollection. 

Сериализация в json таким образом работает. Но немного странно. В результирующей json-строке есть открывающая фигурная скобка, но нет закрывающей. 

Десериализация в json не работает вообще. ReadData отрабатывает без исключений, но на выходе получается пустой экземпляр без заполненных колонок. Аналогичная проблема с EntityCollection. Только сама коллекция пустая.

Сериализация в xml оказалась вообще неработоспособной. 

У кого-то получалось заставить этот функционал работать? Или может кто нашёл какой-то другой вариант решения задачи?

Нравится

2 комментария
Лучший ответ

Насколько понимаю, для Entity не используют DeserializeObject, в коде конфигурации его используют для фильтров и подобного. Например, для работы с данными в пакете есть свои функции в PackageSchemaDataUtilities: Deserialize и Serialize. Примеры из тестов, проверяющих работу с ними:

   EntitySchema schema = CreateSchema("TestSchema", userConnection.EntitySchemaManager);
   AddIntegerColumn(schema, "ColumnInt");
   AddTextColumn(schema, "ColumnText");
   AddDateTimeColumn(schema, "ColumnDateTime");
   PackageSchemaDataDescriptor dataDescriptor = CreateTestPackageSchemaData(schema.UId, schema.Name);
   foreach (var column in schema.Columns) {
    dataDescriptor.AddColumn(new PackageSchemaDataColumnDescriptor(column.UId, false));
   }
   var testDateTime2012 = DateTime.Parse("2012-01-01 12:00");
   TimeSpan testUtcOffset2012 = TimeZoneInfo.Local.GetUtcOffset(testDateTime2012);
   var testDateTime2013 = DateTime.Parse("2013-01-01 00:00");
   TimeSpan testUtcOffset2013 = TimeZoneInfo.Local.GetUtcOffset(testDateTime2013);
   string columnIdUId = schema.Columns.GetByName("Id").UId.ToString();
   string columnIntUId = schema.Columns.GetByName("ColumnInt").UId.ToString();
   string columnTextUId = schema.Columns.GetByName("ColumnText").UId.ToString();
   string columnDateTimeUId = schema.Columns.GetByName("ColumnDateTime").UId.ToString();
   string data = @"{
    ""PackageData"": [
     {
      ""Row"": [
       {
        ""SchemaColumnUId"": """ + columnIdUId + @""",
        ""Value"": ""f16d852d-d896-4792-99ff-f36fdd0ab2e4""
       },
       {
        ""SchemaColumnUId"": """ + columnIntUId + @""",
        ""Value"": 1
       },
       {
        ""SchemaColumnUId"": """ + columnTextUId + @""",
        ""Value"": ""test 1""
       },
       {
        ""SchemaColumnUId"": """ + columnDateTimeUId + @""",
        ""Value"": ""\/" + testDateTime2012.ToJsonFormat(testUtcOffset2012) + @"\/""
       }
      ]
     },
     {
      ""Row"": [
       {
        ""SchemaColumnUId"": """ + columnIdUId + @""",
        ""Value"": ""8b022a83-796a-426c-8337-b6fd40525a49""
       },
       {
        ""SchemaColumnUId"": """ + columnIntUId + @""",
        ""Value"": 2
       },
       {
        ""SchemaColumnUId"": """ + columnTextUId + @""",
        ""Value"": ""test 2""
       },
       {
        ""SchemaColumnUId"": """ + columnDateTimeUId + @""",
        ""Value"": ""\/" + testDateTime2013.ToJsonFormat(testUtcOffset2013) + @"\/""
       }
      ]
     }
    ]
   }";
   var dataUtilities = new PackageSchemaDataUtilities(userConnection);
   ICollection<Entity> entities = dataUtilities.Deserialize(data.ToStream(), schema);

И обратное:

 EntitySchema schema = CreateSchema("TestSchema", userConnection.EntitySchemaManager, false);
 EntitySchemaColumn columnText = AddTextColumn(schema, "ColumnText");
 ICollection<Entity> entities = new Collection<Entity>();
 var entity = schema.CreateEntity(userConnection);
 entity.SetColumnValue(columnText, "Column Text Value");
 entities.Add(entity);
 string data;
 var dataUtilities = new PackageSchemaDataUtilities(userConnection);
 dataUtilities.SerializeColumnName = true;
 using (var dataStream = new MemoryStream()) {
 	dataUtilities.Serialize(dataStream, entities, schema.Columns.Select(c => c.UId));
 	dataStream.Position = 0;
 	data = StreamUtilities.GetStreamContent(dataStream);
 }

Чтобы работать с ними, используется:

using Terrasoft.Core.Packages;

 

Насколько понимаю, для Entity не используют DeserializeObject, в коде конфигурации его используют для фильтров и подобного. Например, для работы с данными в пакете есть свои функции в PackageSchemaDataUtilities: Deserialize и Serialize. Примеры из тестов, проверяющих работу с ними:

   EntitySchema schema = CreateSchema("TestSchema", userConnection.EntitySchemaManager);
   AddIntegerColumn(schema, "ColumnInt");
   AddTextColumn(schema, "ColumnText");
   AddDateTimeColumn(schema, "ColumnDateTime");
   PackageSchemaDataDescriptor dataDescriptor = CreateTestPackageSchemaData(schema.UId, schema.Name);
   foreach (var column in schema.Columns) {
    dataDescriptor.AddColumn(new PackageSchemaDataColumnDescriptor(column.UId, false));
   }
   var testDateTime2012 = DateTime.Parse("2012-01-01 12:00");
   TimeSpan testUtcOffset2012 = TimeZoneInfo.Local.GetUtcOffset(testDateTime2012);
   var testDateTime2013 = DateTime.Parse("2013-01-01 00:00");
   TimeSpan testUtcOffset2013 = TimeZoneInfo.Local.GetUtcOffset(testDateTime2013);
   string columnIdUId = schema.Columns.GetByName("Id").UId.ToString();
   string columnIntUId = schema.Columns.GetByName("ColumnInt").UId.ToString();
   string columnTextUId = schema.Columns.GetByName("ColumnText").UId.ToString();
   string columnDateTimeUId = schema.Columns.GetByName("ColumnDateTime").UId.ToString();
   string data = @"{
    ""PackageData"": [
     {
      ""Row"": [
       {
        ""SchemaColumnUId"": """ + columnIdUId + @""",
        ""Value"": ""f16d852d-d896-4792-99ff-f36fdd0ab2e4""
       },
       {
        ""SchemaColumnUId"": """ + columnIntUId + @""",
        ""Value"": 1
       },
       {
        ""SchemaColumnUId"": """ + columnTextUId + @""",
        ""Value"": ""test 1""
       },
       {
        ""SchemaColumnUId"": """ + columnDateTimeUId + @""",
        ""Value"": ""\/" + testDateTime2012.ToJsonFormat(testUtcOffset2012) + @"\/""
       }
      ]
     },
     {
      ""Row"": [
       {
        ""SchemaColumnUId"": """ + columnIdUId + @""",
        ""Value"": ""8b022a83-796a-426c-8337-b6fd40525a49""
       },
       {
        ""SchemaColumnUId"": """ + columnIntUId + @""",
        ""Value"": 2
       },
       {
        ""SchemaColumnUId"": """ + columnTextUId + @""",
        ""Value"": ""test 2""
       },
       {
        ""SchemaColumnUId"": """ + columnDateTimeUId + @""",
        ""Value"": ""\/" + testDateTime2013.ToJsonFormat(testUtcOffset2013) + @"\/""
       }
      ]
     }
    ]
   }";
   var dataUtilities = new PackageSchemaDataUtilities(userConnection);
   ICollection<Entity> entities = dataUtilities.Deserialize(data.ToStream(), schema);

И обратное:

 EntitySchema schema = CreateSchema("TestSchema", userConnection.EntitySchemaManager, false);
 EntitySchemaColumn columnText = AddTextColumn(schema, "ColumnText");
 ICollection<Entity> entities = new Collection<Entity>();
 var entity = schema.CreateEntity(userConnection);
 entity.SetColumnValue(columnText, "Column Text Value");
 entities.Add(entity);
 string data;
 var dataUtilities = new PackageSchemaDataUtilities(userConnection);
 dataUtilities.SerializeColumnName = true;
 using (var dataStream = new MemoryStream()) {
 	dataUtilities.Serialize(dataStream, entities, schema.Columns.Select(c => c.UId));
 	dataStream.Position = 0;
 	data = StreamUtilities.GetStreamContent(dataStream);
 }

Чтобы работать с ними, используется:

using Terrasoft.Core.Packages;

 

Зверев Александр,

Благодарю! Такой способ оказался рабочим. 

Показать все комментарии