【问题标题】:why doesnt' nhibernate support this "exists in list" syntax?为什么 nhibernate 不支持这种“存在于列表中”的语法?
【发布时间】:2011-01-01 13:33:47
【问题描述】:

我有以下查询,它在 Nhibernate 3 LINQ 中失败,出现“不支持”异常。它是similar to this question,但这个问题是一年多前提出的,所以我很肯定答案已经过时了。

我的数据库表是:

  1. VacationRequest (id, personId)
  2. VacationRequestDate(id,vacationRequestId)
  3. 人员(id、FirstName、LastName)

我的实体是:

  1. 假期请求(个人,IList)
  2. VacationRequestDate(VacationRequest,日期)

这是获得“不支持”异常的查询

 Session.Query<VacationRequestDate>()
   .Where(r => people
     .Contains(r.VacationRequest.Person, new PersonComparer()))
   .Fetch(r=>r.VacationRequest)
   .ToList();

有没有更好的方法来编写这将在 Nhibernate 中得到支持?

仅供参考。 .the PersonComparer 刚刚比较了 person.Id

【问题讨论】:

    标签: c# linq nhibernate fluent-nhibernate


    【解决方案1】:

    nhibernate 无法翻译您的new PersonComparer(),您应该更改它。

    【讨论】:

    • @ooo,如果您在调试模式下看到表达式树,您会发现它无法做到这一点,但我认为如果您覆盖 Person 的相等成员,则可以小心完成。 [但是如果您之前出于其他目的覆盖它,我建议使用 hql]
    【解决方案2】:

    NHibernate 不理解 PersonComparer 类型,因此无法将其用法转换为 SQL。

    您是否尝试过使用不接受比较器的Contains 的重载? NHibernate 应该推断您正在比较实体实例并在 SQL 比较中正确使用 ID(它还能使用什么?):

    Session.Query<VacationRequestDate>()
        .Where(r => people.Contains(r.VacationRequest.Person))
        .Fetch(r => r.VacationRequest)
        .ToList();
    

    另外,请记住,在单个 NHibernate 会话中,始终为相同的 ID 返回相同的实体实例。这意味着如果两个Person 实例都是从同一个会话中检索到的,那么person1 == person1 应该始终为真。这也会传递关系,因此如果两个假期请求具有相同的人员 ID,vacationRequest1.Person == vacationRequest2.Person 在同一会话中也将成立。

    这意味着您可以完全摆脱PersonComparer,除非您通过缓存混合来自多个会话的实体。

    【讨论】:

      【解决方案3】:

      对于初学者来说,它无法针对您的数据库中的代码执行代码。

      以下是我对如何解决此问题的建议

      var peopleIds= people.Select(x=>x.Id);
      Session.Query<VacationRequestDate>()
          .Where(r => peopleIds.Contains(r.VacationRequest.PeopleId)).ToList()
          .Where(x=>people.Contains(r.VacationRequest,new         
           PersonComparer()).Select(r=>r.VacationRequest).ToList()
      

      如果您认为这不是您想要做的,那么我建议您尝试 Criteria 查询或 HQL,您可以从 db 中得到您想要的。

      您也可以按如下方式使用比较器。我喜欢让我的通用。 您也可以进行字符串比较,并在此处添加忽略大小写等逻辑。

      public class ComparerByIntId<T> : IEqualityComparer<T>
          where T : class, IIntegerIdentifiable
      {
          public bool Equals(T x, T y)
          {
              if (x == null && y == null)
                  return true;
      
              if (x == null || y == null)
                  return false;
      
              return x.Id == y.Id;
          }
      
          public int GetHashCode(T obj)
          {
              return base.GetHashCode();
          }
      }
      

      现在,当您运行查询时,它将如下所示:

      Session.Query<VacationRequestDate>()
         .Where(r => people
         .Contains(r.VacationRequest.Person, new ComparerByIntId<Person>()))
         .Select(r=>r.VacationRequest)
         .ToList();
      

      希望有帮助

      【讨论】:

      • Where(r =&gt; peopleIds.Contains(r.VacationRequest.PeopleId)).ToList() 不是一个好建议,加载所有数据可能会导致崩溃也很慢
      • 如何加载所有数据?我们是 21 世纪的人。你是什么意思它会崩溃。假设每个人的数据是 1024 字节大,因此返回的 1024 条记录的总空间是 1024*1024= 1mb 的内存,除非我们突然考虑将内存限制为 1mb,否则我当然认为这是可以管理的。
      猜你喜欢
      • 1970-01-01
      • 2018-09-02
      • 1970-01-01
      • 1970-01-01
      • 2017-12-28
      • 2011-02-02
      • 1970-01-01
      • 2014-04-30
      • 1970-01-01
      相关资源
      最近更新 更多