Соглашения об автоматическом отображении, когда свойство и резервное поле не имеют НИЧЕГО общего?

Используя Fluent NHibernate, я не могу разработать необходимые соглашения об автоматическом сопоставлении для следующего (на первый взгляд простого и распространенного) варианта использования:

public class MyClass
{
    private int _specialIdentityField
    private string _firstname;
    public Id { get { return _specialIdentityField; }; }
    public virtual string Firstname
    {
        get
        {
            return _firstname;
        }
        set
        {
            _firstname = value;
        }
    }
}

public class OtherClass
{
    private int _specialIdentityField
    private string _lastname;
    public Id { get { return _specialIdentityField; }; }
    public virtual string Lastname
    {
        get
        {
            return _lastname;
        }
        set
        {
            _lastname = value;
        }
    }
}

Желаемые сопоставления выглядят так:

<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" default-access="field.camelcase-underscore" auto-import="true" default-cascade="none" default-lazy="true">
    <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="MyClass" table="`MyClass`">
        <id name="_specialIdentityField" type="System.Int32" access=field>
          <column name="Id" />
          <generator class="identity" />
        </id>
        <property name="Firstname" type="System.String">
          <column name="Firstname" />
        </property>
    </class>
    <class xmlns="urn:nhibernate-mapping-2.2" mutable="true" name="OtherClass" table="`OtherClass`">
        <id name="_specialIdentityField" type="System.Int32" access=field>
          <column name="Id" />
          <generator class="identity" />
        </id>
        <property name="Lastname" type="System.String">
          <column name="Lastname" />
        </property>
    </class>
</hibernate-mapping>

В основном правила таковы:

  • все является field-camelcase-underscore как тип доступа, ЗА ИСКЛЮЧЕНИЕМ идентификатора
  • identity - это поле с фиксированным именем в каждом классе (name = _someSpecialIdentityField)
  • идентификационный доступ всегда только для поля и не имеет никакого отношения к имени окружающего его свойства RO

Часть этого, которая меня полностью сбивает с толку, - это сопоставление по соглашению элементов, связанных с идентичностью (очевидно, что сопоставление свойств по соглашению является полностью стандартной платой за проезд). Проблема, с которой я столкнулся, заключается в том, как сообщить соглашениям FNH, что мое поле идентификации является фиксированным именем. Все переопределения соглашений, которые я могу найти, похоже, предполагают, что всегда будет некоторая связь между свойством, представляющим личность, и именем его базового поля поддержки (например, я могу установить «настраиваемый префикс» для поле поддержки, но я не понимаю, как я могу просто сказать: «это всегда имя поля поддержки»).

Для меня очевидно, как добиться этого с помощью явного сопоставления (и, если на то пошло, с помощью файлов сопоставления XML), но для меня совсем не очевидно, как это сделать с сопоставлением на основе соглашений (автоматическое сопоставление) в FNH.

Это не может быть нетипичным вариантом использования, поэтому я должен просто упустить из виду что-то ужасно очевидное. Мысли любых гуру FNH приветствуются!


person sbohlen    schedule 06.02.2010    source источник


Ответы (1)


РЕДАКТИРОВАТЬ: взгляните на интерфейс IAutomappingConfiguration. Создайте собственную реализацию или переопределите класс DefaultAutomappingConfiguration.

public virtual bool IsId(Member member)
    {
        return member.Name.Equals("id", StringComparison.InvariantCultureIgnoreCase);
    }

затем вы добавляете его в инициализацию:

Fluently.Configure( Configuration )
                .Mappings( cfg =>
                { cfg.AutoMappings.Add( IAutomappingConfigurationInstance )}

===============================================

Привет, Стив, думаю, я знаю, что ты пытаешься сделать. Я использую Proteus и FNH automapping. Чтобы проделать трюк с идентификатором, я создал оболочку вокруг Proteus, которая выполняет две функции:

1) Сопоставляет ID

2) Скрывает сеттер для идентификатора

public abstract class EntityObject<TEntity> : IdentityPersistenceBase<TEntity, Guid>, IEntity
    where TEntity : class, IEntity
{
    public virtual Guid Id
    {
        get { return _persistenceId; }
    }

    Guid IIdentifiedEntity<Guid>.Id
    {
        get { return _persistenceId; }
        set { _persistenceId = value; }
    }

    public virtual int Version
    {
        get { return _persistenceVersion; }
        set { _persistenceVersion = value; }
    }
}

И чтобы избежать сохранения свойства IsTransient + других вещей, вы можете создать MappingAlternation:

public class EntityAlteration : IAutoMappingAlteration
{

    public void Alter( AutoPersistenceModel model )
    {
        model.OverrideAll( map =>
        {

            Type recordType = map.GetType().GetGenericArguments().Single();
            if( recordType.BaseType.Name == "EntityObject`1" )
            {
                Type changeType = typeof( Change<> ).MakeGenericType( recordType );
                var change = ( IChange )Activator.CreateInstance( changeType );
                change.Go( map );
            }
        } );
    }

}

interface IChange
{
    void Go( object mapObject );
}

class Change<TRecord> : IChange where TRecord : EntityObject<TRecord>
{
    void IChange.Go( object mapObject )
    {
        var map = ( AutoMapping<TRecord> )mapObject;
        map.Id( x => x.Id ).GeneratedBy.Guid().Access.Property();
        map.IgnoreProperty( x => x.IsTransient );
    }
}

PS: Мне очень не хватает тех времен, когда вы были активны в онлайн-пространстве. Два года назад это было захватывающим летом и осенью ...

person mynkow    schedule 13.07.2010
comment
вау - отлично, если не сказать чересчур сложно! Что касается моего ухода из онлайн-пространства, к сожалению, местное сообщество взяло на себя большую часть моего внимания, но вы скоро увидите мое возвращение к активной онлайн-жизни; быть в курсе! - person sbohlen; 14.07.2010