Могу ли я использовать NHibernate для хранения объекта в сериализованной форме xml? - PullRequest
3 голосов
/ 30 апреля 2009

Скажем, у меня есть такой класс:

public class MyClass
{
    public int Id { get; set; }

    public DateTime Date { get; set; }
    public string String1 { get; set; }
    public string String2 { get; set; }
    public string String3 { get; set; }
    public string String4 { get; set; }
}

Можно ли заставить NHibernate хранить его в следующей схеме?

CREATE TABLE [dbo].[MyClass](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Xml] [varchar](max) NOT NULL,
)

Где Id отображается на Id, но затем все остальные поля сериализуются в XML (или иным образом)? Я не против, если эти другие поля должны идти на дочернем объекте, как показано ниже, если это помогает:

public class MyClass
{
    public int Id { get; set; }

    public AllOtherOptions Options { get; set; }
}

public class AllOtherOptions
{
    public DateTime Date { get; set; }
    public string String1 { get; set; }
    public string String2 { get; set; }
    public string String3 { get; set; }
    public string String4 { get; set; }
}

Ответы [ 2 ]

4 голосов
/ 01 мая 2009

Я думаю о том, чтобы сделать что-то похожее для будущего проекта. Проект требует сбора большого количества данных, но только несколько элементов должны храниться в реляционной базе данных. Я не начал экспериментировать, но это мои мысли до сих пор.

Вы можете отобразить тип данных XML, создав тип, реализующий IUserType. Если дочерний класс (AllOtherOptions) является сериализуемым, вы должны иметь возможность отобразить поле XML как закрытый член в MyClass и сериализовать / десериализовать AllOtherOptions при необходимости. Вы можете либо динамически поддерживать поле XML (звучит как большая работа), либо создать перехватчик для этого. Я думаю, что MyClass будет реализовывать интерфейс, такой как

public interface IXmlObjectContainer
{
    void SerializeChildObjects();
    void DeSerializeChildObjects();
}

и перехватчик будет вызывать эти методы по мере необходимости. Это доказательство идеи концепции. Я, вероятно, уточнил бы это, выставив пары полей xml и сериализуемых объектов, чтобы убрать работу сериализации из реализаторов IXmlObjectContainer. Или, может быть, обработать сериализацию через методы доступа get / set поля XML.

Подробнее:

  1. Работа с полями XML в NHibernate
  2. Другая XML-реализация IUserType
2 голосов
/ 08 ноября 2012

У меня была такая же идея сохранить объект в столбце XML. Моя идея была другой. Я взял код из ссылок и изменил его на общую реализацию IUserType. Таким образом, любое поле / проп [Serializable] может быть сохранено в столбце XML.

public class XmlUserType<T> : IUserType where T : class
{
  public new bool Equals(object x, object y)
  {
    return x == y;
  }

  public int GetHashCode(object x)
  {
    return x.GetHashCode();
  }

  public object NullSafeGet(IDataReader rs, string[] names, object owner)
  {
    if (names.Length != 1)
      throw new InvalidOperationException("names array has more than one element. can't handle this!");

    var val = rs[names[0]] as string;

    if (string.IsNullOrWhiteSpace(val) == false)
    {
      return KRD.Common.GenericXmlSerialization.Deserialize<T>(val);
    }

    return null;
  }

  public void NullSafeSet(IDbCommand cmd, object value, int index)
  {
    var parameter = (DbParameter)cmd.Parameters[index];
    T toSave = value as T;

    if (toSave != null)
    {
      parameter.Value = KRD.Common.GenericXmlSerialization.Serialize(toSave);
    }
    else
    {
      parameter.Value = DBNull.Value;
    }
  }

  public object DeepCopy(object value)
  {
    T toCopy = value as T;

    if (toCopy == null)
      return null;

    string serialized = KRD.Common.GenericXmlSerialization.Serialize(toCopy);

    return KRD.Common.GenericXmlSerialization.Deserialize<T>(serialized);
  }

  public object Replace(object original, object target, object owner)
  {
    throw new NotImplementedException();
  }

  public object Assemble(object cached, object owner)
  {
    var str = cached as string;
    if (string.IsNullOrWhiteSpace(str) == false)
    {
      return null;
    }

    return KRD.Common.GenericXmlSerialization.Deserialize<T>(str);
  }

  public object Disassemble(object value)
  {
    var toCache = value as T;

    if (toCache != null)
    {
      return KRD.Common.GenericXmlSerialization.Serialize(toCache);
    }

    return null;
  }

  public SqlType[] SqlTypes
  {
    get
    {
      return new SqlType[] { new SqlXmlType() };
    }
  }

  public Type ReturnedType
  {
    get { return typeof(XmlDocument); }
  }

  public bool IsMutable
  {
    get { return true; }
  }
}

public class SqlXmlType : SqlType
{
  public SqlXmlType()
    : base(DbType.Xml)
  {
  }
}

Использование с FluentNHibernate:

  public class MainObject
  {
    public int Id { get; set; }

    public ObjectAsXml Data { get; set; }
  }

  public class ObjectAsXml
  {
    public string Name { get; set; }

    public int Date { get; set; }

    public ObjectAsXml OtherObject { get; set; }
  }

  private class MainObjectMap : ClassMap<MainObject>
  {
    public MainObjectMap()
    {
      Id(id => id.Id);
      Map(m => m.Data).CustomType<XmlUserType<ObjectAsXml>>().Nullable();
    }
  }

Может быть, это кому-нибудь поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...