FluentNHibernate base ClassMap и избегает использования typeof (T) для определения типа идентификатора объекта для определения генератора NHibernate

#c# #fluent-nhibernate

#c# #fluent-nhibernate

Вопрос:

Чтобы централизовать часть моей логики для каждого сопоставления классов FluentNHibernate (в частности, для сопоставления свойств аудита и фактического основного идентификатора), у меня есть базовая карта классов под названием AuditedEntityClassMap, которая выглядит примерно следующим образом:

 public class AuditedEntityClassMap<TEntity, T> : ClassMap<TEntity> where TEntity : AuditedPersistentObject<T>
{
    public AuditedEntityClassMap()
    {
        Cache.ReadWrite();
        DynamicUpdate();
        ApplyId();
        this.ChangeAuditInfo();
    }

    protected virtual void ApplyId()
    {
            if (typeof(T) == typeof(int))
                map.Id(x => x.Id).GeneratedBy.HiLo(HiLoConstants.NHibernateHiLoTable, HiLoConstants.NHibernateHiLoColumn, HiLoConstants.NHibernateHiLoMaxLo);
            else if (typeof(T) == typeof(Guid))
                map.Id(x => x.Id).GeneratedBy.GuidComb();
            else
                throw new InvalidIdTypeInClassMappingException("Invalid type set in class mapping: "   typeof(T));
    }
}
  

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

  1. Универсальный тип для идентификаторов объектов моего домена используется повсеместно и отлично работает везде (и он широко используется).
  2. Я бы предпочел не определять отображение идентификаторов в ClassMap каждого объекта, если я могу этого избежать. Если это единственный способ сделать это, я смирюсь с этим.

Мысли и предложения?

Ответ №1:

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

Не будет ли T классом данных вместо идентификатора.

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

Вы могли бы получить свойства T с помощью отражения и выполнить поиск свойства с именем Id или id-код. А затем получает тип этого свойства. Но я не знаю, как бы вы назвали Map в этом контексте.

 var pp = typeof(T).GetProperties().Where(p => p.Name == "Id").FirstOrDefault();
if (pp != null)
{
  if (pp.PropertyType.Name == "Int64" || pp.PropertyType.Name == "Int32")
  {
    Map();
  }
}
  

Комментарии:

1. Спасибо за очень быстрый ответ. Я удалил это вскоре после публикации, но, думаю, после того, как вы увидели это и начали отвечать. Да, синтаксис был неправильным и с тех пор был обновлен.

2. Добавление отражения туда было бы еще более неприятным на мой взгляд. Запах, на мой взгляд, связан с тем, что дженерик уже давно не является универсальным в цепочке, что сводит на нет смысл того, чтобы он был универсальным в первую очередь (помимо того факта, что он бесценен везде в этой цепочке).

3. На предыдущих итерациях я просто выполнял AuditedEntityClassMapOfGuid, AuditedEntityClassMapOfInt и т.д. И просто устанавливал класс-наследник как применимый. Но это мне понравилось еще меньше.

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

5. Спасибо yavosh. Если другого способа нет, то я думаю, что оставлю все как есть. Если бы это имело дело с бесконечным числом типов, у меня была бы проблема. Но как бы то ни было, два типа, возможно, три, все это хорошо.

Ответ №2:

Похоже, нет ничего лучше того, что у меня есть сейчас.