2010-03-17 44 views
1

我有一个奇怪的要求,我的客户强加给我。他们有他们花费了大量的时间来优化的工作如下某些查询:NHibernate:自定义标准来操纵连接

  1. 存储过程建立了一个“ID列表”,这基本上代表了“去哪儿”过滤
  2. 的ID列表被加入到您的数据表

的ID列表将是这个样子

IdListTable.Customers_Id

1087, 
10094, 
87, 
1077 
因此

的连接查询看起来像:

SELECT c.Id, c.FirstName, c.LastName 
FROM Customers c INNER JOIN IdListTable idList ON (c.Id = idList.Customers_Id); 

我希望能够做这样的事在NHibernate的

IEnumerable<Customer> GetMatching(Specification spec) { 
    string idListName = "IdListTable"; 

    _idListGenerator.BuildIdList(idListName); 

    return _session.CreateCriteria<Customer>(). 
    Add(new JoinIdListCriterion(idListName) 
    .Enumerable<Customer>() 
} 

所以首先,这是正确的概念?我想要实现自己的ICriterion还是完全用于其他事情?其次,我该如何做到这一点。我已经尝试过实现AbstractCriterion并阅读doc-comments,我只是不确定我会在哪里查询构建过程。

回答

1

最好的办法是将“id-list”表添加到映射中,这样就可以像任何其他表一样执行连接。

另一种选择是执行连接的WHERE子句,所以你会得到这样的:

SELECT c.Id, c.FirstName, c.LastName 
FROM Customers c WHERE c.Id IN (SELECT Customers_Id FROM IdListTable); 

你可以把它的工作使用SqlCriteria:

return _session.CreateCriteria<Customer>("c") 
    .Add(Expression.Sql("c.Id IN (SELECT Customers_Id FROM IdListTable)", new object[0], new IType[0])) 
    .Enumerable<Customer>(); 
+0

谢谢,但我不想映射id列表,因为它不是一个实体。一个IN查询是这样做的一种方式,当然,但我真的想把它作为一个Join来工作。 ICriterion似乎揭露了这一点,但我不确定如何。 – 2010-03-17 19:27:34

+0

嘿法比奥,这将如何与缓存,交易等工作。看起来好像没有办法,NHibernate可以在这些方面做任何事情,你会放弃使用它开始的许多好处。 – 2010-03-17 20:13:01

+0

缓存和事务应该仍然正常工作,我在一些项目中使用了Expression.Sql,并且从来没有任何问题。至于加入,只要你使用标准API,你必须映射所有的表(这就是为什么你可能应该映射IdListTable,即使它不是一个实体,它仍然是你模型的一个重要部分),或者尝试使用IN子句或某些用户定义的函数“劫持”您的查询。另一个选择是使用纯SQL编写此特定查询(通过使用_session.CreateSQLQuery())。 – 2010-03-17 22:31:26