我创建了一个项目来测试 NHibernate 3+ 与 Entity Framework 4.1,将其包装在存储库中,使其非常易于使用接口等进行测试。
我不想在存储库之外公开任何 ORM(我什至不公开 IQueryables)。一切都应该在该层中处理,直到我尝试以抽象方式处理获取,一切都很好。
Microsoft 添加预加载的实现在 Include 函数中使用魔术字符串 (yuck) 或 Linq 表达式 (yay)。它们的语法如下:
IQueryableThing.Include(o => o.Person);
IQueryableThing.Include(o => o.Company.Contact);
IQueryableThing.Include(o => o.Orders.Select(p => p.LineItem.Cost);
第一个只会加载关联的人。(parent) 第二个会加载关联公司和各个公司的联系方式。(父母和祖父母)。第三个将加载每个订单的所有关联订单、订单项和成本。
这是一个非常巧妙的实现。
NHibernate 使用稍微不同的方法。他们仍然使用 Linq 表达式,但是他们更多地使用了扩展方法(流利的方法)。
IQueryableThing.Fetch(o => o.Person);
IQueryableThing.Fetch(o => o.Company).ThenFetch(o => o.Contact);
IQueryableThing.FetchMany(o => o.Orders).ThenFetch(p => p.LineItem).ThenFetch(q => q.Cost);
(我不确定第三行是否是正确的语法)
我可以将表达式列表封装在一个单独的类中,然后将这些表达式应用于该类中的 IQueryable。所以我需要做的是标准化 Microsoft 表达式语法,然后通过遍历表达式树并重建每个表达式将其转换为 NHibernate 的语法。
这是真正棘手的部分。我必须保持特定的操作顺序才能为 IQueryable 调用正确的函数(必须以 Fetch 或 FetchMany 开头,每个后续都是“ThenFetch”或“ThenFetchMany”),这使我无法使用内置的-在 ExpressionVisitor 类中。
编辑:我最终创建了一个表达式解析器,它将对集合进行任何级别的属性、集合和选择嵌套,并生成一个表达式数组。不幸的是,内置的 Fetch 扩展方法不将 LambdaExpression 作为参数。
我目前坚持的部分是无法使用 nHibernate 的内置 Fetch 定义。看起来我可能不得不直接点击 Remotion 库的函数或注册我自己的扩展方法来满足他们的解析器。
时髦。