Сериализация объектов и передача их на другую машину

6yrop

Пусть есть сущности связанные "многие к одному", например, книги и их категории.
public class Book
{
public string Title;
public CategoryType Category;
}
public class CategoryType
{
public string Name;
}
Как передать 10 книг с сервера на клиента? Если сериализовать каждый объект типа Book отдельно, то некоторые категории будут сериализованы несколько раз, и на клиенте будут восстановлены в два разных объекта. Т.е. нужно сериализовать всю коллекцию из 10 книг сразу и устанавливать поле Book.Category извне (по отношению в классу Book).
А вот если пользоваться data-centric реляционным подходом DataSet-ов, то такой проблемы не возникает.

Dasar

> Если сериализовать каждый объект типа Book отдельно, то некоторые категории будут сериализованы несколько раз, и на клиенте будут восстановлены в два разных объекта. Т.е. нужно сериализовать всю коллекцию из 10 книг сразу и устанавливать поле Book.Category извне (по отношению в классу Book).
Обычно делается, что сериализатор помнит какие объекты он уже сохранил, соответственно при повторных save-ах того же объекта, сохраняется только ссылка.
Например, таким образом сериализация устроена в MFC

Hastya

не понял, речь про Java?
в Java лечится, например, с помощью readResolve

6yrop

Речь идет о .NET.
Список, возвращаемый функцией


public ArrayList My
{
ArrayList s1 = new ArrayList;
s1.Add(1);
ArrayList s2 = new ArrayList;
s2.Add(2);
ArrayList s3 = new ArrayList;
s3.Add(3);
ArrayList p1 = new ArrayList;
p1.Add(s1);
p1.Add(s2);
ArrayList p2 = new ArrayList;
p2.Add(s2);
p2.Add(s3);
ArrayList result = new ArrayList;
result.Add(p1);
result.Add(p2);
return result;
}


по умолчанию сериализуется в


<ArrayOfAnyType xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
<anyType xsi:type="ArrayOfAnyType">
<anyType xsi:type="ArrayOfAnyType">
<anyType xsi:type="xsd:int">1</anyType>
</anyType>
<anyType xsi:type="ArrayOfAnyType">
<anyType xsi:type="xsd:int">2</anyType>
</anyType>
</anyType>
<anyType xsi:type="ArrayOfAnyType">
<anyType xsi:type="ArrayOfAnyType">
<anyType xsi:type="xsd:int">2</anyType>
</anyType>
<anyType xsi:type="ArrayOfAnyType">
<anyType xsi:type="xsd:int">3</anyType>
</anyType>
</anyType>
</ArrayOfAnyType>


видно, что двойка повторилась два раза.

6yrop

с описаной ситуацией сериализатор еще может справиться, а если нужно передать две порции по 5 книг?

Dasar

Если есть две порции, то категории будут два раза передаваться и с DataSet-ом

6yrop

второй раз можно не передавать категории, потом сделать Marriage
точнее второй раз можно передать только те категори,и которые связана с передаваемыми книгами

rosali

Точно не знаю, но пофантазирую...
Есть подозрение, что

по умолчанию

это как раз таки не по умолчанию. Скорее всего в ArrayList дефолтная сериализация переопределена.
А если вместо ArrayList использовать массивы, то же самое получается?

Dasar

Я правильно понял, что ты использовал XmlSerializer?

Dasar

Marriage - это merge?
> точнее второй раз можно передать только те категори,и которые связана с передаваемыми книгами
Такой функционал можно поддержать и на бизнес-entities-ах.

6yrop

Я правильно понял, что ты использовал XmlSerializer?

я создал простейший Web Service, в IE можно посмотреть как передается объект, наверное по-умолчанию используется XmlSerializer.
В bin-формате по-другому?

6yrop

Marriage - это merge?

да.
Такой функционал можно поддержать и на бизнес-entities-ах.

Как? (то что можно всё, это понятно). Если ничего дополнительного не делать, то одна категория может превратиться в несколько объектов, и, например, при изменении имени категории придется менять свойство у нескольких объектов.

Dasar

Скорее всего по-умолчанию в web-service-ах используется soap-сериализатор
Попробуй, в примере, вместо чисел использовать объекты, есть подозрение, что числа всегда сохраняются по значению.
ps
soap-serializer и bin-serializer - одиннаково устроены, и умеют правильно сохранять объектные графы.
xml-serializer - вообще любую ссылку рассматривает как ссылку "parent<->child"

Dasar

при save и загрузке строится hash, в котором регистрируются все загружаемые(выгружаемые)объекты
при save, если объект уже сохранялся, то вместо самого объекта сохраняется ссылка на него (некий id)
при лоад-t, если встречается ссылка, то востанавливается ссылка на реальный объект.

6yrop

Попробуй, в примере, вместо чисел использовать объекты, есть подозрение, что числа всегда сохраняются по значению

в моем примере специально введено дополнительное вложение, чтобы были объекты
s2 это объект

6yrop

ок, вроде не сложно, но всё-таки дополнительные действия, я не против и такого подхода

Dasar

Действия ровно те же самые, что и при использовании data.set-ов: взять готовую библиотечку и заюзать

Dasar

все-таки твой web-service какой-то "неправильный" serializer использует.
при использовании soap-formatter-а генерится следующий xml:


<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<a1:ArrayList id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Collections">
<_items href="#ref-2"/>
<_size>2</_size>
<_version>2</_version>
</a1:ArrayList>
<SOAP-ENC:Array id="ref-2" SOAP-ENC:arrayType="xsd:anyType[16]">
<item href="#ref-3"/>
<item href="#ref-4"/>
</SOAP-ENC:Array>
<a1:ArrayList id="ref-3" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Collections">
<_items href="#ref-5"/>
<_size>2</_size>
<_version>2</_version>
</a1:ArrayList>
<a1:ArrayList id="ref-4" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Collections">
<_items href="#ref-6"/>
<_size>2</_size>
<_version>2</_version>
</a1:ArrayList>
<SOAP-ENC:Array id="ref-5" SOAP-ENC:arrayType="xsd:anyType[16]">
<item href="#ref-7"/>
<item href="#ref-8"/>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-6" SOAP-ENC:arrayType="xsd:anyType[16]">
<item href="#ref-8"/>
<item href="#ref-9"/>
</SOAP-ENC:Array>
<a1:ArrayList id="ref-7" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Collections">
<_items href="#ref-10"/>
<_size>1</_size>
<_version>1</_version>
</a1:ArrayList>
<a1:ArrayList id="ref-8" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Collections">
<_items href="#ref-11"/>
<_size>1</_size>
<_version>1</_version>
</a1:ArrayList>
<a1:ArrayList id="ref-9" xmlns:a1="http://schemas.microsoft.com/clr/ns/System.Collections">
<_items href="#ref-12"/>
<_size>1</_size>
<_version>1</_version>
</a1:ArrayList>
<SOAP-ENC:Array id="ref-10" SOAP-ENC:arrayType="xsd:anyType[16]">
<item xsi:type="xsd:int">1</item>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-11" SOAP-ENC:arrayType="xsd:anyType[16]">
<item xsi:type="xsd:int">2</item>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-12" SOAP-ENC:arrayType="xsd:anyType[16]">
<item xsi:type="xsd:int">3</item>
</SOAP-ENC:Array>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Dasar

При использование же правильных коллекций, xml-получается таким:


static public object[] My2
{
object[] s1 = new object[]{1};
object[] s2 = new object[]{2};
object[] s3 = new object[]{3};
object[] p1 = new object[]{s1, s2};
object[] p2 = new object[]{s2, s3};
return new object[]{p1, p2};
}




<SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
<SOAP-ENV:Body>
<SOAP-ENC:Array SOAP-ENC:arrayType="xsd:anyType[2]">
<item href="#ref-2"/>
<item href="#ref-3"/>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-2" SOAP-ENC:arrayType="xsd:anyType[2]">
<item href="#ref-4"/>
<item href="#ref-5"/>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-3" SOAP-ENC:arrayType="xsd:anyType[2]">
<item href="#ref-5"/>
<item href="#ref-6"/>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-4" SOAP-ENC:arrayType="xsd:anyType[1]">
<item xsi:type="xsd:int">1</item>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-5" SOAP-ENC:arrayType="xsd:anyType[1]">
<item xsi:type="xsd:int">2</item>
</SOAP-ENC:Array>
<SOAP-ENC:Array id="ref-6" SOAP-ENC:arrayType="xsd:anyType[1]">
<item xsi:type="xsd:int">3</item>
</SOAP-ENC:Array>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Оставить комментарий
Имя или ник:
Комментарий: