有没有办法在NHibernate中通过代码组合XML文件和映射

时间:2012-09-14 09:02:20

标签: nhibernate-mapping fluent-nhibernate-mapping

我一直在使用NHibernate> = 3.2中的代码功能进行NHibernate映射,非常喜欢它。现在我想在现有项目中开始使用它,我们有大约80个*.hbm.xml个文件。一次性更改所有*.hbm.xml文件是不可行的,因此我希望使用代码映射新映射,并逐步转换现有XML文件。

我尝试将一个XML文件转换为按代码映射,并修改了我的配置构建代码以引入代码映射。以下是代码的摘录:

private void AddMappings(Configuration configuration, Assembly assembly)
{
    // add mappings from embedded *.hbm.xml files
    configuration.AddAssembly(assembly);

    // add mappings from map by code
    var modelMapper = new ModelMapper();
    modelMapper.AddMappings(assembly.GetExportedTypes());
    var mapping = modelMapper.CompileMappingForAllExplicitlyAddedEntities();
    configuration.AddMapping(mapping);
}

我发现XML文件中的实体已添加到配置中,但我的代码类映射未添加。

有关我做错的任何建议吗?

1 个答案:

答案 0 :(得分:0)

这是我用来做你想做的代码:

    private IHibernateConfigurationExtension m_ExtensionConfig;
    private Configuration m_Configuration;
    public Configuration Configuration
    {
        get
        {
            if (m_Configuration == null)
            {
                m_ExtensionConfig = FetchExtensionConfig();
                m_Configuration = new Configuration();
                string assemblyDirectory = Path.GetDirectoryName(m_ExtensionConfig.Assembly.Location);
                m_Configuration.Configure(Path.Combine(assemblyDirectory, "hibernate.cfg.xml"));
                m_Configuration = LoadHBMXML(m_Configuration);
                m_Configuration = LoadMappings(m_Configuration);
            }
            return m_Configuration;
        }
    }


    #region NHibernate Configuration
    /// <summary>
    /// Load the assemblies that are configured with the *.hbm.xml configuration
    /// </summary>
    /// <param name="configuration"></param>
    /// <returns></returns>
    private Configuration LoadHBMXML(Configuration configuration)
    {
        configuration.AddAssembly(m_ExtensionConfig.Assembly);
        return configuration;
    }

    /// <summary>
    /// Load the configurations that are configured with the ClassMap convention (NHibernate 3.2+)
    /// </summary>
    /// <param name="configuration"></param>
    /// <returns></returns>
    private Configuration LoadMappings(Configuration configuration)
    {
        // This configuration for mapper files
        ModelMapper mapper = new ModelMapper();
        mapper.BeforeMapProperty += new PropertyMappingHandler(mapper_BeforeMapProperty);
        List<Type> typeList = m_ExtensionConfig.Assembly.GetMatchingTypesInAssembly(item => m_ExtensionConfig.MappingsNamespace.Equals(item.Namespace)).ToList();
        mapper.AddMappings(typeList);
        IEnumerable<HbmMapping> mappings = mapper.CompileMappingForEachExplicitlyAddedEntity();
        mappings.ForEach(m => configuration.AddMapping(m));
        if (DumpToXML)
            mappings.WriteAllXmlMapping();
        return configuration;
    }

我使用的界面

/// <summary>
/// An interface to be implemented within the assembly using the 
/// HibernateDAO class.  This determines what gets configured
/// for hibernate automatically.
/// <para>NOTE: Currently only supports a single implementation
/// within all loaded assemblies</para>
/// </summary>
public interface IHibernateConfigurationExtension
{
    /// <summary>
    /// The namespace containing the mapping files.
    /// <para>Only a single namespace is currently supported</para>
    /// </summary>
    string MappingsNamespace { get; }

    /// <summary>
    /// The assembly to search for .hbm.xml hibernate configuration files
    /// </summary>
    Assembly Assembly { get; }

    /// <summary>
    /// Dictionary of conversion mappings
    /// <para>Type is the object type, the type used in object definitions</para>
    /// <para>Type of IUserType is the NHIbernate IUserType implementation to convert 
    /// between the Type and the persisted representation</para>
    /// </summary>
    IDictionary<Type, Type> UserConversionMappings { get; }
}

获取扩展配置的方法

    /// <summary>
    /// Fetch the class that implements the IHibernateConfigurationExtension interface
    /// <para>Support is only provided for a single implementation of this class
    /// through all loaded assemblies</para>
    /// </summary>
    /// <returns>The class that implements the extension</returns>
    private IHibernateConfigurationExtension FetchExtensionConfig()
    {
        ICollection<Type> interfaces = AssemblyUtils.GetMatchingTypes(item => item.GetInterfaces().Contains(typeof(IHibernateConfigurationExtension)));
        if (interfaces.Count == 0)
            throw new ArgumentException("No implementation of IHibernateConfigurationExtension found");
        if (interfaces.Count > 1)
            throw new ArgumentException("Only support for a single implementation if IHibernateConfigurationExtension available.  Please raise support request");
        return Activator.CreateInstance(interfaces.First()) as IHibernateConfigurationExtension;
    }

需要的AssemblyUtils中的部分

    /// <summary>
    /// Get all matching types in all assemblies that match the predicate
    /// </summary>
    /// <param name="predicate">The predicate function to match the types against</param>
    /// <returns>The list of all types that match the predicate</returns>
    public static ICollection<Type> GetMatchingTypes(Predicate<Type> predicate)
    {
        ICollection<Type> types = new List<Type>();
        foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            try
            {
                types.AddRange(assembly.GetTypes().Where(i => i != null && predicate(i)).ToList());
            }
            catch (ReflectionTypeLoadException ex)
            {
                types.AddRange(ProcessExceptionTypes(ex.Types, i => i != null && predicate(i)));
            }
        }
        return types;
    }


    /// <summary>
    /// Process each of the types in the list (usually called from within a ReflectionTypeLoadException
    /// to load the types that match the predicate.
    /// </summary>
    /// <param name="theTypes">The list of types to process (taken from ReflectionTypeLoadException.Types</param>
    /// <param name="predicate">The boolean predicate to compare the type against</param>
    /// <returns>The collection of types (that can be loaded) matching the predicate</returns>
    private static ICollection<Type> ProcessExceptionTypes(Type[] theTypes, Predicate<Type> predicate)
    {
        ICollection<Type> types = new List<Type>();
        foreach (Type theType in theTypes)
        {
            try
            {
                if (predicate(theType))
                    types.Add(theType);
            }
            // This exception list is not exhaustive, modify to suit any reasons
            // you find for failure to parse a single assembly
            catch (BadImageFormatException)
            {
                // Type not in this assembly - reference to elsewhere ignored
            }
            catch (FileNotFoundException)
            {
                // Type not in this assembly - reference to elsewhere ignored
            }
        }
        return types;
    }