Использование ICompositeUserType для разных таблиц с разными именами столбцов - PullRequest
3 голосов
/ 02 марта 2010

Я пытался заставить работать сопоставление NHibernate ICompositeUserType. Но я застрял, пытаясь сделать реализацию достаточно универсальной для использования в разных таблицах.

Наша унаследованная база данных имеет много таблиц с широтами и долготами, и я хочу отобразить их в свои доменные объекты как класс Position. Проблема в том, что каждая таблица имеет разные имена для столбцов широты и долготы.

Я создал реализацию ICompositeUserType, но мне кажется, что в PropertyNames нужно задать имена столбцов в таблице, что означает, что я не могу использовать CustomType в разных таблицах (с разными именами столбцов).

Я подумал, что должен установить для PropertyNames имена свойств в моем классе Position и сопоставить их со столбцами таблицы в моем ClassMap, но, похоже, возникает исключение NHibernate:

NHibernate.MappingException: property mapping has wrong number of columns

Такое ощущение, что я делаю что-то не так в своем отображении, но я не могу понять это.

Вот фрагмент кода из моего ICompositeUserType:

public class PositionUserType : ICompositeUserType
{
  private readonly IType[] _propertyTypes = 
     new [] { NHibernateUtil.Double , NHibernateUtil.Double };

  private readonly string[] _propertyNames = 
     new[] { "Latitude", "Longitude"  };

  public string[] PropertyNames { get { return _propertyNames; } }

  public IType[] PropertyTypes { get { return _propertyTypes; } }

  // Other methods omitted
}

и моя карта классов:

public class LastPositionMap : ClassMap<LastPosition>
{
    public LastPositionMap()
    {
        Map(p => p.Position)
            .Columns.Add("LPLongitude", "LPLongitude")
            .CustomType(typeof(PositionUserType));

        // Other mapping omitted
    }
}

и Позиция класса

public class Position
{
  public double Latitude { get; private set; }
  public double Longitude { get; private set; }

  public Position(double latitude, double longitude)
  {
    Latitude = latitude;
    Longitude = longitude;
  }
}

В настоящее время у меня есть работа, где я могу использовать беглую карту Компонентов, но это означает, что мой класс Position должен быть изменяемым, и я бы предпочел, чтобы это было не так.

Может кто-нибудь помочь? Я хорошо посмотрел несколько статей и книг, но до сих пор не могу заставить его работать.

Спасибо

Адам

Ответы [ 2 ]

4 голосов
/ 11 мая 2010

Вам необходимо очистить коллекцию Column перед добавлением переопределений имен столбцов в вашем отображении:

public class LastPositionMap : ClassMap<LastPosition>
{
    public LastPositionMap()
    {
        Map(p => p.Position)

            // Clear the columns to get rid of Fluent NH's default column names
            .Columns.Clear()

            .ColumnsAdd("LPLongitude", "LPLongitude")
            .CustomType(typeof(PositionUserType));

        // Other mapping omitted
    }
}

Если вы не очищаете коллекцию столбцов перед добавлением пользовательских имен, Fluent NH просто добавляет новые имена столбцов в коллекцию столбцов для сопоставления пользовательских типов, что приводит к тому, что вы получаете слишком много столбцов для данного пользовательского типа. .

Если вы сгенерируете фактические XML-отображения из ваших беглых отображений (используя Mappings.ExportTo () в вашей беглой конфигурации), вы, вероятно, увидите что-то вроде этого:

<property <!-- details here -->
  <column name="Latitude" /> 
  <column name="Longitude" /> 
  <column name="LPLongitude" /> 
  <column name="LPLatitude" /> 
</property>

когда это должно быть на самом деле:

<property <!-- details here -->
  <column name="LPLatitude" /> 
  <column name="LPLongitude" /> 
</property>
2 голосов
/ 19 мая 2011

Это не должно быть изменяемым, вы можете использовать приватное поле поддержки

Component(x => x.Position, c =>
    {
        c.Map(p => p.Longitude, "LPLongitude").Access.BackingField();
        c.Map(p => p.Latitude, "LPLatitude").Access.BackingField();
    })

единственное, что нужно - это конструктор без параметров для класса, который пользовательский код не видит

protected Position() { } // to make NHibernate default implementation happy

другая возможность - использовать хук экземпляра и создать экземпляр класса Position с помощью default(double) в конструкторе

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