【问题标题】:NHibernate mapping-by-code in .NET 4.6 throws "Cannot extend unmapped class".NET 4.6 中的 NHibernate 代码映射引发“无法扩展未映射的类”
【发布时间】:2015-08-17 17:26:00
【问题描述】:

我有一个项目在我今天在全新安装的 Windows 上打开的相同 NH 配置中运行了几个月(安装了 VS 2015 RC,还安装了 .NET 4.6 RC,但项目的目标是 .NET 4.5)

在构建 NH 会话工厂时调用这些行:

var mapper = new AutoMapper();
var mapping = mapper.CompileMappingFor(typeof(Entity).Assembly.GetTypes());
conf.AddMapping(mapping);

最后一行抛出异常:Could not compile the mapping document: mapping_by_code with InnerException Cannot extend unmapped class: [my_namespace].[my_entity_name]。当我遍历mapping 时,我可以看到名称为[my_entity_name] 的对象,一切似乎都正常。只是这个对象在扩展这个对象的对象之后的集合中(我不确定这是否可能是一个问题或顺序无关紧要)。

在任何其他计算机(其他工作站、CI 服务器、生产和开发环境)上,我们都没有注意到这个错误,我想这可能是由于安装了 .NET 4.6 引起的,这是唯一安装 .NET 4.6 的机器。如果我在安装 .NET 4.6 时理解正确,则所有面向 .NET 4.5 的项目都在 .NET 4.6 运行时中运行。我也尝试在 VS 2013 中运行它,但没有任何变化……我也在检查 .NET 4.6RC 更改日志,但没有发现任何可能导致此错误的内容。有什么建议吗?


更新:我在 .NET 4.5 机器上检查了 mapping 集合中项目的顺序,它的顺序正确(依赖子类在父子类之后),所以看起来顺序GetTypes() 返回的类型(不保证排序)巧合地在 .NET 4.5 中工作,但在 .NET 4.6 中不工作,因为 CompileMappingFor 不会重新排序相同类型的映射(这里我有依赖子类 -> 子类)。

【问题讨论】:

  • 我在 Windows 10 (RTM) 上遇到了与 VS2015 (RTM) 相同的问题。该应用程序仍以 .NET Framework 4.5.2 为目标,但正如您所写,“安装 .NET 4.6 后,所有针对 .NET 4.5 的项目都在 .NET 4.6 运行时中运行”我收到的确切错误是 NHibernate.MappingException: Could not compile the mapping document: mapping_by_code ---> NHibernate.MappingException: Cannot extend unmapped class NHibernate 版本: 4.0.3.4000

标签: c# nhibernate nhibernate-mapping-by-code .net-4.6


【解决方案1】:

是的,原因是Assembly.GetTypes() 的顺序在.NET 4.5 和.NET 4.6 中完全不同。巧合的是 .NET 4.5 生成的命令可以正常工作...我将其修改为以下代码,并且可以正常工作。

var types = typeof (Entity).Assembly.GetTypes().Where(t => !t.IsInterface).PartialOrderBy(x => x, new EntityTypeComparer());
var mapping = mapper.CompileMappingFor(types);    

public class EntityTypeComparer : IComparer<Type>
{
    public int Compare(Type x, Type y)
    {           
        if (x == y)
            return 0;
        if (x.IsAssignableFrom(y) || (!x.IsAssignableTo<Entity>() && y.IsAssignableTo<Entity>()))
            return -1;
        if (y.IsAssignableFrom(x) || (!y.IsAssignableTo<Entity>() && x.IsAssignableTo<Entity>()))
            return 1;
        return 0;
    }
}      

编辑: OrderBy 替换为 PartialOrderBy,您可以在此处找到实现 - Topological Sorting using LINQ。这使得拓扑排序而不是常规排序 - 我们有一些不可比较的对象(最后在比较器中返回 0)并且一般 OrderBy 会产生错误的结果。

【讨论】:

  • 对最后一个return 0要非常小心...比较算法并不总是比较您直接认为的类型,而是可以通过第三种类型进行比较。假设您有从 B 继承的 A、B、C 和 C 类型,在这种情况下,比较器将执行:A==B ... A==C ... 然后它假定 B==C 并且您最终顺序错误 - 永远不会为 B 和 C 类型调用 Compare 方法!
  • 是的,你是对的,这个比较器是错误的。实际上不可能使用OrderByIComparer,因为继承关系只是偏序关系而不是线性序关系。正确的解决方案是使用拓扑排序。我会重写它并更新这个问题......
  • 我更新了原代码,只是把OrderBy换成了PartialOrderBy,比较器没有修改。感谢@gschuager 的通知。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-17
  • 2012-04-09
  • 1970-01-01
  • 1970-01-01
  • 2014-04-02
相关资源
最近更新 更多