以ICriteria對象的形式給出查詢,我想使用NHibernate(通過投影的方式?)以等價的方式查找元素的順序 使用ROW_NUMBER()和nhibernate - 查找項目的頁面
SELECT ROW_NUMBER() OVER (...)
在查詢中查找特定項目的索引。 (我需要這個在尋呼「跳轉到頁面」功能) 有什麼建議嗎?
注意:我不想去頁面,因爲它的編號尚未確定 - 我知道該怎麼做 - 我想獲取項目的INDEX,以便按頁面大小分頁並獲取頁面索引。
以ICriteria對象的形式給出查詢,我想使用NHibernate(通過投影的方式?)以等價的方式查找元素的順序 使用ROW_NUMBER()和nhibernate - 查找項目的頁面
SELECT ROW_NUMBER() OVER (...)
在查詢中查找特定項目的索引。 (我需要這個在尋呼「跳轉到頁面」功能) 有什麼建議嗎?
注意:我不想去頁面,因爲它的編號尚未確定 - 我知道該怎麼做 - 我想獲取項目的INDEX,以便按頁面大小分頁並獲取頁面索引。
的ICriteria有這2個功能:
SetFirstResult()
和
SetMaxResults()
這將您的SQL語句轉換成MySql中使用ROW_NUMBER(在SQL Server)或限制。
所以,如果你想25個記錄的第三頁上,你可以使用:
.SetFirstResult(2*25)
.SetMaxResults(25)
謝謝,但我想要做的是有點不同 - 我有一個對象,我想找到它的索引,以便我可以找到對象的頁面。那麼我可以使用這些建議的方法來獲取該頁面。 – 2010-01-11 08:44:12
看源NHibernate的後,我相當肯定,不存在這樣的功能。
然而,我不介意有人證明我錯了。
在我的具體設置,我寫的是需要幾個lambda表達式的方法( - 特定域的實體的所有屬性代表鍵列,以及可選列通過篩選)解決了這個問題。這個方法然後建立sql並且調用session.CreateSQLQuery(...).UniqueResult();
我並不是聲稱這是一個通用的解決方案。
爲了避免使用魔法字符串,我從this answer借了一份PropertyHelper<T>
。
下面的代碼:
public abstract class RepositoryBase<T> where T : DomainEntityBase
{
public long GetIndexOf<TUnique, TWhere>(T entity, Expression<Func<T, TUnique>> uniqueSelector, Expression<Func<T, TWhere>> whereSelector, TWhere whereValue) where TWhere : DomainEntityBase
{
if (entity == null || entity.Id == Guid.Empty)
{
return -1;
}
var entityType = typeof(T).Name;
var keyField = PropertyHelper<T>.GetProperty(uniqueSelector).Name;
var keyValue = uniqueSelector.Compile()(entity);
var innerWhere = string.Empty;
if (whereSelector != null)
{
// Builds a column name that adheres to our naming conventions!
var filterField = PropertyHelper<T>.GetProperty(whereSelector).Name + "Id";
if (whereValue == null)
{
innerWhere = string.Format(" where [{0}] is null", filterField);
}
else
{
innerWhere = string.Format(" where [{0}] = :filterValue", filterField);
}
}
var innerQuery = string.Format("(select [{0}], row_number() over (order by {0}) as RowNum from [{1}]{2}) X", keyField, entityType, innerWhere);
var outerQuery = string.Format("select RowNum from {0} where {1} = :keyValue", innerQuery, keyField);
var query = _session
.CreateSQLQuery(outerQuery)
.SetParameter("keyValue", keyValue);
if (whereValue != null)
{
query = query.SetParameter("filterValue", whereValue.Id);
}
var sqlRowNumber = query.UniqueResult<long>();
// The row_number() function is one-based. Our index should be zero-based.
sqlRowNumber -= 1;
return sqlRowNumber;
}
public long GetIndexOf<TUnique>(T entity, Expression<Func<T, TUnique>> uniqueSelector)
{
return GetIndexOf(entity, uniqueSelector, null, (DomainEntityBase)null);
}
public long GetIndexOf<TUnique, TWhere>(T entity, Expression<Func<T, TUnique>> uniqueSelector, Expression<Func<T, TWhere>> whereSelector) where TWhere : DomainEntityBase
{
return GetIndexOf(entity, uniqueSelector, whereSelector, whereSelector.Compile()(entity));
}
}
public abstract class DomainEntityBase
{
public virtual Guid Id { get; protected set; }
}
你使用它,像這樣:
...
public class Book : DomainEntityBase
{
public virtual string Title { get; set; }
public virtual Category Category { get; set; }
...
}
public class Category : DomainEntityBase { ... }
public class BookRepository : RepositoryBase<Book> { ... }
...
var repository = new BookRepository();
var book = ... a persisted book ...
// Get the index of the book, sorted by title.
var index = repository.GetIndexOf(book, b => b.Title);
// Get the index of the book, sorted by title and filtered by that book's category.
var indexInCategory = repository.GetIndexOf(book, b => b.Title, b => b.Category);
正如我所說的,這對我的作品。隨着我前進,我一定會調整它。因人而異。
現在,如果OP自己解決了這個問題,那麼我很樂意看到他的解決方案! :-)
太棒了,如果我的投影計劃失敗,我可能會放棄它:) – 2010-01-25 15:26:56
試圖找到一個基於NHibernate的解決方案,這一點我自己之後,我最終只是添加到我碰巧視圖的列使用:
CREATE VIEW vw_paged AS
SELECT ROW_NUMBER() OVER (ORDER BY Id) AS [Row], p.column1, p.column2
FROM paged_table p
這並不能真正幫助,如果您需要複雜的排序選項,但它適用於簡單的情況。
條件查詢,當然會是這個樣子:
public static IList<Paged> GetRange(string search, int rows)
{
var match = DbSession.Current.CreateCriteria<Job>()
.Add(Restrictions.Like("Id", search + '%'))
.AddOrder(Order.Asc("Id"))
.SetMaxResults(1)
.UniqueResult<Paged>();
if (match == null)
return new List<Paged>();
if (rows == 1)
return new List<Paged> {match};
return DbSession.Current.CreateCriteria<Paged>()
.Add(Restrictions.Like("Id", search + '%'))
.Add(Restrictions.Ge("Row", match.Row))
.AddOrder(Order.Asc("Id"))
.SetMaxResults(rows)
.List<Paged>();
}
這是我一直在尋找爲好。當你發佈這個問題時,我急切地等待所有的答案......在查看NHibernate的源代碼後,我確信沒有這樣的功能。 – 2010-01-13 10:34:59
此外,row_number()函數的語法有點尷尬,可能會使其實現上述功能非常具有挑戰性。 – 2010-01-13 10:38:27
你會考慮一個不基於ICriteria的解決方案,並且是SQL Server特有的嗎? (該解決方案不需要輸入魔法字符串,在功能上有所限制,但利用了您的域實體...) – 2010-01-15 16:51:43