C # Castle ActiveRecord: как элегантно (XML) сериализовать объекты ActiveRecord?

Мне сложно найти информацию о том, как элегантно сериализовать объекты ActiveRecord.

Мы хотели бы использовать XML в качестве формата, потому что нам нужно выводить наши объекты таким образом, чтобы другая программа могла их реально проанализировать.

XML-сериализацию обычно очень легко реализовать, но проблема возникает при попытке сериализации объекта, возвращаемого из базы данных ActiveRecord. База данных возвращает прокси-класс объекта, тип которого нельзя явно предвидеть с помощью атрибута [XmlInclude].

Например:

public class Foo : ActiveRecordLinqBase<Foo>
{
   public virtual string Bar{get;set;}

   public virtual int FooId{get;set;}

   public Foo(string bar)
   {
      Bar = bar;
   }

   public static void FooSerializeExample()
   {
      Foo tehFoozor = new Foo("omgFoo!");
      tehFoozor.SaveAndFlush();
      int id = tehFoozor.FooId;

      //...
      //Assume new ActiveRecord session.

      XmlSerializer serializer = new XmlSerializer(typeof(Foo));

      Foo tehFoozorToSerialize = Foo.Find(id);

      using(Stream stream = File.OpenWrite("tehFoozor.xml"))
      {
         serializer.Serialize(stream, tehFoozorToSerialize); //Will fail
      }
   }
}

При сериализации здесь мы получим сообщение:
«Тип FooProxy2e2de24df9be42909d13a67fdb00b981 не ожидался. Используйте атрибут XmlInclude или SoapInclude, чтобы указать типы, которые не известны статически».

где тип прокси будет совершенно непредсказуемым (по крайней мере, насколько мне известно).

В качестве временного решения моя команда вставила свойства каждого объекта AR в интерфейсы. Затем мы реализовали объекты «Контейнер» для каждого, которые по сути являются Xml-сериализуемыми версиями объектов без дополненной реальности. Учитывая тот факт, что в настоящее время у нас есть 18 различных объектов AR, которые сериализованы, это 36 дополнительных файлов в нашем решении! Что-то (все) подсказывает мне, что это плохое решение, но я не смог найти лучшего способа.

Мы также пробовали использовать Soap Formatter, но поскольку ActiveRecrodLinqBase ‹> не« помечен как сериализуемый », это тоже было тупиком.


person Anj    schedule 08.10.2009    source источник
comment
После дополнительных поисков я обнаружил, что это происходит потому, что мы используем отложенную загрузку. Это не то, что мы можем пойти на компромисс, потому что объекты, которые мы будем загружать, будут иметь глубокую иерархию, иногда содержащую тысячи частей, которые должны быть загружены и отображены через Microsoft MVC. Один из старших разработчиков выстраивается в очередь, чтобы рассмотреть возможность решения проблемы с помощью рефлексии. Кто-нибудь еще когда-нибудь проходил через это?   -  person Anj    schedule 08.10.2009


Ответы (2)


Получите все, что вам нужно, затем используйте AutoMapper, чтобы сопоставить это с DTO и сериализовать эти DTO.

Ошибка прокси, которую вы получаете, предполагает, что ваши DTO фактически используют прокси-коллекции NHibernate, тогда как вместо этого они должны использовать простой List<T> или массивы. Убедитесь, что вы используете ToList() или аналогичный.

Кроме того, вам не нужно использовать интерфейсы для сопоставления DTO.

person Mauricio Scheffer    schedule 08.10.2009
comment
Я согласен .. Никогда не пытайтесь пересылать реальные объекты по сети. Айенде однажды написал об этом, и я согласен с ним: ayende .com / Blog / archive / 2009/05/14 / the-stripper-pattern.aspx - person Tigraine; 09.10.2009
comment
Я мог ошибаться, но я считаю, что это то, что мы уже делаем: сопоставляем (не используя AutoMapper, потому что он не смог упростить процесс сопоставления в этой ситуации) объекты в базовые клоны объекта, а затем сериализуем их. Как я упоминал ранее, это добавляет к нашему решению 36 файлов, и это не включает файлы модульного теста. @Tigraine: мы не отправляем фактические объекты по сети, но нам нужно загружать части каждого объекта при получении данных, которые мы БУДЕМ отправлять по сети. Вот почему нам нужна отложенная загрузка. - person Anj; 09.10.2009
comment
Вы правы, вы уже используете DTO, но кажется, что отображение DTO не совсем правильное. См. Мой обновленный ответ. - person Mauricio Scheffer; 09.10.2009
comment
Проблема не зависит от типа коллекций в объектах. Я использовал [XmlIgnore], чтобы игнорировать каждую из фактических коллекций, и использовал [XmlArray (‹PropertyName›)] и [XmlArrayItem (‹ArrayItemType›)] в отдельном свойстве оболочки, которое преобразует коллекцию в / из сериализуемого массива. Текущее решение преобразуется в / из объектов и сериализуется просто отлично, но это не то элегантное решение, которое нам нужно. Один из старших разработчиков изучает возможность использования специального решения XmlSerialization, которое использует глубокую рефлексию. - person Anj; 09.10.2009
comment
Нет необходимости в атрибутах xml или пользовательских сериализациях. Вам нужно только убедиться, что DTO не имеют прокси и представляют собой простые списки / массивы. Проверяйте везде, где можно использовать прокси. Если это не коллекции, проверьте ленивый [BelongsTo] - person Mauricio Scheffer; 09.10.2009
comment
Я ценю ваш вклад, но я считаю, что это обсуждение дает ответ на неправильный вопрос. Наше текущее решение, которое отображает DTO и сериализует / десериализует их, логически работает и не имеет проблем. Однако мы ищем более элегантное решение, которое не предполагает создания DTO для каждого объекта, который мы хотим сериализовать. - person Anj; 09.10.2009
comment
О, хорошо, извините за недоразумение - person Mauricio Scheffer; 09.10.2009

Попробуйте DataContractSerializer.

Его эквивалентом [XmlInclude] является [KnownType], который включает версию, которая может динамически предоставлять тип для включения при первом отражении типа. См. http://msdn.microsoft.com/en-us/library/ms730167.aspx

Кроме того, я думаю (хотя и не уверен на 100%), что .NET4.0 будет включать функцию «Type Mapper» в DataContractSerializer, которая специально упрощает подобные сценарии.

Если вы все же попробуете DCS и столкнетесь с вопросами, оставьте комментарий к этому ответу, и я постараюсь на них ответить.

person Eugene Osovetsky    schedule 09.10.2009
comment
Проверим, жизнеспособно ли это решение, и обновим здесь результаты. Спасибо! - person Anj; 09.10.2009