fluent-nhibernate - 为 fluentnhibernate automapper 中的接口(interface)提供 AutoMappingOverride 的最佳方法是什么

标签 fluent-nhibernate interface automapping

在为应用程序寻找版本范围的数据库过滤器时,我编写了以下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
using FluentNHibernate.Mapping;
using MvcExtensions.Model;
using NHibernate;

namespace MvcExtensions.Services.Impl.FluentNHibernate
{
    public interface IVersionAware
    {
        string Version { get; set; }
    }

    public class VersionFilter : FilterDefinition
    {
        const string FILTERNAME = "MyVersionFilter";
        const string COLUMNNAME = "Version";

        public VersionFilter()
        {
            this.WithName(FILTERNAME)
                .WithCondition("Version = :"+COLUMNNAME)
                .AddParameter(COLUMNNAME, NHibernateUtil.String );
        }

        public static void EnableVersionFilter(ISession session,string version)
        {
            session.EnableFilter(FILTERNAME).SetParameter(COLUMNNAME, version);
        }

        public static void DisableVersionFilter(ISession session)
        {
            session.DisableFilter(FILTERNAME);
        }
    }

    public class VersionAwareOverride : IAutoMappingOverride<IVersionAware>
    {
        #region IAutoMappingOverride<IVersionAware> Members

        public void Override(AutoMapping<IVersionAware> mapping)
        {
            mapping.ApplyFilter<VersionFilter>();
        }
        #endregion
    }

}

但是,由于覆盖不适用于接口(interface),我正在寻找一种方法来实现它。
目前,我对每个实现接口(interface)的类都使用这种(相当麻烦的)方式:
public class SomeVersionedEntity : IModelId, IVersionAware
{
    public virtual int Id { get; set; }
    public virtual string Version { get; set; }
}

public class SomeVersionedEntityOverride : IAutoMappingOverride<SomeVersionedEntity>
{
    #region IAutoMappingOverride<SomeVersionedEntity> Members

    public void Override(AutoMapping<SomeVersionedEntity> mapping)
    {
        mapping.ApplyFilter<VersionFilter>();
    }

    #endregion
}

我一直在查看 IClassmap 接口(interface)等,但它们似乎没有提供访问 ApplyFilter 方法的方法,所以我在这里没有任何线索......

由于我可能不是第一个遇到这个问题的人,我很确定它应该是可能的;我只是不太确定这是如何工作的..

编辑 :
我已经更接近通用解决方案了:


这是我试图解决它的方式:

使用泛型类来实现对实现接口(interface)的类的更改:
public abstract class AutomappingInterfaceAlteration<I> : IAutoMappingAlteration
{
    public void Alter(AutoPersistenceModel model)
    {
        model.OverrideAll(map =>
        {
            var recordType = map.GetType().GetGenericArguments().Single();
            if (typeof(I).IsAssignableFrom(recordType))
            {
                this.GetType().GetMethod("overrideStuff").MakeGenericMethod(recordType).Invoke(this, new object[] { model });
            }
        });
    }

    public void overrideStuff<T>(AutoPersistenceModel pm) where T : I
    {
        pm.Override<T>( a => Override(a));
    }

    public abstract void Override<T>(AutoMapping<T> am) where T:I;
}

和一个具体的实现:
public class VersionAwareAlteration : AutomappingInterfaceAlteration<IVersionAware>
{
    public override void Override<T>(AutoMapping<T> am)
    {
        am.Map(x => x.Version).Column("VersionTest");
        am.ApplyFilter<VersionFilter>();
    }
}

不幸的是,我现在收到以下错误:
[InvalidOperationException: Collection was modified; enumeration operation may not execute.]
   System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource) +51
   System.Collections.Generic.Enumerator.MoveNextRare() +7661017
   System.Collections.Generic.Enumerator.MoveNext() +61
   System.Linq.WhereListIterator`1.MoveNext() +156
   FluentNHibernate.Utils.CollectionExtensions.Each(IEnumerable`1 enumerable, Action`1 each) +239
   FluentNHibernate.Automapping.AutoMapper.ApplyOverrides(Type classType, IList`1 mappedProperties, ClassMappingBase mapping) +345
   FluentNHibernate.Automapping.AutoMapper.MergeMap(Type classType, ClassMappingBase mapping, IList`1 mappedProperties) +43
   FluentNHibernate.Automapping.AutoMapper.Map(Type classType, List`1 types) +566
   FluentNHibernate.Automapping.AutoPersistenceModel.AddMapping(Type type) +85
   FluentNHibernate.Automapping.AutoPersistenceModel.CompileMappings() +746

编辑2:我设法更进一步; 我现在使用反射为每个实现接口(interface)的类调用“覆盖”:
public abstract class PersistenceOverride<I> 
{

    public void DoOverrides(AutoPersistenceModel model,IEnumerable<Type> Mytypes)
    {
        foreach(var t in Mytypes.Where(x=>typeof(I).IsAssignableFrom(x)))
            ManualOverride(t,model);
    }

    private void ManualOverride(Type recordType,AutoPersistenceModel model)
    {
        var t_amt = typeof(AutoMapping<>).MakeGenericType(recordType);
        var t_act = typeof(Action<>).MakeGenericType(t_amt);
        var m = typeof(PersistenceOverride<I>)
                .GetMethod("MyOverride")
                .MakeGenericMethod(recordType)
                .Invoke(this, null);
        model.GetType().GetMethod("Override").MakeGenericMethod(recordType).Invoke(model, new object[] { m });
    }

    public abstract Action<AutoMapping<T>> MyOverride<T>() where T:I;
}

public class VersionAwareOverride : PersistenceOverride<IVersionAware>
{
    public override Action<AutoMapping<T>> MyOverride<T>()
    {
        return am =>
        {
            am.Map(x => x.Version).Column(VersionFilter.COLUMNNAME);
            am.ApplyFilter<VersionFilter>();
        };
    }
}

但是,出于某种原因,我生成的 hbm 文件不包含任何“过滤器”字段....
也许有人现在可以帮助我更进一步?

最佳答案

显然,当前版本的 fluent-nhibernate 中有一个错误。当您使用 Automapper.Override 时,过滤器没有被复制。

我 fork 了源代码,修复了错误,进行了测试,现在我已经向 github 上的 fluentnhib 人员发送了一个拉取请求。

目前,您可以在 http://github.com/ToJans/fluent-nhibernate/commit/29058de9b2bc3af85bc433aa6f71549f7b5d8e04 下载固定源代码。

现在还有一篇关于如何做到这一点的完整博客文章:
http://www.corebvba.be/blog/post/How-to-override-interface-mappings-and-creata-a-generic-entity-version-filter-in-fluent-nhibernate.aspx

关于fluent-nhibernate - 为 fluentnhibernate automapper 中的接口(interface)提供 AutoMappingOverride 的最佳方法是什么,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2630249/

相关文章:

fluent-nhibernate - BuildSessionFactory 行中的 Automapping 和 FNH 异常

c# - Fluent NHibernate 在外键引用上强制执行不可为空

c# - Fluent NHibernate 自动映射私有(private)/ protected 属性作为 Id

c# - 不可空类型的通用约束

c# - ASP.Net MVC & NHibernate Burrow & Fluent NHibernate

c# - 是否可以使用 FluentNHibernate 将具有空格的 varchar 映射到枚举

c# - 带有外键的 Fluent NHibernate 子类映射

java - 谁在 Java 中实现操作系统接口(interface)?

java - 接口(interface)指定方法

c# - NHibernate 配置 "current_session_context_class"可能的值和描述