没有LINQ扩展的NHibernate通用存储库?

时间:2013-11-04 12:55:13

标签: c# linq nhibernate repository

我正在寻找几天前没有结果的答案。

我正在尝试使用NHibernate为通用存储库创建一个IRepository接口的实现。这是界面:

public interface IRepository<TEntity, TKey> where TEntity : BaseEntity
{
    TEntity GetById(TKey id);
    void Insert(TEntity entidad);
    void Update(TEntity entidad);
    void Delete(TEntity entidad);
    IQueryable<TEntity > Table { get; };
}

我知道ISession接口有一个扩展,它在我的查询中使用LINQ,但我也知道该插件不能100%工作(我测试了它但是当我尝试执行一些时复杂的查询,它没有实现异常,所以我不能使用那个插件)

我正在使用来自ISession的100%QueryOver函数,所以..你知道如何将IQueroOver函数实现为IQueryable(不启动“SELECT *”查询)吗?如果没有,那么在没有使用LINQ扩展的情况下实现通用存储库模式的任何其他想法?

非常感谢

1 个答案:

答案 0 :(得分:1)

没有这样的事情

每个人都有自己定义100%实现的LINQ提供程序应具有的功能。 有人可能希望LINQ提供程序能够将String.Equals(String, String, StringComparison)转换为使用正确排序规则的SQL表达式,但除非创建LINQ提供程序的程序员对其进行编程,否则它将无法执行此操作。 。 我们可能希望LINQ提供商能够做到的事情没有尽头,所以每个 LINQ提供商都有局限性。 在LINQ提供商方面,没有100%这样的东西。 这是一个无法实现的概念。 这是无限的。

因此,重要的是......

  1. 了解LINQ提供程序的限制,
  2. 知道如何解决这些限制。
  3. 限制

    使用NHibernate,知道这些限制比它应该有点困难,因为目前还没有NHibernate LINQ提供程序的官方文档。 (NH-2444,欢迎补丁!) 但是,你可以通过知道这个LINQ提供程序是建立在HQL之上来解决一些问题,因此HQL具有任何限制,LINQ也会有。

    没有NHibernate查询语法直接支持在不相关的列上执行任意左外连接(当然,除了Native SQL之外)。 NHibernate中的查询被设计为使得执行连接的所有信息都已存储在映射中。 之后,您所要做的就是指定关系,例如order.Customer,NHibernate知道要连接在一起的表和列。您应该能够使用HQL或LINQ进行任意交叉连接,然后您可以添加一个where子句,使其行为类似于内连接,但没有左外连接。

    由于没有一个查询语法直接支持您想要做的事情,因此构建LINQ / QueryOver包装器(与现有的LINQ / HQL包装器相关,并且实现起来可能同样复杂)将不会获得任何好处。 无论您使用的是LINQ还是QueryOver,都必须采取相同的步骤来处理此查询。

    变通方法

    由于LINQ提供程序不可能完整,因此设计良好的LINQ提供程序必须是可扩展的。 这样,如果LINQ提供程序本身不支持您需要的功能,它不会毁了您的一天。 NHibernate LINQ提供程序可以进行扩展。 有关详细信息,请参阅Giorgetti Alessandro's blog

    但是,当然,在我们编写LINQ提供程序扩展之前,我们应该检查是否有更简单的方法来解决问题。 想到了几种可能性:

    处理此问题的最简单方法是简单地将关系添加到NHibernate映射,使您能够在NHibernate查询(LINQ或其他)中利用它。 如果这两列是不兼容的数据类型,或者在执行连接之前需要某种操作,请考虑修复数据和模式,以便实现更平滑的映射。

    另一种选择是通过子查询获得创意,或使用多个查询来模拟您所需的联接将执行的操作。例如,请参阅我的other answers之一:

      

    ...这个LEFT OUTER JOIN可以通过组合两个单独查询的结果来模拟 - 一个用于获取订单......

    var orders = session.Query<OrderHeader>()
        .Fetch(x => x.CreatedBy);
    
         

    ...和另一个让没有订单的人:

    var peopleWithNoOrders = session.Query<Person>()
        .Where(p => !session.Query<OrderHeader>().Any(o => o.CreatedBy == p));
    

    ...因为left outer join相当于inner join加上非匹配的附加结果。我不知道您尝试执行的联接的详细信息,但希望这会给您足够的想法以便开始。