Fluent nhibernate 当属性和支持字段没有共同点时自动映射约定?

Fluent nhibernate 当属性和支持字段没有共同点时自动映射约定?,fluent-nhibernate,orm,Fluent Nhibernate,Orm,使用Fluent NHibernate,我似乎无法为以下(看似简单且常见)用例设计必要的自动映射约定: public class MyClass { private int _specialIdentityField private string _firstname; public Id { get { return _specialIdentityField; }; } public virtual string Firstname {

使用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>

基本上规则是:

  • 除标识外,所有内容都以下划线作为访问类型
  • 标识是每个类中的固定名称字段(名称=\u someSpecialIdentityField)
  • 身份访问始终仅限于字段,与围绕它的RO属性的名称无关
这一部分完全让我绊倒的是身份相关元素的约定映射(显然属性的约定映射是完全标准的)。我遇到的问题是如何告诉FNH约定我的标识字段是一个固定名称。我能找到的所有约定重写似乎都假定表示标识的属性与其基础支持字段的名称之间始终存在某种关系(例如,我可以为支持字段设置“自定义前缀”,但似乎看不出我如何只说“这始终是支持字段的名称”)

对于我来说,如何使用显式映射(对于这一点,使用XML映射文件)来实现这一点是显而易见的,但是对于我来说,如何在FNH中使用基于约定的(自动映射)映射来实现这一点却一点也不明显


这不可能是一个非典型的用例,所以我必须忽略一些非常明显的东西。感谢所有FNH大师的想法

编辑:查看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自动映射。为了使用id实现这个技巧,我在Proteus周围创建了一个包装器,它可以做两件事:

1) 映射ID

2) 隐藏id的Setter

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; }
    }
}
public抽象类EntityObject:IdentityPersistenceBase,entity
其中tenty:类,tenty
{
公共虚拟Guid Id
{
获取{return\u persistenceId;}
}
Guid IIIdentifiedIdentity.Id
{
获取{return\u persistenceId;}
设置{u persistenceId=value;}
}
公共虚拟整数版本
{
获取{return\u persistenceVersion;}
设置{u 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 );
    }
}
公共类实体变更:IAutomapping变更
{
public void Alter(AutoPersistenceModel模型)
{
model.OverrideAll(map=>
{
类型recordType=map.GetType().GetGenericArguments().Single();
if(recordType.BaseType.Name==“EntityObject`1”)
{
类型changeType=typeof(Change).MakeGenericType(recordType);
var change=(IChange)Activator.CreateInstance(changeType);
改变。去(地图);
}
} );
}
}
界面易变
{
void Go(对象映射对象);
}
类更改:IChange其中TRecord:EntityObject
{
void IChange.Go(对象映射对象)
{
变量映射=(自动映射)映射对象;
map.Id(x=>x.Id).GeneratedBy.Guid().Access.Property();
map.IgnoreProperty(x=>x.IsTransient);
}
}

PS:我真的很怀念你在网上活跃的时光。这是一个激动人心的夏天,两年前的作者……

编辑:看看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自动映射。为了使用id实现这个技巧,我在Proteus周围创建了一个包装器,它可以做两件事:

1) 映射ID

2) 隐藏id的Setter

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; }
    }
}
public抽象类EntityObject:IdentityPersistenceBase,entity
其中tenty:类,tenty
{
公共虚拟Guid Id
{
获取{return\u persistenceId;}
}
Guid IIIdentifiedIdentity.Id
{
获取{return\u persistenceId;}
设置{u persistenceId=value;}
}
公共虚拟整数版本
{
获取{return\u persistenceVersion;}
设置{u 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 );
    }
}
公共类实体变更:IAutomapping变更
{
public void Alter(AutoPersistenceModel模型)
{
model.OverrideAll(map=>
{
类型recordType=map.GetType().GetGenericArguments().Single();
if(recordType.BaseType.Name==“EntityObject`1”)
{
类型changeType=typeof(Change).MakeGenericType(recordType);
var change=(IChange)Activator.CreateInstance(changeType);
改变。去(地图);
}
} );
}
}
界面易变
{
void Go(对象映射对象);
}
类更改:IChange其中TRecord:EntityObject
{
void IChange.Go(对象映射对象)
{
变量映射=(自动映射)映射对象;
map.Id(x=>x.Id).GeneratedBy.Guid().Access.Property();
map.IgnoreProperty(x=>x.IsTransient);
}
}
PS:我真的很怀念你在网上活跃的时光。这是一个激动人心的夏天,2年前的作者……

wow——完美,如果不是有点过于复杂的话!关于我离开onli的事