Составное объявление первичного ключа через конвенцию для fluent-nHibernate - PullRequest
0 голосов
/ 05 августа 2011

Мне нужно использовать Fluent-nHibernate для таблицы с составным первичным ключом (таблица Azure, первичными ключами (PartitionKey, RowKey)), и я хотел бы сопоставить их с соответствующими свойствами объекта (или со свойством компонента,если проще)

моя таблица будет выглядеть так:

{
  PartitionKey PK,
  RowKey PK,
  [..]
}

и сущность

public class MyRecord
{
  public virtual string PartitionKey{get;set;}
  public virtual string RowKey{get;set;}

  [...]
}

Мой текущий проект использует пользовательский драйвер nHibernate, ориентированный на AzureTable.

Мне удалось заставить его работать с сопоставлениями ClassMap или XML. Поэтому я уверен, что драйвер работает. Кроме того, HTTP-запросы таблицы Azure корректны с использованием карт классов или объявлений XML.

Однако мне действительно нужносоглашения, так что это не приемлемое решение.

Наконец, всегда есть возможность отобразить только RowKey в качестве PK, даже если Datastore использует (PartitionKey, RowKey). Это тоже работает, но это не такдействительно удовлетворяет, поскольку вводит несоответствие обработки уникальности между nHibernate и базовым хранилищем данных.

UPDATE:

Я пытался создать собственную IIdentityConvention.Метод IIdentityInstance.Column () учитывает только первый вызов.Однако если я использую отражение, чтобы добавить оба столбца в основное поле сопоставления, сборка конфигурации завершится неудачно с исключением XML-проверки (требуется атрибут «класс»)

1 Ответ

1 голос
/ 21 января 2012

У меня сегодня работает, но не красиво.Это также не использует соглашение.Как я понимаю соглашения, они действительно предназначены для настройки вещей после того, как произошло основное сопоставление.Я полагаю, что добавление отображений не входит в сферу действия соглашений.

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

Способ, которым я заставил это работать через отражение, заключался в том, чтобы заполучить соответствующий объект AutoPersistenceModel.Если у вас есть код, похожий на этот:

Fluently.Configure().Mappings(m => ...

Объектом AutoPersistenceModel будет m.AutoMappings.First ()

Отсюда это довольно серьезная работа по отражению, завершающаяся вызовомзащищенный метод внутри FluentNHibernate.Вот код, который я использую:

    private void Override(AutoPersistenceModel container, 
                          Type type, 
                          IEnumerable<KeyValuePair<string,string>> compositeKeys)
    {
        // We need to call container.Override<T>(Action<Automapping<T>> populateMap)
        // Through reflection...yikes
        var overrideMethod = typeof(AutoPersistenceModel)
                               .GetMethod("Override")
                               .MakeGenericMethod(type);
        var actionFactoryMethod = typeof(FluentNHibernateInitializer)
                                    .GetMethod("CompositeMapperFactory",
                                       BindingFlags.Instance | BindingFlags.NonPublic)
                                    .MakeGenericMethod(type);
        var actionMethod = actionFactoryMethod
                             .Invoke(this, new object[] { compositeKeys });
        overrideMethod.Invoke(container, new object[] {actionMethod});
    }

    private Action<AutoMapping<T>> CompositeMapperFactory<T>
           (IEnumerable<KeyValuePair<string, string>> compositeKeys)
    {
        return new Action<AutoMapping<T>>(m =>
            {
                var compositeId = m.CompositeId();
                foreach (var kvp in compositeKeys) 
                    compositeId = 
                      AddKeyProperty(
                        compositeId, 
                        typeof(T).GetProperty(kvp.Key), 
                        kvp.Value);
            }
        );
    }

    /// <summary>
    /// Uses reflection to invoke private and protected members!
    /// </summary>
    /// <param name="compositeId"></param>
    /// <param name="propertyInfo"></param>
    /// <returns></returns>
    private CompositeIdentityPart<T> AddKeyProperty<T>
      (CompositeIdentityPart<T> compositeId, 
       PropertyInfo propertyInfo, 
       string column)
    {
        var member = FluentNHibernate.MemberExtensions.ToMember(propertyInfo);
        var keyPropertyMethod = typeof(CompositeIdentityPart<T>)
                                  .GetMethod("KeyProperty", 
                                     BindingFlags.Instance | BindingFlags.NonPublic);
        return (CompositeIdentityPart<T>)
                 keyPropertyMethod
                   .Invoke(compositeId, new object[] { member, column, null });
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...