I have a model called 'BusinessPage' which can be associated with 1 or more 'BusinessPageCategories'. So I've got a 3rd table called 'BusinessPagesInCategories' that links these two.
I am trying to get a paged recordset of BusinessPages, along with the total number of records (I may have 100 rows in total but only return 20 at a time, but I pass back an int containing that total number in addition to the 20 rows).
The problem I have is that, since I implemented the Many-To-Many relationship, it was bringing back the same BusinessPage row x times (where x is the number of categories that BusinessPage is associated with). I only want a single instance of each business page to be returned. So I added the following to my NHibernate Criteria to give Distinct BusinessPage results.
.SetResultTransformer(CriteriaSpecification.DistinctRootEntity);
Whilst this works for me, in that I'm now correctly getting a single row per BusinessPage (and my Categories property within each BusinessPage contains the correct x categories that it's assigned to), my row count is not reflecting that 'distinct' count - instead, if I have just 1 BusinessPage record which is associated with 3 categories, the row count is 3!?!
BusinessPage (Model)
public virtual int BusinessPageId { get; private set; }
public virtual IList<BusinessPageCategory> Categories { get; set; }
public virtual string BusinessName { get; set; }
BusinessPageCategory (Model)
public virtual int CategoryId { get; private set; }
public virtual string CategoryName { get; set; }
BusinessPagesInCategories (SQL Table used to relate the two models)
BusinessPageId
CategoryId
Here is the code I use to get my 'paged business pages':
public virtual IList<BusinessPage> GetPagedBusinessPages(int pageNumber, int pageSize, out int totalRecordCount)
{
ICriteria c = CreateCriteria_BusinessPage()
开发者_如何学编程 // we only want distinct business pages returned
.SetResultTransformer(CriteriaSpecification.DistinctRootEntity);
return c.PagedResults<BusinessPage>(pageNumber, pageSize, out totalRecordCount);
}
protected virtual ICriteria CreateCriteria_BusinessPage()
{
return Session
.CreateCriteria<BusinessPage>()
.AddOrder(Order.Asc("BusinessName"));
}
And here are my extension methods for getting both the paged results AND the all important row count.
public static IList<T> PagedResults<T>(this ICriteria criteria, int pageNumber, int pageSize, out int totalRecordCount)
{
var results = criteria
.CloneNewCriteria()
.SetPaging(pageNumber, pageSize)
.Future<T>();
totalRecordCount = criteria.GetTotalCount().Value;
return results.ToList<T>();
}
public static ICriteria CloneNewCriteria(this ICriteria criteria)
{
return CriteriaTransformer.Clone(criteria);
}
public static ICriteria SetPaging(this ICriteria criteria, int pageNumber, int pageSize)
{
return criteria
.SetMaxResults(pageSize)
.SetFirstResult((pageNumber - 1) * pageSize);
}
public static IFutureValue<int> GetTotalCount(this ICriteria criteria)
{
criteria.ClearOrders();
return criteria
.SetProjection(Projections.RowCount())
.FutureValue<int>();
}
I'm still very new to NHibernate so there may be a simple solution to this?
Problem solved. It turns out that I was setting up an Alias to the Categories regardless of whether I need to filter by category or not, therefore, the join was established in a scenario I didn't need it to be, and as a result was bringing back the duplicate rows (one for each join onto the categories)!
In the scenario whereby I do need to pass in a categoryid and filter my results on that category, there are no duplicate rows via the joins as each businesspage can be assigned any 1 category just the once.
I thought it was strange that it was making this join to categories even though I wasn't wanting to reference the categories object until after I had the initial records returned, but it looks like creating that alias outside of the scope required, forced the join and the loading of those categories unnecessarily.
精彩评论